├── .github └── workflows │ └── check.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── generated ├── .cache │ ├── 1302b28796d8f77bb67b916ce3e4f3cf7f26a0ad │ ├── b33403ac7d85e8532537d86edba4cac92f97d2d1 │ ├── c4d221b18810d6dc4a0110586659b26ac8834a06 │ └── da5e9777dea24949e2fc5cd1079816fe534682cc ├── assets │ ├── cb_microblock │ │ └── models │ │ │ └── item │ │ │ ├── diamond_saw.json │ │ │ ├── iron_saw.json │ │ │ ├── microblock.json │ │ │ ├── stone_rod.json │ │ │ └── stone_saw.json │ └── cb_multipart │ │ ├── blockstates │ │ └── multipart.json │ │ └── models │ │ └── block │ │ └── multipart.json └── data │ ├── cb_microblock │ ├── recipe │ │ ├── diamond_saw.json │ │ ├── iron_saw.json │ │ ├── microblock.json │ │ ├── stone_rod.json │ │ └── stone_saw.json │ └── tags │ │ └── item │ │ └── tools │ │ └── saw.json │ └── forge │ └── tags │ └── item │ └── rods │ └── stone.json ├── java └── codechicken │ ├── microblock │ ├── CBMicroblock.java │ ├── api │ │ ├── BlockMicroMaterial.java │ │ ├── MicroHighlightRenderer.java │ │ ├── MicroMaterial.java │ │ ├── MicroMaterialClient.java │ │ ├── SlottedHollowConnect.java │ │ └── package-info.java │ ├── client │ │ ├── MicroBlockPartRenderer.java │ │ ├── MicroMaterialClientRegistry.java │ │ ├── MicroblockItemRenderer.java │ │ ├── MicroblockRender.java │ │ └── package-info.java │ ├── init │ │ ├── CBMicroblockModContent.java │ │ ├── CBMicroblockTags.java │ │ ├── ClientInit.java │ │ ├── DataGenerators.java │ │ ├── MicroMaterialConfig.java │ │ └── package-info.java │ ├── item │ │ ├── ItemMicroBlock.java │ │ ├── MicroMaterialComponent.java │ │ ├── SawItem.java │ │ └── package-info.java │ ├── package-info.java │ ├── part │ │ ├── ExecutablePlacement.java │ │ ├── IMicroOcclusion.java │ │ ├── IMicroShrinkRender.java │ │ ├── MicroblockPart.java │ │ ├── MicroblockPartFactory.java │ │ ├── MicroblockPlacement.java │ │ ├── PlacementGrid.java │ │ ├── PlacementProperties.java │ │ ├── StandardMicroFactory.java │ │ ├── StandardMicroblockPart.java │ │ ├── corner │ │ │ ├── CornerMicroFactory.java │ │ │ ├── CornerMicroblockPart.java │ │ │ ├── CornerPlacementGrid.java │ │ │ ├── CornerPlacementProperties.java │ │ │ └── package-info.java │ │ ├── edge │ │ │ ├── EdgeMicroFactory.java │ │ │ ├── EdgeMicroblockPart.java │ │ │ ├── EdgePlacementGrid.java │ │ │ ├── EdgePlacementProperties.java │ │ │ ├── PostMicroblockFactory.java │ │ │ ├── PostMicroblockPart.java │ │ │ └── package-info.java │ │ ├── face │ │ │ ├── FaceEdgeGrid.java │ │ │ ├── FaceMicroFactory.java │ │ │ ├── FaceMicroblockPart.java │ │ │ ├── FacePlacementProperties.java │ │ │ └── package-info.java │ │ ├── hollow │ │ │ ├── HollowMicroFactory.java │ │ │ ├── HollowMicroblockPart.java │ │ │ ├── HollowPlacementProperties.java │ │ │ └── package-info.java │ │ └── package-info.java │ ├── recipe │ │ ├── MicroRecipe.java │ │ └── package-info.java │ └── util │ │ ├── MaskedCuboid.java │ │ ├── MicroMaterialRegistry.java │ │ ├── MicroOcclusionHelper.java │ │ └── package-info.java │ └── multipart │ ├── CBMultipart.java │ ├── api │ ├── ItemMultipart.java │ ├── MultipartClientRegistry.java │ ├── MultipartType.java │ ├── NormalOcclusionTest.java │ ├── PartConverter.java │ ├── RedstoneConnectorBlock.java │ ├── RedstoneInteractions.java │ ├── RegisterMultipartTraitsEvent.java │ ├── SimpleMultipartType.java │ ├── TickableTile.java │ ├── package-info.java │ ├── part │ │ ├── AnimateTickPart.java │ │ ├── BaseMultipart.java │ │ ├── CapabilityProviderPart.java │ │ ├── EdgePart.java │ │ ├── FacePart.java │ │ ├── IconHitEffectsPart.java │ │ ├── ModelRenderPart.java │ │ ├── MultiPart.java │ │ ├── NeighborTileChangePart.java │ │ ├── NormalOcclusionPart.java │ │ ├── PartialOcclusionPart.java │ │ ├── RandomTickPart.java │ │ ├── SlottedPart.java │ │ ├── TickablePart.java │ │ ├── package-info.java │ │ ├── redstone │ │ │ ├── FaceRedstonePart.java │ │ │ ├── MaskedRedstonePart.java │ │ │ ├── RedstonePart.java │ │ │ └── package-info.java │ │ └── render │ │ │ ├── PartBakedModelRenderer.java │ │ │ ├── PartRenderer.java │ │ │ └── package-info.java │ └── tile │ │ ├── RedstoneConnector.java │ │ └── package-info.java │ ├── block │ ├── BlockMultipart.java │ ├── TileMultipart.java │ └── package-info.java │ ├── client │ ├── ClientEventHandler.java │ ├── MultipartBlockRenderer.java │ ├── MultipartModelData.java │ ├── MultipartTileBakedModel.java │ ├── MultipartTileRenderer.java │ ├── Shaders.java │ └── package-info.java │ ├── handler │ ├── ControlKeyHandler.java │ ├── PlacementConversionHandler.java │ └── package-info.java │ ├── init │ ├── CBMultipartModContent.java │ ├── ClientInit.java │ ├── DataGenerators.java │ ├── MultiPartRegistries.java │ └── package-info.java │ ├── internal │ ├── mixin │ │ ├── TileEntityMixin.java │ │ └── package-info.java │ └── package-info.java │ ├── minecraft │ ├── ButtonPart.java │ ├── ClientInit.java │ ├── LeverPart.java │ ├── McSidedStatePart.java │ ├── McStatePart.java │ ├── MinecraftMultipart.java │ ├── MinecraftMultipartModContent.java │ ├── RedstoneTorchPart.java │ ├── SoulTorchPart.java │ ├── TorchPart.java │ └── package-info.java │ ├── network │ ├── MultiPartCPH.java │ ├── MultiPartNetwork.java │ ├── MultiPartSPH.java │ └── package-info.java │ ├── trait │ ├── TAnimateTickTile.java │ ├── TCapabilityTile.java │ ├── TInventoryTile.java │ ├── TPartialOcclusionTile.java │ ├── TRedstoneTile.java │ ├── TSlottedTile.java │ ├── TTickableTile.java │ ├── TTileChangeTile.java │ ├── TileMultipartClient.java │ ├── extern │ │ ├── RedstoneTile.java │ │ └── package-info.java │ └── package-info.java │ └── util │ ├── ControlKeyModifier.java │ ├── ForgeMixinBackend.java │ ├── MergedVoxelShapeHolder.java │ ├── MultipartGenerator.java │ ├── MultipartHelper.java │ ├── MultipartLoadHandler.java │ ├── MultipartPlaceContext.java │ ├── MultipartVoxelShape.java │ ├── PartMap.java │ ├── PartRayTraceResult.java │ ├── TickScheduler.java │ ├── WorldTickScheduler.java │ └── package-info.java └── resources ├── META-INF ├── MANIFEST.MF ├── accesstransformer.cfg └── neoforge.mods.toml ├── assets ├── cb_microblock │ ├── lang │ │ ├── cs_cz.json │ │ ├── de_de.json │ │ ├── en_us.json │ │ ├── es_es.json │ │ ├── fr_ca.json │ │ ├── fr_fr.json │ │ ├── hr_hr.json │ │ ├── it_it.json │ │ ├── ko_kr.json │ │ ├── nl_nl.json │ │ ├── pl_pl.json │ │ ├── pt_br.json │ │ ├── ru_ru.json │ │ ├── tr_tr.json │ │ ├── zh_cn.json │ │ └── zh_tw.json │ ├── models │ │ └── saw.obj │ └── textures │ │ └── item │ │ ├── diamond_saw.png │ │ ├── iron_saw.png │ │ ├── saw.png │ │ ├── stone_rod.png │ │ └── stone_saw.png └── cb_multipart │ └── shaders │ └── core │ ├── highlight.fsh │ ├── highlight.json │ └── highlight.vsh ├── mixins.cbmultipart.json └── pack.mcmeta /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: [ push, pull_request ] 4 | 5 | env: 6 | BUILD_NUMBER: 9999 7 | GITHUB_CI: true 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup Java 16 | uses: actions/setup-java@v4 17 | with: 18 | java-version: 21 19 | distribution: 'temurin' 20 | - name: Build 21 | run: ./gradlew check 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Exclude all the things! 2 | /* 3 | 4 | # Gradle stuff 5 | !gradle/ 6 | !gradlew 7 | !gradlew.bat 8 | !build.gradle 9 | !settings.gradle 10 | !gradle.properties 11 | 12 | # Other Files. 13 | !LICENSE.txt 14 | !README.md 15 | 16 | # Include git important files 17 | !.gitmodules 18 | !.gitignore 19 | !.github/ 20 | 21 | # Include Important Folders 22 | !src/ 23 | !libs/ 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CBMultipart 2 | ============== 3 | [![](http://cf.way2muchnoise.eu/short_codechicken-lib-1-8_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/cb-multipart) 4 | [![](http://cf.way2muchnoise.eu/versions/Available%20for_codechicken-lib-1-8_full.svg)](https://www.curseforge.com/minecraft/mc-mods/cb-multipart/files) 5 | [![](https://img.shields.io/discord/214781374698225666.svg?logo=discord&label=Discord&labelColor=2d2d2d&style=flat)](https://discord.gg/9nr3qyC) 6 | [![](https://img.shields.io/badge/Nexus%20index-maven-blue?style=flat&labelColor=2d2d2d)](https://nexus.covers1624.net/#browse/browse:maven-hosted:codechicken%2FCBMultipart) 7 | [![](https://img.shields.io/badge/Patreon-covers1624-red?style=flat&labelColor=2d2d2d&logo=patreon)](https://www.patreon.com/covers1624) 8 | 9 | Formely known as ForgeMultipart. 10 | 11 | An API for dynamically handling different functional parts in the one block space. 12 | 13 | Grab it on CurseForge [here!](https://www.curseforge.com/minecraft/mc-mods/cb-multipart) 14 | 15 | Maven for developers: `https://maven.covers1624.net` 16 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | mc_version=1.21.1 2 | forge_version=21.1.72 3 | mod_version=3.5.0 4 | 5 | ccl_version=4.6.1.+ 6 | ccl_version_max=5.0.0 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CBMultipart/68e51552065a1517c17634f5044f468fd7635e64/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | maven { 5 | name = 'NeoForged' 6 | url = 'https://maven.neoforged.net/releases' 7 | } 8 | } 9 | } 10 | 11 | plugins { 12 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' 13 | } 14 | 15 | rootProject.name = 'CBMultipart' 16 | -------------------------------------------------------------------------------- /src/main/generated/.cache/1302b28796d8f77bb67b916ce3e4f3cf7f26a0ad: -------------------------------------------------------------------------------- 1 | // 1.21.1 2024-10-29T17:19:34.128263858 cb_microblock Item models. 2 | 889a6094a52ed0abee52e315fe6a4710dcd12851 assets/cb_microblock/models/item/diamond_saw.json 3 | 3c81fc1f5313b123c5e31c1241ea90231dc0180f assets/cb_microblock/models/item/iron_saw.json 4 | 55430d3d211ed564fe0a798ba8747dd5b798fce1 assets/cb_microblock/models/item/microblock.json 5 | b75b209c3a3053ae0b5119d5e3cf98fc76dda312 assets/cb_microblock/models/item/stone_rod.json 6 | 5f86061e96d33329e77a6e907a7193fabf3017eb assets/cb_microblock/models/item/stone_saw.json 7 | -------------------------------------------------------------------------------- /src/main/generated/.cache/b33403ac7d85e8532537d86edba4cac92f97d2d1: -------------------------------------------------------------------------------- 1 | // 1.21.1 2025-01-21T12:58:44.654761702 Block States: cb_multipart 2 | 252af1a9ca3913f6eb67517ac064c91a13a1b681 assets/cb_multipart/blockstates/multipart.json 3 | ce4575aeea4602bcf528513e5f3e39b8ff46eec3 assets/cb_multipart/models/block/multipart.json 4 | -------------------------------------------------------------------------------- /src/main/generated/.cache/c4d221b18810d6dc4a0110586659b26ac8834a06: -------------------------------------------------------------------------------- 1 | // 1.21.1 2024-10-29T17:19:34.128772853 Tags for minecraft:item mod id cb_microblock 2 | 1ecfd9a89080afa1d00e0911bd0678541b7c9ef3 data/cb_microblock/tags/item/tools/saw.json 3 | 8d28864c67fe7828067aa17fbabaf0d1c7a743d1 data/forge/tags/item/rods/stone.json 4 | -------------------------------------------------------------------------------- /src/main/generated/.cache/da5e9777dea24949e2fc5cd1079816fe534682cc: -------------------------------------------------------------------------------- 1 | // 1.21.1 2025-01-02T14:36:54.619724648 cb_microblock Recipes. 2 | a0d3dad44d8955510428ca551307115c101d2f75 data/cb_microblock/recipe/diamond_saw.json 3 | 6c4ccfa2ec0563522f1fbe85549f3e4ec9e88ef0 data/cb_microblock/recipe/iron_saw.json 4 | 81a245dcb7e18d2e7b81d16ff2137888b7c53670 data/cb_microblock/recipe/microblock.json 5 | 78fedca06ab63a74fdaafaba6778e6db22849cf9 data/cb_microblock/recipe/stone_rod.json 6 | f241270a30261b914c2092dab2b9cccf86ed405b data/cb_microblock/recipe/stone_saw.json 7 | -------------------------------------------------------------------------------- /src/main/generated/assets/cb_microblock/models/item/diamond_saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "cb_microblock:item/diamond_saw" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/generated/assets/cb_microblock/models/item/iron_saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "cb_microblock:item/iron_saw" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/generated/assets/cb_microblock/models/item/microblock.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "class": "codechicken.microblock.client.MicroblockItemRenderer", 4 | "loader": "codechickenlib:class" 5 | } -------------------------------------------------------------------------------- /src/main/generated/assets/cb_microblock/models/item/stone_rod.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "cb_microblock:item/stone_rod" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/generated/assets/cb_microblock/models/item/stone_saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "cb_microblock:item/stone_saw" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/generated/assets/cb_multipart/blockstates/multipart.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "": { 4 | "model": "cb_multipart:block/multipart" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/generated/assets/cb_multipart/models/block/multipart.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:block/block", 3 | "class": "codechicken.multipart.client.MultipartTileBakedModel", 4 | "loader": "codechickenlib:class" 5 | } -------------------------------------------------------------------------------- /src/main/generated/data/cb_microblock/recipe/diamond_saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "category": "misc", 4 | "key": { 5 | "M": { 6 | "tag": "c:gems/diamond" 7 | }, 8 | "R": { 9 | "tag": "forge:rods/stone" 10 | }, 11 | "S": { 12 | "tag": "c:rods/wooden" 13 | } 14 | }, 15 | "pattern": [ 16 | "SRR", 17 | "SMR" 18 | ], 19 | "result": { 20 | "count": 1, 21 | "id": "cb_microblock:diamond_saw" 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/generated/data/cb_microblock/recipe/iron_saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "category": "misc", 4 | "key": { 5 | "M": { 6 | "tag": "c:ingots/iron" 7 | }, 8 | "R": { 9 | "tag": "forge:rods/stone" 10 | }, 11 | "S": { 12 | "tag": "c:rods/wooden" 13 | } 14 | }, 15 | "pattern": [ 16 | "SRR", 17 | "SMR" 18 | ], 19 | "result": { 20 | "count": 1, 21 | "id": "cb_microblock:iron_saw" 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/generated/data/cb_microblock/recipe/microblock.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "cb_microblock:microblock", 3 | "category": "misc" 4 | } -------------------------------------------------------------------------------- /src/main/generated/data/cb_microblock/recipe/stone_rod.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "category": "misc", 4 | "key": { 5 | "S": { 6 | "tag": "c:cobblestones" 7 | } 8 | }, 9 | "pattern": [ 10 | "S", 11 | "S" 12 | ], 13 | "result": { 14 | "count": 1, 15 | "id": "cb_microblock:stone_rod" 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/generated/data/cb_microblock/recipe/stone_saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "category": "misc", 4 | "key": { 5 | "M": { 6 | "item": "minecraft:flint" 7 | }, 8 | "R": { 9 | "tag": "forge:rods/stone" 10 | }, 11 | "S": { 12 | "tag": "c:rods/wooden" 13 | } 14 | }, 15 | "pattern": [ 16 | "SRR", 17 | "SMR" 18 | ], 19 | "result": { 20 | "count": 1, 21 | "id": "cb_microblock:stone_saw" 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/generated/data/cb_microblock/tags/item/tools/saw.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | "cb_microblock:stone_saw", 4 | "cb_microblock:iron_saw", 5 | "cb_microblock:diamond_saw" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/main/generated/data/forge/tags/item/rods/stone.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | "cb_microblock:stone_rod" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/CBMicroblock.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock; 2 | 3 | import codechicken.microblock.init.CBMicroblockModContent; 4 | import codechicken.microblock.init.ClientInit; 5 | import codechicken.microblock.init.DataGenerators; 6 | import codechicken.microblock.util.MicroMaterialRegistry; 7 | import net.neoforged.bus.api.IEventBus; 8 | import net.neoforged.fml.common.Mod; 9 | import net.neoforged.fml.loading.FMLEnvironment; 10 | 11 | import static codechicken.microblock.CBMicroblock.MOD_ID; 12 | 13 | /** 14 | * Created by covers1624 on 26/6/22. 15 | */ 16 | @Mod (MOD_ID) 17 | public class CBMicroblock { 18 | 19 | public static final String MOD_ID = "cb_microblock"; 20 | 21 | public CBMicroblock(IEventBus modBus) { 22 | MicroMaterialRegistry.init(modBus); 23 | CBMicroblockModContent.init(modBus); 24 | 25 | DataGenerators.init(modBus); 26 | 27 | if (FMLEnvironment.dist.isClient()) { 28 | ClientInit.init(modBus); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/api/MicroHighlightRenderer.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.api; 2 | 3 | import codechicken.microblock.part.StandardMicroFactory; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import net.minecraft.client.renderer.MultiBufferSource; 6 | import net.minecraft.world.InteractionHand; 7 | import net.minecraft.world.entity.player.Player; 8 | import net.minecraft.world.phys.BlockHitResult; 9 | 10 | /** 11 | * Used to override the default micro material placement highlight rendering. 12 | *

13 | * Created by covers1624 on 22/10/22. 14 | */ 15 | public interface MicroHighlightRenderer { 16 | 17 | /** 18 | * Called to handle any custom highlight rendering. 19 | * 20 | * @return {@code true} If default rendering should be skipped. 21 | */ 22 | boolean renderHighlight(Player player, InteractionHand hand, BlockHitResult hit, StandardMicroFactory factory, int size, MicroMaterial material, PoseStack pStack, MultiBufferSource buffers, float partialTicks); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/api/MicroMaterialClient.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.api; 2 | 3 | import codechicken.lib.render.CCRenderState; 4 | import codechicken.lib.vec.Vector3; 5 | import codechicken.microblock.part.MicroblockPart; 6 | import codechicken.microblock.util.MaskedCuboid; 7 | import codechicken.multipart.util.PartRayTraceResult; 8 | import com.mojang.blaze3d.vertex.PoseStack; 9 | import net.minecraft.client.particle.ParticleEngine; 10 | import net.minecraft.client.renderer.MultiBufferSource; 11 | import net.minecraft.client.renderer.RenderType; 12 | import net.minecraft.client.renderer.block.model.BakedQuad; 13 | import net.minecraft.core.Direction; 14 | import net.minecraft.world.entity.Entity; 15 | import net.minecraft.world.item.ItemDisplayContext; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * Created by covers1624 on 23/10/22. 22 | */ 23 | public abstract class MicroMaterialClient { 24 | 25 | @Nullable 26 | public static MicroMaterialClient get(MicroMaterial material) { 27 | return (MicroMaterialClient) material.renderProperties; 28 | } 29 | 30 | public abstract RenderType getItemRenderLayer(); 31 | 32 | public abstract List getQuads(MicroblockPart part, @Nullable Direction side, @Nullable RenderType layer, Iterable cuboids); 33 | 34 | @Deprecated 35 | public abstract void renderCuboids(CCRenderState ccrs, @Nullable RenderType layer, Iterable cuboids); 36 | 37 | public void renderDynamic(MicroblockPart part, @Nullable ItemDisplayContext transformType, PoseStack pStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { } 38 | 39 | public void addHitEffects(MicroblockPart part, PartRayTraceResult hit, ParticleEngine engine) { } 40 | 41 | public void addDestroyEffects(MicroblockPart part, PartRayTraceResult hit, ParticleEngine engine) { } 42 | 43 | public void addLandingEffects(MicroblockPart part, PartRayTraceResult hit, Vector3 entity, int numberOfParticles) { } 44 | 45 | public void addRunningEffects(MicroblockPart part, PartRayTraceResult hit, Entity entity) { } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/api/SlottedHollowConnect.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.api; 2 | 3 | import org.jetbrains.annotations.Range; 4 | 5 | /** 6 | * Implement on center attached parts that can connect through Hollow covers to adjust the hole size of the cover. 7 | */ 8 | public interface SlottedHollowConnect { 9 | 10 | /** 11 | * @param side The side of the block on which the cover resides. 12 | * @return The size (width and height) of the connection in pixels. Must be less than 12 and more than 0. 13 | */ 14 | @Range(from = 1, to = 11) 15 | int getHoleSize(int side); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/api/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.api; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/client/MicroBlockPartRenderer.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.client; 2 | 3 | import codechicken.lib.render.CCRenderState; 4 | import codechicken.microblock.api.MicroMaterialClient; 5 | import codechicken.microblock.part.MicroblockPart; 6 | import codechicken.multipart.api.part.render.PartRenderer; 7 | import com.mojang.blaze3d.vertex.PoseStack; 8 | import net.minecraft.client.renderer.MultiBufferSource; 9 | import net.minecraft.client.renderer.RenderType; 10 | import net.minecraft.client.renderer.block.model.BakedQuad; 11 | import net.minecraft.core.Direction; 12 | import net.minecraft.util.RandomSource; 13 | import net.neoforged.neoforge.client.model.data.ModelData; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * Created by covers1624 on 20/10/22. 20 | */ 21 | public class MicroBlockPartRenderer implements PartRenderer { 22 | 23 | public static final MicroBlockPartRenderer INSTANCE = new MicroBlockPartRenderer(); 24 | 25 | @Override 26 | public List getQuads(MicroblockPart part, @Nullable Direction side, RandomSource rand, ModelData data, @Nullable RenderType renderType) { 27 | MicroMaterialClient clientMaterial = MicroMaterialClient.get(part.material); 28 | if (clientMaterial == null) return List.of(); 29 | 30 | return clientMaterial.getQuads(part, side, renderType, part.getRenderCuboids(false)); 31 | } 32 | 33 | @Override 34 | @Deprecated 35 | public void renderStatic(MicroblockPart part, @Nullable RenderType layer, CCRenderState ccrs) { 36 | MicroMaterialClient clientMaterial = MicroMaterialClient.get(part.material); 37 | if (clientMaterial != null) { 38 | clientMaterial.renderCuboids(ccrs, layer, part.getRenderCuboids(false)); 39 | } 40 | } 41 | 42 | @Override 43 | public void renderDynamic(MicroblockPart part, PoseStack pStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { 44 | MicroMaterialClient clientMaterial = MicroMaterialClient.get(part.material); 45 | if (clientMaterial != null) { 46 | clientMaterial.renderDynamic(part, null, pStack, buffers, packedLight, packedOverlay, partialTicks); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/client/MicroMaterialClientRegistry.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.client; 2 | 3 | import codechicken.microblock.api.MicroHighlightRenderer; 4 | import codechicken.microblock.api.MicroMaterial; 5 | import codechicken.microblock.part.StandardMicroFactory; 6 | import com.mojang.blaze3d.vertex.PoseStack; 7 | import net.minecraft.client.renderer.MultiBufferSource; 8 | import net.minecraft.world.InteractionHand; 9 | import net.minecraft.world.entity.player.Player; 10 | import net.minecraft.world.phys.BlockHitResult; 11 | 12 | import java.util.HashMap; 13 | import java.util.LinkedList; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * Created by covers1624 on 22/10/22. 19 | */ 20 | public class MicroMaterialClientRegistry { 21 | 22 | private final static Map> SPECIFIC_HIGHLIGHT_RENDERERS = new HashMap<>(); 23 | private final static List GLOBAL_HIGHLIGHT_RENDERERS = new LinkedList<>(); 24 | 25 | public static void registerHighlightRenderer(MicroMaterial material, MicroHighlightRenderer renderer) { 26 | synchronized (SPECIFIC_HIGHLIGHT_RENDERERS) { 27 | SPECIFIC_HIGHLIGHT_RENDERERS.computeIfAbsent(material, e -> new LinkedList<>()).add(renderer); 28 | } 29 | } 30 | 31 | public static void registerGlobalHighlightRenderer(MicroHighlightRenderer renderer) { 32 | synchronized (GLOBAL_HIGHLIGHT_RENDERERS) { 33 | GLOBAL_HIGHLIGHT_RENDERERS.add(renderer); 34 | } 35 | } 36 | 37 | public static boolean renderHighlightOverride(Player player, InteractionHand hand, BlockHitResult hit, StandardMicroFactory factory, int size, MicroMaterial material, PoseStack pStack, MultiBufferSource buffers, float partialTicks) { 38 | List specific = SPECIFIC_HIGHLIGHT_RENDERERS.getOrDefault(material, List.of()); 39 | for (MicroHighlightRenderer renderer : specific) { 40 | if (renderer.renderHighlight(player, hand, hit, factory, size, material, pStack, buffers, partialTicks)) { 41 | return true; 42 | } 43 | } 44 | for (MicroHighlightRenderer renderer : GLOBAL_HIGHLIGHT_RENDERERS) { 45 | if (renderer.renderHighlight(player, hand, hit, factory, size, material, pStack, buffers, partialTicks)) { 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/client/MicroblockItemRenderer.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.client; 2 | 3 | import codechicken.lib.model.PerspectiveModelState; 4 | import codechicken.lib.render.CCRenderState; 5 | import codechicken.lib.render.item.IItemRenderer; 6 | import codechicken.lib.util.TransformUtils; 7 | import codechicken.lib.vec.Vector3; 8 | import codechicken.microblock.api.MicroMaterialClient; 9 | import codechicken.microblock.item.MicroMaterialComponent; 10 | import codechicken.microblock.part.MicroblockPart; 11 | import com.mojang.blaze3d.vertex.PoseStack; 12 | import net.minecraft.client.Minecraft; 13 | import net.minecraft.client.renderer.MultiBufferSource; 14 | import net.minecraft.client.renderer.RenderType; 15 | import net.minecraft.core.Direction; 16 | import net.minecraft.world.item.ItemDisplayContext; 17 | import net.minecraft.world.item.ItemStack; 18 | 19 | /** 20 | * Created by covers1624 on 20/10/22. 21 | */ 22 | public class MicroblockItemRenderer implements IItemRenderer { 23 | 24 | @Override 25 | public void renderItem(ItemStack stack, ItemDisplayContext transformType, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay) { 26 | MicroMaterialComponent component = MicroMaterialComponent.getComponent(stack); 27 | 28 | if (component == null || component.factory() == null) return; 29 | 30 | MicroMaterialClient clientMaterial = MicroMaterialClient.get(component.material()); 31 | if (clientMaterial == null) return; 32 | 33 | MicroblockPart part = component.factory().create(true, component.material()); 34 | part.setShape(component.size(), component.factory().getItemSlot()); 35 | 36 | mStack.pushPose(); 37 | Vector3 offset = Vector3.CENTER.copy().subtract(part.getBounds().center()); 38 | mStack.translate(offset.x, offset.y, offset.z); 39 | 40 | RenderType layer = clientMaterial.getItemRenderLayer(); 41 | var cuboids = part.getRenderCuboids(true); 42 | var itemRenderer = Minecraft.getInstance().getItemRenderer(); 43 | for (Direction side : Direction.values()) { 44 | itemRenderer.renderQuadList( 45 | mStack, 46 | buffers.getBuffer(layer), 47 | clientMaterial.getQuads(part, side, null, cuboids), 48 | stack, 49 | packedLight, 50 | packedOverlay 51 | ); 52 | } 53 | itemRenderer.renderQuadList( 54 | mStack, 55 | buffers.getBuffer(layer), 56 | clientMaterial.getQuads(part, null, null, cuboids), 57 | stack, 58 | packedLight, 59 | packedOverlay 60 | ); 61 | 62 | clientMaterial.renderDynamic(part, transformType, mStack, buffers, packedLight, packedOverlay, 0); 63 | mStack.popPose(); 64 | } 65 | 66 | @Override 67 | public PerspectiveModelState getModelState() { 68 | return TransformUtils.DEFAULT_BLOCK; 69 | } 70 | 71 | @Override 72 | public boolean useAmbientOcclusion() { 73 | return true; 74 | } 75 | 76 | @Override 77 | public boolean isGui3d() { 78 | return true; 79 | } 80 | 81 | @Override 82 | public boolean usesBlockLight() { 83 | return false; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/client/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.client; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/init/CBMicroblockTags.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.init; 2 | 3 | import codechicken.microblock.CBMicroblock; 4 | import net.minecraft.resources.ResourceLocation; 5 | import net.minecraft.tags.ItemTags; 6 | import net.minecraft.tags.TagKey; 7 | import net.minecraft.world.item.Item; 8 | 9 | /** 10 | * Created by covers1624 on 22/10/22. 11 | */ 12 | public class CBMicroblockTags { 13 | 14 | public static class Items { 15 | 16 | public static final TagKey STONE_ROD = forge("rods/stone"); 17 | 18 | public static final TagKey TOOL_SAW = mod("tools/saw"); 19 | 20 | private static TagKey forge(String path) { 21 | return ItemTags.create(ResourceLocation.fromNamespaceAndPath("forge", path)); 22 | } 23 | 24 | private static TagKey mod(String path) { 25 | return ItemTags.create(ResourceLocation.fromNamespaceAndPath(CBMicroblock.MOD_ID, path)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/init/ClientInit.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.init; 2 | 3 | import codechicken.microblock.client.MicroBlockPartRenderer; 4 | import codechicken.microblock.client.MicroblockRender; 5 | import codechicken.multipart.api.MultipartClientRegistry; 6 | import net.covers1624.quack.util.CrashLock; 7 | import net.neoforged.bus.api.IEventBus; 8 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 9 | 10 | /** 11 | * Created by covers1624 on 20/10/22. 12 | */ 13 | public class ClientInit { 14 | 15 | private static final CrashLock LOCK = new CrashLock("Already Initialized."); 16 | 17 | // private static final ModelRegistryHelper MODEL_HELPER = new ModelRegistryHelper(); 18 | 19 | public static void init(IEventBus modBus) { 20 | LOCK.lock(); 21 | 22 | modBus.addListener(ClientInit::clientSetup); 23 | 24 | MicroblockRender.init(modBus); 25 | } 26 | 27 | private static void clientSetup(FMLClientSetupEvent event) { 28 | MultipartClientRegistry.register(CBMicroblockModContent.FACE_MICROBLOCK_PART.get(), MicroBlockPartRenderer.INSTANCE); 29 | MultipartClientRegistry.register(CBMicroblockModContent.HOLLOW_MICROBLOCK_PART.get(), MicroBlockPartRenderer.INSTANCE); 30 | MultipartClientRegistry.register(CBMicroblockModContent.CORNER_MICROBLOCK_PART.get(), MicroBlockPartRenderer.INSTANCE); 31 | MultipartClientRegistry.register(CBMicroblockModContent.EDGE_MICROBLOCK_PART.get(), MicroBlockPartRenderer.INSTANCE); 32 | MultipartClientRegistry.register(CBMicroblockModContent.POST_MICROBLOCK_PART.get(), MicroBlockPartRenderer.INSTANCE); 33 | // MODEL_HELPER.register(new ModelResourceLocation(CBMicroblockModContent.MICRO_BLOCK_ITEM.getId(), "inventory"), new MicroblockItemRenderer()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/init/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.init; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/item/ItemMicroBlock.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.item; 2 | 3 | import codechicken.lib.raytracer.RayTracer; 4 | import codechicken.microblock.api.MicroMaterial; 5 | import codechicken.microblock.init.CBMicroblockModContent; 6 | import codechicken.microblock.part.ExecutablePlacement; 7 | import codechicken.microblock.part.MicroblockPlacement; 8 | import net.minecraft.network.chat.Component; 9 | import net.minecraft.sounds.SoundSource; 10 | import net.minecraft.world.InteractionResult; 11 | import net.minecraft.world.entity.player.Player; 12 | import net.minecraft.world.item.Item; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraft.world.item.context.UseOnContext; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.block.SoundType; 17 | import net.minecraft.world.phys.BlockHitResult; 18 | 19 | /** 20 | * Created by covers1624 on 20/10/22. 21 | */ 22 | public class ItemMicroBlock extends Item { 23 | 24 | public ItemMicroBlock(Properties properties) { 25 | super(properties); 26 | } 27 | 28 | @Override 29 | public Component getName(ItemStack stack) { 30 | MicroMaterialComponent component = MicroMaterialComponent.getComponent(stack); 31 | if (component == null || component.factory() == null) { 32 | return Component.literal("Unnamed"); 33 | } 34 | 35 | return Component.translatable("item." + component.factory().getRegistryName().toString().replace(':', '.') + "." + component.size(), component.material().getLocalizedName()); 36 | } 37 | 38 | @Override 39 | public InteractionResult useOn(UseOnContext ctx) { 40 | Player player = ctx.getPlayer(); 41 | Level level = ctx.getLevel(); 42 | ItemStack stack = player.getItemInHand(ctx.getHand()); 43 | MicroMaterialComponent component = MicroMaterialComponent.getComponent(stack); 44 | if (component == null || component.factory() == null) return InteractionResult.FAIL; 45 | 46 | BlockHitResult hit = RayTracer.retraceBlock(level, player, ctx.getClickedPos()); 47 | if (hit != null) { 48 | ExecutablePlacement placement = new MicroblockPlacement(player, ctx.getHand(), hit, component.size(), component.material(), !player.getAbilities().instabuild, component.factory().placementProperties()).calculate(); 49 | if (placement == null) return InteractionResult.FAIL; 50 | 51 | if (!level.isClientSide) { 52 | placement.place(level, player, stack); 53 | if (!player.getAbilities().instabuild) { 54 | placement.consume(level, player, stack); 55 | } 56 | SoundType sound = component.material().getSound(); 57 | if (sound != null) { 58 | level.playSound(null, placement.pos.getX() + 0.5D, placement.pos.getY() + 0.5D, placement.pos.getZ() + 0.5D, sound.getPlaceSound(), SoundSource.BLOCKS, (sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F); 59 | } 60 | } 61 | return InteractionResult.SUCCESS; 62 | } 63 | 64 | return InteractionResult.FAIL; 65 | } 66 | 67 | public static ItemStack create(int factoryId, int size, MicroMaterial material) { 68 | return createStack(1, factoryId, size, material); 69 | } 70 | 71 | public static ItemStack createStack(int amount, int factoryId, int size, MicroMaterial material) { 72 | ItemStack stack = new ItemStack(CBMicroblockModContent.MICRO_BLOCK_ITEM.get(), amount); 73 | stack.set(CBMicroblockModContent.MICRO_MATERIAL_COMPONENT, new MicroMaterialComponent(factoryId, size, material)); 74 | return stack; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/item/MicroMaterialComponent.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.item; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import codechicken.microblock.init.CBMicroblockModContent; 5 | import codechicken.microblock.part.StandardMicroFactory; 6 | import com.mojang.serialization.Codec; 7 | import com.mojang.serialization.codecs.RecordCodecBuilder; 8 | import net.minecraft.network.RegistryFriendlyByteBuf; 9 | import net.minecraft.network.codec.ByteBufCodecs; 10 | import net.minecraft.network.codec.StreamCodec; 11 | import net.minecraft.world.item.ItemStack; 12 | import org.jetbrains.annotations.Contract; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | /** 16 | * Created by covers1624 on 23/10/24. 17 | */ 18 | public record MicroMaterialComponent( 19 | int factoryId, 20 | int size, 21 | MicroMaterial material 22 | ) { 23 | 24 | public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( 25 | Codec.INT.fieldOf("factoryId").forGetter(MicroMaterialComponent::factoryId), 26 | Codec.INT.fieldOf("size").forGetter(MicroMaterialComponent::size), 27 | MicroMaterial.CODEC.fieldOf("material").forGetter(MicroMaterialComponent::material) 28 | ).apply(builder, MicroMaterialComponent::new) 29 | ); 30 | 31 | public static StreamCodec STREAM_CODEC = StreamCodec.composite( 32 | ByteBufCodecs.VAR_INT, MicroMaterialComponent::factoryId, 33 | ByteBufCodecs.VAR_INT, MicroMaterialComponent::size, 34 | MicroMaterial.STREAM_CODEC, MicroMaterialComponent::material, 35 | MicroMaterialComponent::new 36 | ); 37 | 38 | public MicroMaterialComponent { 39 | if (factoryId == -1) throw new IllegalArgumentException("Illegal factory id."); 40 | } 41 | 42 | @Contract (pure = true) 43 | public @Nullable StandardMicroFactory factory() { 44 | return StandardMicroFactory.FACTORIES.get(factoryId); 45 | } 46 | 47 | public static @Nullable MicroMaterialComponent getComponent(ItemStack stack) { 48 | return stack.get(CBMicroblockModContent.MICRO_MATERIAL_COMPONENT); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/item/SawItem.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.item; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | import net.minecraft.world.item.Tier; 5 | import net.minecraft.world.item.TieredItem; 6 | 7 | /** 8 | * Created by covers1624 on 22/10/22. 9 | */ 10 | public class SawItem extends TieredItem { 11 | 12 | public SawItem(Tier tier, Properties properties) { 13 | super(tier, properties); 14 | } 15 | 16 | @Override 17 | public boolean hasCraftingRemainingItem(ItemStack stack) { 18 | return true; 19 | } 20 | 21 | @Override 22 | public ItemStack getCraftingRemainingItem(ItemStack stack) { 23 | if (stack.isDamageableItem()) { 24 | if (stack.getDamageValue() + 1 >= stack.getMaxDamage()) { 25 | return ItemStack.EMPTY; 26 | } 27 | ItemStack newStack = stack.copy(); 28 | newStack.setDamageValue(stack.getDamageValue() + 1); 29 | return newStack; 30 | } 31 | return stack; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/item/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.item; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/ExecutablePlacement.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import codechicken.multipart.block.TileMultipart; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.item.ItemStack; 7 | import net.minecraft.world.level.Level; 8 | 9 | /** 10 | * Created by covers1624 on 20/10/22. 11 | */ 12 | public abstract class ExecutablePlacement { 13 | 14 | public final BlockPos pos; 15 | public final MicroblockPart part; 16 | 17 | protected ExecutablePlacement(BlockPos pos, MicroblockPart part) { 18 | this.pos = pos; 19 | this.part = part; 20 | } 21 | 22 | public abstract void place(Level level, Player player, ItemStack stack); 23 | 24 | public abstract void consume(Level level, Player player, ItemStack stack); 25 | 26 | public static class AdditionPlacement extends ExecutablePlacement { 27 | 28 | public AdditionPlacement(BlockPos pos, MicroblockPart part) { 29 | super(pos, part); 30 | } 31 | 32 | @Override 33 | public void place(Level level, Player player, ItemStack stack) { 34 | TileMultipart.addPart(level, pos, part); 35 | } 36 | 37 | @Override 38 | public void consume(Level level, Player player, ItemStack stack) { 39 | stack.shrink(1); 40 | } 41 | } 42 | 43 | public static class ExpandingPlacement extends ExecutablePlacement { 44 | 45 | private final MicroblockPart oPart; 46 | 47 | public ExpandingPlacement(BlockPos pos, MicroblockPart nPart, MicroblockPart oPart) { 48 | super(pos, nPart); 49 | this.oPart = oPart; 50 | } 51 | 52 | @Override 53 | public void place(Level level, Player player, ItemStack stack) { 54 | oPart.shape = part.shape; 55 | oPart.tile().notifyPartChange(oPart); 56 | oPart.sendShapeUpdate(); 57 | } 58 | 59 | @Override 60 | public void consume(Level level, Player player, ItemStack stack) { 61 | stack.shrink(1); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/IMicroOcclusion.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import codechicken.lib.vec.Cuboid6; 4 | import codechicken.microblock.api.MicroMaterial; 5 | import codechicken.multipart.api.part.SlottedPart; 6 | 7 | /** 8 | * Created by covers1624 on 10/7/22. 9 | */ 10 | public interface IMicroOcclusion extends SlottedPart { 11 | 12 | int getSlot(); 13 | 14 | int getSize(); 15 | 16 | MicroMaterial getMaterial(); 17 | 18 | Cuboid6 getBounds(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/IMicroShrinkRender.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import codechicken.lib.vec.Cuboid6; 4 | import codechicken.multipart.api.part.MultiPart; 5 | 6 | /** 7 | * Created by covers1624 on 10/7/22. 8 | */ 9 | public interface IMicroShrinkRender extends MultiPart { 10 | 11 | int getPriorityClass(); 12 | 13 | int getSlot(); 14 | 15 | int getSize(); 16 | 17 | boolean isTransparent(); 18 | 19 | Cuboid6 getBounds(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/MicroblockPartFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import codechicken.lib.data.MCDataInput; 4 | import codechicken.microblock.api.MicroMaterial; 5 | import codechicken.microblock.util.MicroMaterialRegistry; 6 | import codechicken.multipart.api.MultipartType; 7 | import net.minecraft.nbt.CompoundTag; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * Created by covers1624 on 26/6/22. 13 | */ 14 | public abstract class MicroblockPartFactory extends MultipartType { 15 | 16 | public abstract MicroblockPart create(boolean client, MicroMaterial material); 17 | 18 | @Nullable 19 | @Override 20 | public MicroblockPart createPartServer(CompoundTag tag) { 21 | MicroMaterial material = MicroMaterialRegistry.getMaterial(tag.getString("material")); 22 | if (material == null) return null; 23 | 24 | return create(false, material); 25 | } 26 | 27 | @NotNull 28 | @Override 29 | public MicroblockPart createPartClient(MCDataInput packet) { 30 | return create(true, packet.readRegistryIdDirect(MicroMaterialRegistry.microMaterials())); 31 | } 32 | 33 | public abstract float getResistanceFactor(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/PlacementGrid.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import codechicken.lib.vec.Line3; 4 | import codechicken.lib.vec.Vector3; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Created by covers1624 on 20/10/22. 10 | */ 11 | public abstract class PlacementGrid { 12 | 13 | public abstract int getHitSlot(Vector3 vHit, int side); 14 | 15 | public abstract List getOverlayLines(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/PlacementProperties.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | /** 6 | * Created by covers1624 on 20/10/22. 7 | */ 8 | public abstract class PlacementProperties { 9 | 10 | public abstract int opposite(int slot, int side); 11 | 12 | public boolean sneakOpposite(int slot, int side) { 13 | return true; 14 | } 15 | 16 | public boolean expand(int slot, int size) { 17 | return true; 18 | } 19 | 20 | public abstract MicroblockPartFactory microFactory(); 21 | 22 | public abstract PlacementGrid placementGrid(); 23 | 24 | @Nullable 25 | public ExecutablePlacement customPlacement(MicroblockPlacement placement) { 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/StandardMicroFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; 5 | import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 6 | import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; 7 | 8 | /** 9 | * Created by covers1624 on 9/7/22. 10 | */ 11 | public abstract class StandardMicroFactory extends MicroblockPartFactory { 12 | 13 | private static final Int2ObjectMap _FACTORIES = new Int2ObjectArrayMap<>(5); 14 | public static final Int2ObjectMap FACTORIES = Int2ObjectMaps.unmodifiable(_FACTORIES); 15 | 16 | public final int factoryId; 17 | 18 | protected StandardMicroFactory(int factoryId) { 19 | this.factoryId = factoryId; 20 | assert !_FACTORIES.containsKey(factoryId) : "Factory with ID already exists."; 21 | _FACTORIES.put(factoryId, this); 22 | } 23 | 24 | @Override 25 | public abstract StandardMicroblockPart create(boolean client, MicroMaterial material); 26 | 27 | public abstract int getItemSlot(); 28 | 29 | public abstract PlacementProperties placementProperties(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/corner/CornerMicroFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.corner; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import codechicken.microblock.part.StandardMicroFactory; 5 | import codechicken.microblock.part.PlacementProperties; 6 | import codechicken.microblock.part.StandardMicroblockPart; 7 | 8 | /** 9 | * Created by covers1624 on 21/10/22. 10 | */ 11 | public class CornerMicroFactory extends StandardMicroFactory { 12 | 13 | public CornerMicroFactory() { 14 | super(2); 15 | } 16 | 17 | @Override 18 | public PlacementProperties placementProperties() { 19 | return CornerPlacementProperties.CORNER_PLACEMENT; 20 | } 21 | 22 | @Override 23 | public StandardMicroblockPart create(boolean client, MicroMaterial material) { 24 | return new CornerMicroblockPart(material); 25 | } 26 | 27 | @Override 28 | public float getResistanceFactor() { 29 | return 1; 30 | } 31 | 32 | @Override 33 | public int getItemSlot() { 34 | return 7; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/corner/CornerMicroblockPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.corner; 2 | 3 | import codechicken.lib.raytracer.VoxelShapeCache; 4 | import codechicken.lib.vec.Cuboid6; 5 | import codechicken.lib.vec.Scale; 6 | import codechicken.lib.vec.Transformation; 7 | import codechicken.lib.vec.Vector3; 8 | import codechicken.microblock.api.MicroMaterial; 9 | import codechicken.microblock.part.StandardMicroFactory; 10 | import codechicken.microblock.init.CBMicroblockModContent; 11 | import codechicken.microblock.part.StandardMicroblockPart; 12 | import net.minecraft.world.phys.shapes.CollisionContext; 13 | import net.minecraft.world.phys.shapes.VoxelShape; 14 | 15 | /** 16 | * Created by covers1624 on 21/10/22. 17 | */ 18 | public class CornerMicroblockPart extends StandardMicroblockPart { 19 | 20 | public static final Cuboid6[] aBounds = new Cuboid6[256]; 21 | public static final VoxelShape[] aShapes = new VoxelShape[256]; 22 | 23 | static { 24 | for (int s = 0; s < 8; s++) { 25 | int rx = (s & 4) != 0 ? -1 : 1; 26 | int ry = (s & 1) != 0 ? -1 : 1; 27 | int rz = (s & 2) != 0 ? -1 : 1; 28 | Transformation tr = new Scale(rx, ry, rz).at(Vector3.CENTER); 29 | 30 | for (int t = 0; t < 8; t++) { 31 | double d = t / 8D; 32 | int i = t << 4 | s; 33 | aBounds[i] = new Cuboid6(0, 0, 0, d, d, d).apply(tr); 34 | aShapes[i] = VoxelShapeCache.getShape(aBounds[i]); 35 | } 36 | } 37 | } 38 | 39 | public CornerMicroblockPart(MicroMaterial material) { 40 | super(material); 41 | } 42 | 43 | @Override 44 | public void setShape(int size, int slot) { 45 | shape = (byte) (size << 4 | (slot - 7)); 46 | } 47 | 48 | @Override 49 | public VoxelShape getShape(CollisionContext context) { 50 | return aShapes[shape]; 51 | } 52 | 53 | @Override 54 | public Cuboid6 getBounds() { 55 | return aBounds[shape]; 56 | } 57 | 58 | @Override 59 | public StandardMicroFactory getMicroFactory() { 60 | return CBMicroblockModContent.CORNER_MICROBLOCK_PART.get(); 61 | } 62 | 63 | @Override 64 | public int getSlot() { 65 | return getShapeSlot() + 7; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/corner/CornerPlacementGrid.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.corner; 2 | 3 | import codechicken.lib.vec.Line3; 4 | import codechicken.lib.vec.Rotation; 5 | import codechicken.lib.vec.Vector3; 6 | import codechicken.microblock.part.PlacementGrid; 7 | import net.covers1624.quack.util.LazyValue; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by covers1624 on 21/10/22. 13 | */ 14 | public class CornerPlacementGrid extends PlacementGrid { 15 | 16 | public static final CornerPlacementGrid CORNER_GRID = new CornerPlacementGrid(); 17 | private static final LazyValue> LINES = new LazyValue<>(() -> List.of( 18 | new Line3(-0.5, 0, -0.5, -0.5, 0, 0.5), 19 | new Line3(-0.5, 0, 0.5, 0.5, 0, 0.5), 20 | new Line3(0.5, 0, 0.5, 0.5, 0, -0.5), 21 | new Line3(0.5, 0, -0.5, -0.5, 0, -0.5), 22 | new Line3(0, 0, -0.5, 0, 0, 0.5), 23 | new Line3(-0.5, 0, 0, 0.5, 0, 0) 24 | )); 25 | 26 | @Override 27 | public List getOverlayLines() { 28 | return LINES.get(); 29 | } 30 | 31 | @Override 32 | public int getHitSlot(Vector3 vHit, int side) { 33 | int s1 = ((side & 6) + 3) % 6; 34 | int s2 = ((side & 6) + 5) % 6; 35 | double u = vHit.copy().add(-0.5, -0.5, -0.5).scalarProject(Rotation.axes[s1]); 36 | double v = vHit.copy().add(-0.5, -0.5, -0.5).scalarProject(Rotation.axes[s2]); 37 | 38 | int bu = u >= 0 ? 1 : 0; 39 | int bv = v >= 0 ? 1 : 0; 40 | int bw = (side & 1) ^ 1; 41 | 42 | return 7 + (bw << (side >> 1) | bu << (s1 >> 1) | bv << (s2 >> 1)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/corner/CornerPlacementProperties.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.corner; 2 | 3 | import codechicken.microblock.part.MicroblockPartFactory; 4 | import codechicken.microblock.init.CBMicroblockModContent; 5 | import codechicken.microblock.part.PlacementGrid; 6 | import codechicken.microblock.part.PlacementProperties; 7 | 8 | import static codechicken.microblock.part.corner.CornerPlacementGrid.CORNER_GRID; 9 | 10 | /** 11 | * Created by covers1624 on 21/10/22. 12 | */ 13 | public class CornerPlacementProperties extends PlacementProperties { 14 | 15 | public static final CornerPlacementProperties CORNER_PLACEMENT = new CornerPlacementProperties(); 16 | 17 | @Override 18 | public int opposite(int slot, int side) { 19 | return ((slot - 7) ^ (1 << (side >> 1))) + 7; 20 | } 21 | 22 | @Override 23 | public MicroblockPartFactory microFactory() { 24 | return CBMicroblockModContent.CORNER_MICROBLOCK_PART.get(); 25 | } 26 | 27 | @Override 28 | public PlacementGrid placementGrid() { 29 | return CORNER_GRID; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/corner/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.part.corner; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/edge/EdgeMicroFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.edge; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import codechicken.microblock.part.StandardMicroFactory; 5 | import codechicken.microblock.part.PlacementProperties; 6 | import codechicken.microblock.part.StandardMicroblockPart; 7 | 8 | import static codechicken.microblock.part.edge.EdgePlacementProperties.EDGE_PLACEMENT; 9 | 10 | /** 11 | * Created by covers1624 on 21/10/22. 12 | */ 13 | public class EdgeMicroFactory extends StandardMicroFactory { 14 | 15 | public EdgeMicroFactory() { 16 | super(3); 17 | } 18 | 19 | @Override 20 | public PlacementProperties placementProperties() { 21 | return EDGE_PLACEMENT; 22 | } 23 | 24 | @Override 25 | public StandardMicroblockPart create(boolean client, MicroMaterial material) { 26 | return new EdgeMicroblockPart(material); 27 | } 28 | 29 | @Override 30 | public float getResistanceFactor() { 31 | return 0.5F; 32 | } 33 | 34 | @Override 35 | public int getItemSlot() { 36 | return 15; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/edge/EdgeMicroblockPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.edge; 2 | 3 | import codechicken.lib.raytracer.VoxelShapeCache; 4 | import codechicken.lib.vec.*; 5 | import codechicken.microblock.api.MicroMaterial; 6 | import codechicken.microblock.part.StandardMicroFactory; 7 | import codechicken.microblock.init.CBMicroblockModContent; 8 | import codechicken.microblock.part.StandardMicroblockPart; 9 | import codechicken.multipart.api.part.EdgePart; 10 | import net.minecraft.world.phys.shapes.CollisionContext; 11 | import net.minecraft.world.phys.shapes.VoxelShape; 12 | 13 | /** 14 | * Created by covers1624 on 21/10/22. 15 | */ 16 | public class EdgeMicroblockPart extends StandardMicroblockPart implements EdgePart { 17 | 18 | public static final Cuboid6[] aBounds = new Cuboid6[256]; 19 | public static final VoxelShape[] aShapes = new VoxelShape[256]; 20 | 21 | static { 22 | for (int s = 0; s < 12; s++) { 23 | int rx = (s & 2) != 0 ? -1 : 1; 24 | int rz = (s & 1) != 0 ? -1 : 1; 25 | Transformation tr = new TransformationList(new Scale(rx, 1, rz), AxisCycle.cycles[s >> 2]).at(Vector3.CENTER); 26 | 27 | for (int t = 1; t < 8; t++) { 28 | double d = t / 8D; 29 | int i = t << 4 | s; 30 | aBounds[i] = new Cuboid6(0, 0, 0, d, 1, d).apply(tr); 31 | aShapes[i] = VoxelShapeCache.getShape(aBounds[i]); 32 | } 33 | } 34 | } 35 | 36 | public EdgeMicroblockPart(MicroMaterial material) { 37 | super(material); 38 | } 39 | 40 | @Override 41 | public void setShape(int size, int slot) { 42 | shape = (byte) (size << 4 | (slot - 15)); 43 | } 44 | 45 | @Override 46 | public Cuboid6 getBounds() { 47 | return aBounds[shape]; 48 | } 49 | 50 | @Override 51 | public VoxelShape getShape(CollisionContext context) { 52 | return aShapes[shape]; 53 | } 54 | 55 | @Override 56 | public StandardMicroFactory getMicroFactory() { 57 | return CBMicroblockModContent.EDGE_MICROBLOCK_PART.get(); 58 | } 59 | 60 | @Override 61 | public int getSlot() { 62 | return getShapeSlot() + 15; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/edge/EdgePlacementGrid.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.edge; 2 | 3 | import codechicken.lib.vec.Line3; 4 | import codechicken.lib.vec.Rotation; 5 | import codechicken.lib.vec.Vector3; 6 | import codechicken.microblock.part.PlacementGrid; 7 | import codechicken.multipart.util.PartMap; 8 | import net.covers1624.quack.util.LazyValue; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by covers1624 on 21/10/22. 14 | */ 15 | public class EdgePlacementGrid extends PlacementGrid { 16 | 17 | public static final EdgePlacementGrid EDGE_GRID = new EdgePlacementGrid(); 18 | private static final LazyValue> LINES = new LazyValue<>(() -> List.of( 19 | new Line3(-0.5, 0, -0.5, -0.5, 0, 0.5), 20 | new Line3(-0.5, 0, 0.5, 0.5, 0, 0.5), 21 | new Line3(0.5, 0, 0.5, 0.5, 0, -0.5), 22 | new Line3(0.5, 0, -0.5, -0.5, 0, -0.5), 23 | new Line3(0.25, 0, -0.5, 0.25, 0, 0.5), 24 | new Line3(-0.25, 0, -0.5, -0.25, 0, 0.5), 25 | new Line3(-0.5, 0, 0.25, 0.5, 0, 0.25), 26 | new Line3(-0.5, 0, -0.25, 0.5, 0, -0.25) 27 | )); 28 | 29 | @Override 30 | public List getOverlayLines() { 31 | return LINES.get(); 32 | } 33 | 34 | @Override 35 | public int getHitSlot(Vector3 vHit, int side) { 36 | int s1 = (side + 2) % 6; 37 | int s2 = (side + 4) % 6; 38 | double u = vHit.copy().add(-0.5, -0.5, -0.5).scalarProject(Rotation.axes[s1]); 39 | double v = vHit.copy().add(-0.5, -0.5, -0.5).scalarProject(Rotation.axes[s2]); 40 | 41 | if (Math.abs(u) < 4 / 16D && Math.abs(v) < 4 / 16D) { 42 | return -1; 43 | } 44 | 45 | if (Math.abs(u) > 4 / 16D && Math.abs(v) > 4 / 16D) { 46 | return PartMap.edgeBetween(u > 0 ? s1 : s1 ^ 1, v > 0 ? s2 : s2 ^ 1); 47 | } 48 | 49 | int s = Math.abs(u) > Math.abs(v) ? (u > 0 ? s1 : s1 ^ 1) : (v > 0 ? s2 : s2 ^ 1); 50 | 51 | return PartMap.edgeBetween(side ^ 1, s); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/edge/EdgePlacementProperties.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.edge; 2 | 3 | import codechicken.microblock.part.MicroblockPartFactory; 4 | import codechicken.microblock.init.CBMicroblockModContent; 5 | import codechicken.microblock.part.*; 6 | import codechicken.multipart.api.part.MultiPart; 7 | import codechicken.multipart.util.PartMap; 8 | import codechicken.multipart.util.PartRayTraceResult; 9 | 10 | /** 11 | * Created by covers1624 on 21/10/22. 12 | */ 13 | public class EdgePlacementProperties extends PlacementProperties { 14 | 15 | public static final EdgePlacementProperties EDGE_PLACEMENT = new EdgePlacementProperties(); 16 | 17 | @Override 18 | public MicroblockPartFactory microFactory() { 19 | return CBMicroblockModContent.EDGE_MICROBLOCK_PART.get(); 20 | } 21 | 22 | @Override 23 | public PlacementGrid placementGrid() { 24 | return EdgePlacementGrid.EDGE_GRID; 25 | } 26 | 27 | @Override 28 | public int opposite(int slot, int side) { 29 | if (slot < 0) { // Custom placement 30 | return slot; 31 | } 32 | int e = slot - 15; 33 | return 15 + PartMap.packEdgeBits(e, PartMap.unpackEdgeBits(e) ^ (1 << (side >> 1))); 34 | } 35 | 36 | @Override 37 | public ExecutablePlacement customPlacement(MicroblockPlacement placement) { 38 | if (placement.size % 2 == 1) return null; 39 | PostMicroblockFactory postFactory = CBMicroblockModContent.POST_MICROBLOCK_PART.get(); 40 | 41 | PostMicroblockPart part = postFactory.create(placement.level.isClientSide, placement.material); 42 | part.setShape(placement.size, placement.side >> 1); 43 | if (placement.doExpand) { 44 | MultiPart hPart = ((PartRayTraceResult) placement.hit).part; 45 | if (hPart.getType() == postFactory) { 46 | MicroblockPart mPart = (MicroblockPart) hPart; 47 | if (mPart.material == placement.material && mPart.getSize() + placement.size < 8) { 48 | part.shape = (byte) ((mPart.getSize() + placement.size) << 4 | mPart.getShapeSlot()); 49 | return placement.expand(mPart, part); 50 | } 51 | } 52 | } 53 | 54 | if (placement.slot >= 0) return null; 55 | 56 | if (placement.internal && !placement.oppMod) { 57 | return placement.internalPlacement(placement.hTile, part); 58 | } 59 | 60 | return placement.externalPlacement(part); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/edge/PostMicroblockFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.edge; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import codechicken.microblock.part.MicroblockPartFactory; 5 | 6 | /** 7 | * Created by covers1624 on 21/10/22. 8 | */ 9 | public class PostMicroblockFactory extends MicroblockPartFactory { 10 | 11 | @Override 12 | public PostMicroblockPart create(boolean client, MicroMaterial material) { 13 | return new PostMicroblockPart(material); 14 | } 15 | 16 | @Override 17 | public float getResistanceFactor() { 18 | return 0.5F; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/edge/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.part.edge; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/face/FaceEdgeGrid.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.face; 2 | 3 | import codechicken.lib.vec.Line3; 4 | import codechicken.lib.vec.Rotation; 5 | import codechicken.lib.vec.Vector3; 6 | import codechicken.microblock.part.PlacementGrid; 7 | import com.mojang.blaze3d.vertex.VertexConsumer; 8 | import net.covers1624.quack.util.LazyValue; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by covers1624 on 20/10/22. 14 | */ 15 | public class FaceEdgeGrid extends PlacementGrid { 16 | 17 | public static final FaceEdgeGrid FACE_PLACEMENT_GRID = new FaceEdgeGrid(1 / 4D); 18 | public static final FaceEdgeGrid HOLLOW_PLACEMENT_GRID = new FaceEdgeGrid(3 / 8D); 19 | 20 | private final double size; 21 | private final LazyValue> lines; 22 | 23 | public FaceEdgeGrid(double size) { 24 | this.size = size; 25 | lines = new LazyValue<>(() -> List.of( 26 | new Line3(-0.5, 0, -0.5, -0.5, 0, 0.5), 27 | new Line3(-0.5, 0, 0.5, 0.5, 0, 0.5), 28 | new Line3(0.5, 0, 0.5, 0.5, 0, -0.5), 29 | new Line3(0.5, 0, -0.5, -0.5, 0, -0.5), 30 | new Line3(0.5, 0, 0.5, size, 0, size), 31 | new Line3(-0.5, 0, 0.5, -size, 0, size), 32 | new Line3(0.5, 0, -0.5, size, 0, -size), 33 | new Line3(-0.5, 0, -0.5, -size, 0, -size), 34 | new Line3(-size, 0, -size, -size, 0, size), 35 | new Line3(-size, 0, size, size, 0, size), 36 | new Line3(size, 0, size, size, 0, -size), 37 | new Line3(size, 0, -size, -size, 0, -size) 38 | )); 39 | } 40 | 41 | @Override 42 | public List getOverlayLines() { 43 | return lines.get(); 44 | } 45 | 46 | @Override 47 | public int getHitSlot(Vector3 vHit, int side) { 48 | int s1 = (side + 2) % 6; 49 | int s2 = (side + 4) % 6; 50 | double u = vHit.copy().add(-0.5, -0.5, -0.5).scalarProject(Rotation.axes[s1]); 51 | double v = vHit.copy().add(-0.5, -0.5, -0.5).scalarProject(Rotation.axes[s2]); 52 | 53 | if (Math.abs(u) < size && Math.abs(v) < size) { 54 | return side ^ 1; 55 | } 56 | if (Math.abs(u) > Math.abs(v)) { 57 | return u > 0 ? s1 : s1 ^ 1; 58 | } 59 | return v > 0 ? s2 : s2 ^ 1; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/face/FaceMicroFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.face; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import codechicken.microblock.part.StandardMicroFactory; 5 | import codechicken.microblock.part.PlacementProperties; 6 | 7 | import static codechicken.microblock.part.face.FacePlacementProperties.FACE_PLACEMENT; 8 | 9 | /** 10 | * Created by covers1624 on 17/10/22. 11 | */ 12 | public class FaceMicroFactory extends StandardMicroFactory { 13 | 14 | public FaceMicroFactory() { 15 | super(0); 16 | } 17 | 18 | @Override 19 | public FaceMicroblockPart create(boolean client, MicroMaterial material) { 20 | return new FaceMicroblockPart(material); 21 | } 22 | 23 | @Override 24 | public float getResistanceFactor() { 25 | return 1; 26 | } 27 | 28 | @Override 29 | public PlacementProperties placementProperties() { 30 | return FACE_PLACEMENT; 31 | } 32 | 33 | @Override 34 | public int getItemSlot() { 35 | return 3; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/face/FaceMicroblockPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.face; 2 | 3 | import codechicken.lib.raytracer.VoxelShapeCache; 4 | import codechicken.lib.vec.Cuboid6; 5 | import codechicken.lib.vec.Rotation; 6 | import codechicken.lib.vec.Transformation; 7 | import codechicken.lib.vec.Vector3; 8 | import codechicken.microblock.api.MicroMaterial; 9 | import codechicken.microblock.init.CBMicroblockModContent; 10 | import codechicken.microblock.part.StandardMicroFactory; 11 | import codechicken.microblock.part.StandardMicroblockPart; 12 | import codechicken.microblock.util.MaskedCuboid; 13 | import codechicken.multipart.api.part.FacePart; 14 | import com.google.common.collect.ImmutableSet; 15 | import net.minecraft.world.phys.shapes.CollisionContext; 16 | import net.minecraft.world.phys.shapes.VoxelShape; 17 | 18 | /** 19 | * Created by covers1624 on 20/10/22. 20 | */ 21 | public class FaceMicroblockPart extends StandardMicroblockPart implements FacePart { 22 | 23 | public static final Cuboid6[] aBounds = new Cuboid6[256]; 24 | public static final VoxelShape[] aShapes = new VoxelShape[256]; 25 | 26 | static { 27 | for (int s = 0; s < 6; s++) { 28 | Transformation transform = Rotation.sideRotations[s].at(Vector3.CENTER); 29 | for (int t = 1; t < 8; t++) { 30 | double d = t / 8D; 31 | int i = t << 4 | s; 32 | aBounds[i] = new Cuboid6(0, 0, 0, 1, d, 1).apply(transform); 33 | aShapes[i] = VoxelShapeCache.getShape(aBounds[i]); 34 | } 35 | } 36 | } 37 | 38 | public FaceMicroblockPart(MicroMaterial material) { 39 | super(material); 40 | } 41 | 42 | @Override 43 | public Cuboid6 getBounds() { 44 | return aBounds[shape]; 45 | } 46 | 47 | @Override 48 | public VoxelShape getShape(CollisionContext context) { 49 | return aShapes[shape]; 50 | } 51 | 52 | @Override 53 | public Iterable getRenderCuboids(boolean isInventory) { 54 | if (isInventory) return ImmutableSet.of(MaskedCuboid.of(getBounds(), 0)); 55 | 56 | if (isTransparent()) return ImmutableSet.of(MaskedCuboid.of(renderBounds, renderMask)); 57 | 58 | return ImmutableSet.of( 59 | MaskedCuboid.of(renderBounds, renderMask | 1 << getSlot()), // All faces except our slot use these bounds. 60 | MaskedCuboid.of(getBounds(), ~(1 << getSlot())) // Our slot renders at our full bounds. 61 | ); 62 | } 63 | 64 | @Override 65 | public StandardMicroFactory getMicroFactory() { 66 | return CBMicroblockModContent.FACE_MICROBLOCK_PART.get(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/face/FacePlacementProperties.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.face; 2 | 3 | import codechicken.microblock.part.MicroblockPartFactory; 4 | import codechicken.microblock.init.CBMicroblockModContent; 5 | import codechicken.microblock.part.PlacementGrid; 6 | import codechicken.microblock.part.PlacementProperties; 7 | 8 | /** 9 | * Created by covers1624 on 20/10/22. 10 | */ 11 | public class FacePlacementProperties extends PlacementProperties { 12 | 13 | public static final FacePlacementProperties FACE_PLACEMENT = new FacePlacementProperties(); 14 | 15 | @Override 16 | public int opposite(int slot, int side) { 17 | return slot ^ 1; 18 | } 19 | 20 | @Override 21 | public boolean expand(int slot, int size) { 22 | return sneakOpposite(slot, size); 23 | } 24 | 25 | @Override 26 | public boolean sneakOpposite(int slot, int side) { 27 | return slot == (side ^ 1); 28 | } 29 | 30 | @Override 31 | public MicroblockPartFactory microFactory() { 32 | return CBMicroblockModContent.FACE_MICROBLOCK_PART.get(); 33 | } 34 | 35 | @Override 36 | public PlacementGrid placementGrid() { 37 | return FaceEdgeGrid.FACE_PLACEMENT_GRID; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/face/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.part.face; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/hollow/HollowMicroFactory.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.hollow; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import codechicken.microblock.part.StandardMicroFactory; 5 | import codechicken.microblock.part.PlacementProperties; 6 | import codechicken.microblock.part.StandardMicroblockPart; 7 | 8 | import static codechicken.microblock.part.hollow.HollowPlacementProperties.HOLLOW_PLACEMENT; 9 | 10 | /** 11 | * Created by covers1624 on 20/10/22. 12 | */ 13 | public class HollowMicroFactory extends StandardMicroFactory { 14 | 15 | public HollowMicroFactory() { 16 | super(1); 17 | } 18 | 19 | @Override 20 | public PlacementProperties placementProperties() { 21 | return HOLLOW_PLACEMENT; 22 | } 23 | 24 | @Override 25 | public StandardMicroblockPart create(boolean client, MicroMaterial material) { 26 | return new HollowMicroblockPart(material); 27 | } 28 | 29 | @Override 30 | public float getResistanceFactor() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public int getItemSlot() { 36 | return 3; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/hollow/HollowPlacementProperties.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.part.hollow; 2 | 3 | import codechicken.microblock.part.MicroblockPartFactory; 4 | import codechicken.microblock.init.CBMicroblockModContent; 5 | import codechicken.microblock.part.PlacementGrid; 6 | import codechicken.microblock.part.face.FaceEdgeGrid; 7 | import codechicken.microblock.part.face.FacePlacementProperties; 8 | 9 | /** 10 | * Created by covers1624 on 20/10/22. 11 | */ 12 | public class HollowPlacementProperties extends FacePlacementProperties { 13 | 14 | public static final HollowPlacementProperties HOLLOW_PLACEMENT = new HollowPlacementProperties(); 15 | 16 | @Override 17 | public MicroblockPartFactory microFactory() { 18 | return CBMicroblockModContent.HOLLOW_MICROBLOCK_PART.get(); 19 | } 20 | 21 | @Override 22 | public PlacementGrid placementGrid() { 23 | return FaceEdgeGrid.HOLLOW_PLACEMENT_GRID; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/hollow/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.part.hollow; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/part/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.part; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/recipe/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.recipe; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/util/MaskedCuboid.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.util; 2 | 3 | import codechicken.lib.vec.Cuboid6; 4 | import com.google.common.cache.Cache; 5 | import com.google.common.cache.CacheBuilder; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.function.Function; 9 | 10 | /** 11 | * A cuboid and side mask pair. 12 | *

13 | * Cuboids should be treated as immutable and not modified. 14 | *

15 | * Masks are, if bit set, side is important. 16 | *

17 | * {@link MaskedCuboid}s should be created with {@link MaskedCuboid#of(Cuboid6, int)} to receive automatic interning and caching. 18 | * Making sure these are interned is important, as these are stored inside caches as keys, and may be long-lived. Ensuring that 19 | * duplicates aren't saved is important to keep memory usage down. Ideally we should cache sets of cuboids as well, but that's a later issue. 20 | *

21 | * Created by covers1624 on 20/10/22. 22 | */ 23 | public record MaskedCuboid(Cuboid6 box, int sideMask) { 24 | 25 | private static final Cache CUBOID_CACHE = CacheBuilder.newBuilder() 26 | .expireAfterAccess(1, TimeUnit.HOURS) 27 | .build(); 28 | 29 | public static MaskedCuboid intern(MaskedCuboid cuboid) { 30 | return CUBOID_CACHE.asMap().computeIfAbsent(cuboid, Function.identity()); 31 | } 32 | 33 | public static MaskedCuboid of(Cuboid6 box, int sideMask) { 34 | return intern(new MaskedCuboid(box.copy(), sideMask)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/util/MicroMaterialRegistry.java: -------------------------------------------------------------------------------- 1 | package codechicken.microblock.util; 2 | 3 | import codechicken.microblock.api.MicroMaterial; 4 | import net.covers1624.quack.util.CrashLock; 5 | import net.minecraft.core.Registry; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.neoforged.bus.api.IEventBus; 8 | import net.neoforged.neoforge.registries.NewRegistryEvent; 9 | import net.neoforged.neoforge.registries.RegistryBuilder; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import static java.util.Objects.requireNonNull; 13 | 14 | /** 15 | * Created by covers1624 on 26/6/22. 16 | */ 17 | public class MicroMaterialRegistry { 18 | 19 | private static final CrashLock LOCK = new CrashLock("Already initialized"); 20 | 21 | @Deprecated 22 | public static Registry microMaterials() { 23 | return MicroMaterial.REGISTRY; 24 | } 25 | 26 | public static void init(IEventBus modBus) { 27 | LOCK.lock(); 28 | 29 | modBus.addListener(MicroMaterialRegistry::createRegistries); 30 | } 31 | 32 | private static void createRegistries(NewRegistryEvent event) { 33 | event.register(MicroMaterial.REGISTRY); 34 | } 35 | 36 | @Nullable 37 | public static MicroMaterial getMaterial(String name) { 38 | return getMaterial(ResourceLocation.parse(name)); 39 | } 40 | 41 | @Nullable 42 | public static MicroMaterial getMaterial(ResourceLocation name) { 43 | return microMaterials().get(name); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/codechicken/microblock/util/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.microblock.util; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/CBMultipart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart; 2 | 3 | import codechicken.multipart.api.RegisterMultipartTraitsEvent; 4 | import codechicken.multipart.api.part.*; 5 | import codechicken.multipart.api.part.redstone.RedstonePart; 6 | import codechicken.multipart.handler.PlacementConversionHandler; 7 | import codechicken.multipart.init.CBMultipartModContent; 8 | import codechicken.multipart.init.ClientInit; 9 | import codechicken.multipart.init.DataGenerators; 10 | import codechicken.multipart.init.MultiPartRegistries; 11 | import codechicken.multipart.network.MultiPartNetwork; 12 | import codechicken.multipart.trait.*; 13 | import codechicken.multipart.util.MultipartGenerator; 14 | import codechicken.multipart.util.MultipartLoadHandler; 15 | import codechicken.multipart.util.TickScheduler; 16 | import net.minecraft.world.Container; 17 | import net.minecraft.world.WorldlyContainer; 18 | import net.neoforged.bus.api.IEventBus; 19 | import net.neoforged.fml.ModContainer; 20 | import net.neoforged.fml.common.Mod; 21 | import net.neoforged.fml.loading.FMLEnvironment; 22 | import org.jetbrains.annotations.Nullable; 23 | 24 | import static codechicken.multipart.CBMultipart.MOD_ID; 25 | import static java.util.Objects.requireNonNull; 26 | 27 | /** 28 | * Created by covers1624 on 30/8/20. 29 | */ 30 | @Mod (MOD_ID) 31 | public class CBMultipart { 32 | 33 | public static final String MOD_ID = "cb_multipart"; 34 | 35 | private static @Nullable ModContainer container; 36 | 37 | public CBMultipart(ModContainer container, IEventBus modBus) { 38 | CBMultipart.container = container; 39 | CBMultipartModContent.init(modBus); 40 | MultiPartRegistries.init(modBus); 41 | DataGenerators.init(modBus); 42 | 43 | if (FMLEnvironment.dist.isClient()) { 44 | ClientInit.init(modBus); 45 | } 46 | 47 | MultipartGenerator.INSTANCE.load(modBus); 48 | MultipartLoadHandler.init(); 49 | MultiPartNetwork.init(modBus); 50 | PlacementConversionHandler.init(); 51 | TickScheduler.init(); 52 | 53 | modBus.addListener(this::onRegisterMultipartTraits); 54 | } 55 | 56 | public static ModContainer container() { 57 | return requireNonNull(container); 58 | } 59 | 60 | private void onRegisterMultipartTraits(RegisterMultipartTraitsEvent event) { 61 | event.registerClientTrait(AnimateTickPart.class, TAnimateTickTile.class); 62 | event.registerTrait(CapabilityProviderPart.class, TCapabilityTile.class); 63 | event.registerTrait(Container.class, TInventoryTile.class); 64 | event.registerTrait(WorldlyContainer.class, TInventoryTile.class); 65 | event.registerTrait(PartialOcclusionPart.class, TPartialOcclusionTile.class); 66 | event.registerTrait(RedstonePart.class, TRedstoneTile.class); 67 | event.registerTrait(SlottedPart.class, TSlottedTile.class); 68 | event.registerTrait(TickablePart.class, TTickableTile.class); 69 | event.registerServerTrait(NeighborTileChangePart.class, TTileChangeTile.class); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/ItemMultipart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.block.TileMultipart; 5 | import codechicken.multipart.util.MultipartPlaceContext; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.sounds.SoundSource; 8 | import net.minecraft.world.InteractionResult; 9 | import net.minecraft.world.item.Item; 10 | import net.minecraft.world.item.context.UseOnContext; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraft.world.level.block.SoundType; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | /** 16 | * Created by covers1624 on 1/1/21. 17 | */ 18 | public abstract class ItemMultipart extends Item { 19 | 20 | public ItemMultipart(Properties properties) { 21 | super(properties); 22 | } 23 | 24 | @Nullable 25 | public abstract MultiPart newPart(MultipartPlaceContext context); 26 | 27 | @Override 28 | public InteractionResult useOn(UseOnContext context) { 29 | 30 | MultipartPlaceContext ctx = new MultipartPlaceContext(context); 31 | 32 | if (ctx.getHitDepth() < 1 && place(ctx)) { 33 | return InteractionResult.SUCCESS; 34 | } 35 | return place(ctx.applyOffset()) ? InteractionResult.SUCCESS : InteractionResult.FAIL; 36 | } 37 | 38 | private boolean place(MultipartPlaceContext context) { 39 | Level world = context.getLevel(); 40 | BlockPos pos = context.getClickedPos(); 41 | 42 | MultiPart part = newPart(context); 43 | if (part == null || !TileMultipart.canPlacePart(context, part)) return false; 44 | 45 | if (!world.isClientSide) { 46 | TileMultipart.addPart(world, pos, part); 47 | SoundType sound = part.getPlacementSound(context); 48 | if (sound != null) { 49 | world.playSound(null, pos, sound.getPlaceSound(), 50 | SoundSource.BLOCKS, (sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F); 51 | } 52 | } 53 | if (!context.getPlayer().getAbilities().instabuild) { 54 | context.getItemInHand().shrink(1); 55 | } 56 | return true; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/MultipartClientRegistry.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.api.part.render.PartRenderer; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | import static net.covers1624.quack.util.SneakyUtils.unsafeCast; 9 | 10 | /** 11 | * Created by covers1624 on 8/11/21. 12 | */ 13 | public class MultipartClientRegistry { 14 | 15 | /** 16 | * Register a {@link PartRenderer} for a given {@link MultipartType}. 17 | * 18 | * @param type The {@link MultipartType}. 19 | * @param renderer The {@link PartRenderer}. 20 | * @throws IllegalArgumentException When attempting to replace an already registered {@link PartRenderer} 21 | */ 22 | public static synchronized void register(MultipartType type, PartRenderer renderer) { 23 | if (type.renderer != null) { 24 | throw new IllegalArgumentException( 25 | "Attempted to replace part renderer for: " 26 | + type.getRegistryName() 27 | + ". Prev: " + type.renderer.getClass() 28 | + ", New: " + renderer.getClass() 29 | ); 30 | } 31 | type.renderer = renderer; 32 | } 33 | 34 | /** 35 | * Get the {@link PartRenderer} for the given {@link MultipartType}. 36 | * 37 | * @param type The {@link MultipartType} to get the renderer for. 38 | * @return The {@link PartRenderer}, or null if none exists. 39 | */ 40 | @Nullable 41 | public static PartRenderer getRenderer(MultipartType type) { 42 | return unsafeCast(type.renderer); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/MultipartType.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.lib.data.MCDataInput; 4 | import codechicken.multipart.CBMultipart; 5 | import codechicken.multipart.api.part.MultiPart; 6 | import codechicken.multipart.init.MultiPartRegistries; 7 | import net.minecraft.core.Registry; 8 | import net.minecraft.nbt.CompoundTag; 9 | import net.minecraft.resources.ResourceKey; 10 | import net.minecraft.resources.ResourceLocation; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.Objects; 14 | 15 | /** 16 | * Created by covers1624 on 3/16/20. 17 | */ 18 | public abstract class MultipartType { 19 | 20 | /** 21 | * The registry name used by MultipartType. 22 | */ 23 | public static final ResourceKey>> MULTIPART_TYPES = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(CBMultipart.MOD_ID, "multipart_types")); 24 | 25 | // Internal. 26 | @Nullable 27 | Object renderer; 28 | 29 | public MultipartType() { 30 | } 31 | 32 | /** 33 | * Called to create a {@link MultiPart} instance on the server 34 | * side from a {@link CompoundTag} tag. This is called when 35 | * the MultiPart is loaded from disk. 36 | * 37 | * @param tag The {@link CompoundTag} to load from. 38 | * @return The {@link MultiPart} instance, or {@code null} to 39 | * discard. 40 | */ 41 | @Nullable 42 | public abstract T createPartServer(CompoundTag tag); 43 | 44 | /** 45 | * Called to create a {@link MultiPart} instance from 46 | * the provided {@link MCDataInput}. 47 | *

48 | * The supplied packet comes from {@link MultiPart#writeDesc} 49 | * 50 | * @param packet The packet. 51 | * @return The client-side part. 52 | */ 53 | public abstract T createPartClient(MCDataInput packet); 54 | 55 | public ResourceLocation getRegistryName() { 56 | return Objects.requireNonNull(MultiPartRegistries.multipartTypes().getKey(this)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/NormalOcclusionTest.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.api.part.BaseMultipart; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.api.part.NormalOcclusionPart; 6 | import codechicken.multipart.api.part.PartialOcclusionPart; 7 | import net.minecraft.world.phys.shapes.BooleanOp; 8 | import net.minecraft.world.phys.shapes.Shapes; 9 | import net.minecraft.world.phys.shapes.VoxelShape; 10 | 11 | /** 12 | * Utilities for performing a 'normal' occlusion test, where no Shape may obstruct the other in any capacity. 13 | */ 14 | public class NormalOcclusionTest { 15 | 16 | /** 17 | * Test if part1 is occluded by part2 in any way. 18 | *

19 | * Checks both {@link NormalOcclusionPart#getOcclusionShape()} and 20 | * {@link PartialOcclusionPart#getPartialOcclusionShape()} on part2. 21 | * 22 | * @param part1 The first part. 23 | * @param part2 The other part. 24 | * @return If part1 is occluded by part2 in any way. 25 | */ 26 | public static boolean test(NormalOcclusionPart part1, MultiPart part2) { 27 | VoxelShape shape = Shapes.empty(); 28 | if (part2 instanceof NormalOcclusionPart p) { 29 | shape = Shapes.or(shape, p.getOcclusionShape()); 30 | } 31 | if (part2 instanceof PartialOcclusionPart p) { 32 | shape = Shapes.or(shape, p.getPartialOcclusionShape()); 33 | } 34 | 35 | return !Shapes.joinIsNotEmpty(shape, part1.getOcclusionShape(), BooleanOp.AND); 36 | } 37 | 38 | /** 39 | * Wraps the given {@link VoxelShape} to a {@link NormalOcclusionPart} for the purpose of occlusion testing. 40 | * 41 | * @param shape The shape. 42 | * @return The wrapped VoxelShape part. 43 | */ 44 | public static NormalOcclusionPart of(VoxelShape shape) { 45 | return new NormallyOccludedPart(shape); 46 | } 47 | 48 | private static class NormallyOccludedPart extends BaseMultipart implements NormalOcclusionPart { 49 | 50 | private final VoxelShape shape; 51 | 52 | private NormallyOccludedPart(VoxelShape shape) { 53 | this.shape = shape; 54 | } 55 | 56 | @Override 57 | public MultipartType getType() { 58 | // Yes, this returns null, however should only be used 59 | // inside the occlusion engine, making this safe. 60 | //noinspection ConstantConditions 61 | return null; 62 | } 63 | 64 | @Override 65 | public VoxelShape getOcclusionShape() { 66 | return shape; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/PartConverter.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.CBMultipart; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.util.MultipartPlaceContext; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.core.Registry; 8 | import net.minecraft.resources.ResourceKey; 9 | import net.minecraft.resources.ResourceLocation; 10 | import net.minecraft.world.item.ItemStack; 11 | import net.minecraft.world.item.context.UseOnContext; 12 | import net.minecraft.world.level.LevelAccessor; 13 | import net.minecraft.world.level.block.state.BlockState; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.Collection; 17 | import java.util.Collections; 18 | 19 | /** 20 | * Created by covers1624 on 4/17/20. 21 | */ 22 | public abstract class PartConverter { 23 | 24 | /** 25 | * The registry name used by PartConverter. 26 | */ 27 | public static final ResourceKey> PART_CONVERTERS = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(CBMultipart.MOD_ID, "part_converters")); 28 | 29 | private static final ConversionResult> EMPTY_LIST = new ConversionResult<>(Collections.emptyList(), false); 30 | private static final ConversionResult EMPTY = new ConversionResult<>(null, false); 31 | 32 | /** 33 | * Convert the block / tile at the given position in world, to a {@link Collection} 34 | * of {@link MultiPart} instances. 35 | * It should be noted, that a mod can choose to delete the block at the position by 36 | * returning a failed {@link ConversionResult}. 37 | * 38 | * @param world The world. 39 | * @param pos The pos. 40 | * @param state The state at pos in world. 41 | * @return A {@link ConversionResult}, providing a {@link Collection} of {@link MultiPart} instances 42 | * if conversion was successful. 43 | */ 44 | public ConversionResult> convert(LevelAccessor world, BlockPos pos, BlockState state) { 45 | return emptyResultList(); 46 | } 47 | 48 | /** 49 | * Convert an {@link ItemStack} about to be placed into a {@link MultiPart} instance. 50 | * 51 | * @param context The {@link MultipartPlaceContext} for the placement. 52 | * @return A {@link ConversionResult}, providing the {@link MultiPart} instance if conversion 53 | * was successful. 54 | */ 55 | public ConversionResult convert(MultipartPlaceContext context) { 56 | return emptyResult(); 57 | } 58 | 59 | public static ConversionResult> emptyResultList() { 60 | return EMPTY_LIST; 61 | } 62 | 63 | public static ConversionResult emptyResult() { 64 | return EMPTY; 65 | } 66 | 67 | public record ConversionResult(@Nullable T result, boolean success) { 68 | 69 | public static ConversionResult success(T thing) { 70 | return new ConversionResult<>(thing, true); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/RedstoneConnectorBlock.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.api.tile.RedstoneConnector; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.world.level.LevelReader; 6 | import net.minecraft.world.level.block.Block; 7 | 8 | /** 9 | * Block version of {@link RedstoneConnector} 10 | * Due to the inadequate {@link Block#canConnectRedstone} not handling the bottom side (nor the top particularly well) 11 | */ 12 | public interface RedstoneConnectorBlock { 13 | 14 | int getConnectionMask(LevelReader world, BlockPos pos, int side); 15 | 16 | int weakPowerLevel(LevelReader world, BlockPos pos, int side, int mask); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/RegisterMultipartTraitsEvent.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.block.TileMultipart; 5 | import codechicken.multipart.util.MultipartGenerator; 6 | import net.neoforged.bus.api.Event; 7 | import net.neoforged.fml.event.IModBusEvent; 8 | import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; 9 | 10 | /** 11 | * Fired on the mod bus for mods to register their traits and passthrough interfaces 12 | * for {@link TileMultipart} classes. 13 | *

14 | * This is fired at the end of mod loading, from {@link FMLLoadCompleteEvent}. 15 | *

16 | * Created by covers1624 on 20/1/24. 17 | */ 18 | public final class RegisterMultipartTraitsEvent extends Event implements IModBusEvent { 19 | 20 | private final MultipartGenerator generator; 21 | 22 | public RegisterMultipartTraitsEvent(MultipartGenerator generator) { 23 | this.generator = generator; 24 | } 25 | 26 | /** 27 | * Register {@code trait} to be mixed into the {@link TileMultipart} when 28 | * {@code marker} is found implemented on a {@link MultiPart} instance. 29 | * 30 | * @param marker The part marker class. 31 | * @param trait The trait to implement. 32 | */ 33 | public void registerTrait(Class marker, Class trait) { 34 | generator.registerTrait(marker, trait); 35 | } 36 | 37 | /** 38 | * The same as {@link #registerTrait(Class, Class)} however, only effective client side. 39 | * 40 | * @param marker The part marker class. 41 | * @param trait The trait to implement. 42 | */ 43 | public void registerClientTrait(Class marker, Class trait) { 44 | generator.registerTrait(marker, trait, null); 45 | } 46 | 47 | /** 48 | * The same as {@link #registerTrait(Class, Class)} however, only effective server side (including integrated server). 49 | * 50 | * @param marker The part marker class. 51 | * @param trait The trait to implement. 52 | */ 53 | public void registerServerTrait(Class marker, Class trait) { 54 | generator.registerTrait(marker, null, trait); 55 | } 56 | 57 | /** 58 | * Register the specified class, when found on a {@link MultiPart} instance:
59 | * - Implemented the interface on the {@link TileMultipart} instance with all methods proxied through to your part.
60 | * - Only allow one instance of a part with this interface in the block space. 61 | * 62 | * @param iFace The interface to register. 63 | */ 64 | public void registerPassthroughInterface(Class iFace) { 65 | generator.registerPassThroughInterface(iFace); 66 | } 67 | 68 | /** 69 | * The same as {@link #registerPassthroughInterface(Class)} however, only effective client side. 70 | * 71 | * @param iFace The interface to register. 72 | */ 73 | public void registerClientPassthroughInterface(Class iFace) { 74 | generator.registerPassThroughInterface(iFace, true, false); 75 | } 76 | 77 | /** 78 | * The same as {@link #registerPassthroughInterface(Class)} however, only effective server side (including integrated server). 79 | * 80 | * @param iFace The interface to register. 81 | */ 82 | public void registerServerPassthroughInterface(Class iFace) { 83 | generator.registerPassThroughInterface(iFace, false, true); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/SimpleMultipartType.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.lib.data.MCDataInput; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import net.minecraft.nbt.CompoundTag; 6 | 7 | /** 8 | * A simple implementation of {@link MultipartType} providing 9 | * a unified callback to create the part for each side. 10 | *

11 | * Created by covers1624 on 3/17/20. 12 | */ 13 | public class SimpleMultipartType extends MultipartType { 14 | 15 | private final SimpleMultiPartTypeFactory factory; 16 | 17 | public SimpleMultipartType(SimpleMultiPartTypeFactory factory) { 18 | this.factory = factory; 19 | } 20 | 21 | @Override 22 | public T createPartServer(CompoundTag tag) { 23 | return factory.create(false); 24 | } 25 | 26 | @Override 27 | public T createPartClient(MCDataInput packet) { 28 | return factory.create(true); 29 | } 30 | 31 | public interface SimpleMultiPartTypeFactory { 32 | 33 | T create(boolean client); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/TickableTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api; 2 | 3 | import codechicken.multipart.block.BlockMultipart; 4 | 5 | /** 6 | * Internal interface for identifying tiles owned by {@link BlockMultipart}, which can tick. 7 | *

8 | * Created by covers1624 on 23/10/22. 9 | */ 10 | public interface TickableTile { 11 | 12 | void tick(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.api; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/AnimateTickPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import net.minecraft.util.RandomSource; 4 | import net.minecraft.world.level.block.Block; 5 | 6 | /** 7 | * Parts that need to do random animation ticks can implement this. 8 | * This is passed from {@link Block#animateTick}. 9 | *

10 | * Created by covers1624 on 2/9/20. 11 | */ 12 | public interface AnimateTickPart extends MultiPart { 13 | 14 | void animateTick(RandomSource random); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/BaseMultipart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import codechicken.multipart.block.TileMultipart; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Created by covers1624 on 6/6/22. 8 | */ 9 | public abstract class BaseMultipart implements MultiPart { 10 | 11 | @Nullable 12 | private TileMultipart tile; 13 | 14 | @Override 15 | public final TileMultipart tile() { 16 | assert tile != null; 17 | return tile; 18 | } 19 | 20 | @Override 21 | public final boolean hasTile() { 22 | return tile != null; 23 | } 24 | 25 | public final void bind(TileMultipart tile) { 26 | this.tile = tile; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/CapabilityProviderPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import net.neoforged.neoforge.capabilities.BlockCapability; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Created by covers1624 on 7/1/21. 8 | */ 9 | public interface CapabilityProviderPart extends MultiPart { 10 | 11 | @Nullable T getCapability(BlockCapability capability, C context); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/EdgePart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | /** 4 | * Interface which must be implemented by parts that go in an edge slot. 5 | */ 6 | public interface EdgePart extends SlottedPart { 7 | 8 | /** 9 | * Return true if this part can conduct redstone signal or let redstone signal pass through it. 10 | */ 11 | default boolean conductsRedstone() { 12 | return false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/FacePart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | /** 4 | * Interface which must be implemented by parts that go in a face part. 5 | */ 6 | public interface FacePart extends SlottedPart { 7 | 8 | /** 9 | * Return the redstone conduction map for which signal can pass through this part on the face. 10 | * Eg, hollow covers return 0x10 as signal can pass through the center hole. 11 | */ 12 | default int redstoneConductionMap() { 13 | return 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/IconHitEffectsPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import codechicken.lib.render.particle.CustomParticleHandler; 4 | import codechicken.lib.vec.Cuboid6; 5 | import codechicken.multipart.util.PartRayTraceResult; 6 | import net.minecraft.client.particle.ParticleEngine; 7 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; 8 | import net.neoforged.api.distmarker.Dist; 9 | import net.neoforged.api.distmarker.OnlyIn; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * Interface for parts which want easy custom hit/breaking particles. 16 | *

17 | * Created by covers1624 on 6/6/22. 18 | */ 19 | public interface IconHitEffectsPart extends MultiPart { 20 | 21 | Cuboid6 getBounds(); 22 | 23 | @OnlyIn (Dist.CLIENT) 24 | TextureAtlasSprite getBreakingIcon(PartRayTraceResult hit); 25 | 26 | @OnlyIn (Dist.CLIENT) 27 | TextureAtlasSprite getBrokenIcon(int side); 28 | 29 | @Override 30 | @OnlyIn (Dist.CLIENT) 31 | default void addHitEffects(PartRayTraceResult hit, ParticleEngine engine) { 32 | addHitEffects(this, hit, engine); 33 | } 34 | 35 | @Override 36 | @OnlyIn (Dist.CLIENT) 37 | default void addDestroyEffects(PartRayTraceResult hit, ParticleEngine engine) { 38 | addDestroyEffects(this, engine); 39 | } 40 | 41 | @OnlyIn (Dist.CLIENT) 42 | static void addHitEffects(IconHitEffectsPart part, PartRayTraceResult hit, ParticleEngine engine) { 43 | CustomParticleHandler.addBlockHitEffects( 44 | part.level(), 45 | part.getBounds().copy().add(part.pos()), 46 | hit.getDirection(), 47 | part.getBreakingIcon(hit), 48 | engine 49 | ); 50 | } 51 | 52 | @OnlyIn (Dist.CLIENT) 53 | static void addDestroyEffects(IconHitEffectsPart part, ParticleEngine engine) { 54 | addDestroyEffects(part, engine, true); 55 | } 56 | 57 | @OnlyIn (Dist.CLIENT) 58 | static void addDestroyEffects(IconHitEffectsPart part, ParticleEngine engine, boolean scaleDensity) { 59 | List icons = new ArrayList<>(6); 60 | for (int i = 0; i < 6; i++) { 61 | icons.add(i, part.getBrokenIcon(i)); 62 | } 63 | Cuboid6 bounds = scaleDensity ? part.getBounds() : Cuboid6.full; 64 | 65 | CustomParticleHandler.addBlockDestroyEffects(part.level(), bounds.copy().add(part.pos()), icons, engine); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/ModelRenderPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import codechicken.multipart.api.part.render.PartBakedModelRenderer; 4 | import net.minecraft.world.level.block.state.BlockState; 5 | import net.neoforged.neoforge.client.model.data.ModelData; 6 | 7 | /** 8 | * Companion to {@link PartBakedModelRenderer} 9 | */ 10 | // TODO 1.21.4, Refactor this to `BlockStateModelPart` 11 | public interface ModelRenderPart extends MultiPart { 12 | 13 | BlockState getCurrentState(); 14 | 15 | @Override 16 | default ModelData getModelData() { 17 | return ModelData.EMPTY; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/NeighborTileChangePart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import net.minecraft.core.Direction; 4 | 5 | /** 6 | * Mixin interface for parts that want to be notified of neighbor tile change events (comparators or inventory maintainers) 7 | */ 8 | public interface NeighborTileChangePart extends MultiPart { 9 | 10 | /** 11 | * Returns whether this part needs calls for tile changes through one solid block 12 | */ 13 | boolean weakTileChanges(); 14 | 15 | /** 16 | * Callback for neighbor tile changes, from same function in Block 17 | */ 18 | void onNeighborTileChanged(Direction side, boolean weak); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/NormalOcclusionPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import codechicken.multipart.api.NormalOcclusionTest; 4 | import net.minecraft.world.phys.shapes.VoxelShape; 5 | 6 | /** 7 | * Provides standard bounding box based occlusion testing. 8 | * If any two parts have overlapping bounding boxes, the test fails 9 | */ 10 | public interface NormalOcclusionPart extends MultiPart { 11 | 12 | VoxelShape getOcclusionShape(); 13 | 14 | @Override 15 | default boolean occlusionTest(MultiPart nPart) { 16 | return NormalOcclusionTest.test(this, nPart); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/PartialOcclusionPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import codechicken.multipart.block.TileMultipart; 4 | import net.minecraft.world.phys.shapes.VoxelShape; 5 | 6 | /** 7 | * This class provides a special type of occlusion model used by microblocks. 8 | * The partial occlusion test defines bounding boxes that may intersect, so long as no part is completely obscured by a combination of the others. 9 | * Partial bounding boxes may not intersect with normal bounding boxes from {@link NormalOcclusionPart} 10 | *

11 | * This part marker is managed by the mixin trait {@link codechicken.multipart.trait.TPartialOcclusionTile}. 12 | */ 13 | public interface PartialOcclusionPart extends MultiPart { 14 | 15 | /** 16 | * The VoxelShape to use for Partial occlusion tests, 17 | * this shape must not be occluded by any other {@link PartialOcclusionPart}'s shape, 18 | * unless {@link #allowCompleteOcclusion()} returns true. 19 | *

20 | * It is expected that this method return some form of cached instance that does NOT change 21 | * each call, unless some internal state has changed. 22 | *

23 | * If this shape changes after initial placement, call {@link TileMultipart#markShapeChange()}. 24 | * 25 | * @return the VoxelShape for partial occlusion tests. 26 | */ 27 | VoxelShape getPartialOcclusionShape(); 28 | 29 | /** 30 | * Return true if this part may be completely obscured 31 | */ 32 | default boolean allowCompleteOcclusion() { 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/RandomTickPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | import codechicken.multipart.util.TickScheduler; 4 | import net.minecraft.world.level.chunk.LevelChunk; 5 | 6 | /** 7 | * Interface for parts with random update ticks. 8 | *

9 | * Used in conjunction with {@link TickScheduler} 10 | */ 11 | public interface RandomTickPart extends MultiPart { 12 | 13 | /** 14 | * Called on random update. 15 | *

16 | * Random ticks are between 800 and 1600 ticks from their last scheduled/random tick. 17 | */ 18 | void randomTick(); 19 | 20 | @Override 21 | default void onChunkLoad(LevelChunk chunk) { 22 | TickScheduler.loadRandomTick(this, chunk); 23 | } 24 | 25 | @Override 26 | default void onWorldJoin() { 27 | TickScheduler.loadRandomTick(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/SlottedPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part; 2 | 3 | /** 4 | * Interface for parts that fill a slot based configuration as defined in PartMap. 5 | * If this is implemented, calling partMap(slot) on the host tile will return this part if the corresponding bit in the slotMask is set 6 | *

7 | * Marker interface for TSlottedTile 8 | */ 9 | public interface SlottedPart extends MultiPart { 10 | 11 | /** 12 | * a bitmask of slots that this part fills. slot x is 1< 11 | * see IRedstoneConnector for mask definition. 12 | * 13 | * @param side The side to get the mask for. 14 | * @return The mask. 15 | */ 16 | int getConnectionMask(int side); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/redstone/RedstonePart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part.redstone; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.trait.extern.RedstoneTile; 5 | 6 | /** 7 | * Interface for parts with redstone interaction 8 | *

9 | * Marker interface for TRedstoneTile. This means that if a part is an instance of {@link RedstonePart}, 10 | * the container tile may be cast to {@link RedstoneTile} 11 | */ 12 | public interface RedstonePart extends MultiPart { 13 | 14 | /** 15 | * Returns the strong (indirect, through blocks) signal being emitted by this part on the specified side. 16 | * 17 | * @param side The side index. 18 | * @return The redstone signal. 19 | */ 20 | int strongPowerLevel(int side); 21 | 22 | /** 23 | * Returns the weak (direct) being emitted by this part on the specified side. 24 | * 25 | * @param side The side index. 26 | * @return The redstone signal. 27 | */ 28 | int weakPowerLevel(int side); 29 | 30 | /** 31 | * Returns weather this part can connect to redstone on the specified side. 32 | *

33 | * Blocking parts like covers will be handled by RedstoneInteractions. 34 | * 35 | * @param side The side index. 36 | * @return True if redstone can connect. 37 | */ 38 | boolean canConnectRedstone(int side); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/redstone/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.api.part.redstone; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/render/PartBakedModelRenderer.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.part.render; 2 | 3 | import codechicken.lib.render.CCRenderState; 4 | import codechicken.multipart.api.part.ModelRenderPart; 5 | import com.mojang.blaze3d.vertex.PoseStack; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.client.renderer.RenderType; 8 | import net.minecraft.client.renderer.block.BlockRenderDispatcher; 9 | import net.minecraft.client.renderer.block.model.BakedQuad; 10 | import net.minecraft.client.resources.model.BakedModel; 11 | import net.minecraft.core.Direction; 12 | import net.minecraft.util.RandomSource; 13 | import net.minecraft.world.level.block.state.BlockState; 14 | import net.neoforged.neoforge.client.model.data.ModelData; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * A simple {@link PartRenderer} partial implementation to render a {@link BlockState}'s {@link BakedModel}. 21 | *

22 | * 23 | * @see PartRenderer 24 | * Created by covers1624 on 7/11/21. 25 | */ 26 | // TODO 1.21.4, Refactor to BlockStatePartBakedModelRenderer 27 | public interface PartBakedModelRenderer extends PartRenderer { 28 | 29 | /** 30 | * Returns a new {@link PartBakedModelRenderer}. 31 | * Use this when you don't require overriding any of the other methods provided by {@link PartRenderer}. 32 | * 33 | * @return The {@link PartBakedModelRenderer} instance. 34 | */ 35 | static PartBakedModelRenderer simple() { 36 | return new PartBakedModelRenderer<>() { }; 37 | } 38 | 39 | @Override 40 | default List getQuads(T part, @Nullable Direction side, RandomSource rand, ModelData data, @Nullable RenderType renderType) { 41 | BlockRenderDispatcher blockRenderer = Minecraft.getInstance().getBlockRenderer(); 42 | BlockState state = part.getCurrentState(); 43 | RandomSource randy = RandomSource.create(); 44 | BakedModel model = blockRenderer.getBlockModel(state); 45 | 46 | if (renderType != null && !model.getRenderTypes(state, randy, data).contains(renderType)) return List.of(); 47 | 48 | return model.getQuads(state, side, rand, data, renderType); 49 | } 50 | 51 | @Override 52 | @SuppressWarnings ("ConstantConditions") 53 | default void renderStatic(T part, @Nullable RenderType layer, CCRenderState ccrs) { 54 | 55 | BlockRenderDispatcher blockRenderer = Minecraft.getInstance().getBlockRenderer(); 56 | BlockState state = part.getCurrentState(); 57 | RandomSource randy = RandomSource.create(); 58 | 59 | if (layer != null && !blockRenderer.getBlockModel(state).getRenderTypes(state, randy, part.getModelData()).contains(layer)) return; 60 | 61 | blockRenderer.renderBatched( 62 | part.getCurrentState(), 63 | part.pos(), 64 | ccrs.lightMatrix.access, 65 | new PoseStack(), 66 | ccrs.getConsumer(), 67 | true, 68 | randy, 69 | part.getModelData(), 70 | layer 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/part/render/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.api.part.render; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/tile/RedstoneConnector.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.api.tile; 2 | 3 | /** 4 | * Interface for tile entities which split their redstone connections into a mask for each side (edges and center) 5 | * 6 | * All connection masks are a 5 bit map. 7 | * The lowest 4 bits correspond to the connection toward the face specified Rotation.rotateSide(side & 6, b) where b is the bit index from lowest to highest. 8 | * Bit 5 corresponds to a connection opposite side. 9 | */ 10 | public interface RedstoneConnector { 11 | 12 | /** 13 | * Returns the connection mask of this tile for the given side. 14 | * 15 | * @param side The side index. 16 | * @return The connection mask. 17 | */ 18 | int getConnectionMask(int side); 19 | 20 | /** 21 | * Returns the weak power level provided by this tile on the given side, through the given mask. 22 | * 23 | * @param side The side index. 24 | * @param mask The connection mask. 25 | * @return The redstone signal. 26 | */ 27 | int weakPowerLevel(int side, int mask); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/api/tile/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.api.tile; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/block/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.block; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/client/ClientEventHandler.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.client; 2 | 3 | import codechicken.lib.render.RenderUtils; 4 | import codechicken.lib.vec.Matrix4; 5 | import codechicken.multipart.api.MultipartClientRegistry; 6 | import codechicken.multipart.api.part.MultiPart; 7 | import codechicken.multipart.api.part.render.PartRenderer; 8 | import codechicken.multipart.block.BlockMultipart; 9 | import codechicken.multipart.block.TileMultipart; 10 | import codechicken.multipart.util.PartRayTraceResult; 11 | import com.mojang.blaze3d.vertex.PoseStack; 12 | import net.minecraft.client.Camera; 13 | import net.minecraft.client.renderer.MultiBufferSource; 14 | import net.minecraft.world.phys.BlockHitResult; 15 | import net.minecraft.world.phys.shapes.CollisionContext; 16 | import net.neoforged.neoforge.client.event.RenderHighlightEvent; 17 | import net.neoforged.neoforge.common.NeoForge; 18 | 19 | import static net.covers1624.quack.util.SneakyUtils.unsafeCast; 20 | 21 | /** 22 | * Created by covers1624 on 2/9/20. 23 | */ 24 | public class ClientEventHandler { 25 | 26 | public static void init() { 27 | NeoForge.EVENT_BUS.addListener(ClientEventHandler::onDrawBlockHighlight); 28 | } 29 | 30 | private static void onDrawBlockHighlight(RenderHighlightEvent.Block event) { 31 | Camera camera = event.getCamera(); 32 | PoseStack mStack = event.getPoseStack(); 33 | MultiBufferSource buffers = event.getMultiBufferSource(); 34 | float partialTicks = event.getDeltaTracker().getGameTimeDeltaPartialTick(true); 35 | BlockHitResult target = event.getTarget(); 36 | if (!(target instanceof PartRayTraceResult hit)) return; 37 | 38 | TileMultipart tile = BlockMultipart.getTile(camera.getEntity().level(), target.getBlockPos()); 39 | if (tile == null) return; 40 | 41 | MultiPart part = hit.part; 42 | 43 | PartRenderer renderer = MultipartClientRegistry.getRenderer(part.getType()); 44 | 45 | if (renderer == null || !renderer.drawHighlight(unsafeCast(part), hit, camera, mStack, buffers, partialTicks)) { 46 | Matrix4 mat = new Matrix4(mStack); 47 | mat.translate(hit.getBlockPos()); 48 | RenderUtils.bufferShapeHitBox(mat, buffers, camera, part.getShape(CollisionContext.empty())); 49 | } 50 | event.setCanceled(true); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/client/MultipartModelData.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.client; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.block.TileMultipart; 5 | import net.neoforged.neoforge.client.model.data.ModelData; 6 | import net.neoforged.neoforge.client.model.data.ModelProperty; 7 | 8 | import java.util.IdentityHashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * Created by covers1624 on 2/8/25. 13 | */ 14 | public record MultipartModelData( 15 | TileMultipart tile, 16 | IdentityHashMap partsAndData 17 | ) { 18 | public static final ModelProperty DATA = new ModelProperty<>(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/client/MultipartTileBakedModel.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.client; 2 | 3 | import codechicken.lib.texture.TextureUtils; 4 | import codechicken.multipart.api.MultipartClientRegistry; 5 | import codechicken.multipart.api.part.MultiPart; 6 | import codechicken.multipart.util.PartRayTraceResult; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.renderer.RenderType; 9 | import net.minecraft.client.renderer.block.model.BakedQuad; 10 | import net.minecraft.client.renderer.block.model.ItemOverrides; 11 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; 12 | import net.minecraft.core.Direction; 13 | import net.minecraft.util.RandomSource; 14 | import net.minecraft.world.level.block.state.BlockState; 15 | import net.neoforged.neoforge.client.model.IDynamicBakedModel; 16 | import net.neoforged.neoforge.client.model.data.ModelData; 17 | import net.neoforged.neoforge.common.util.ConcatenatedListView; 18 | import org.jetbrains.annotations.Nullable; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * Created by covers1624 on 1/21/25. 25 | */ 26 | public class MultipartTileBakedModel implements IDynamicBakedModel { 27 | 28 | @Override 29 | public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, ModelData data, @Nullable RenderType renderType) { 30 | var multipartData = data.get(MultipartModelData.DATA); 31 | if (multipartData == null) return List.of(); 32 | 33 | if (renderType == null && Minecraft.getInstance().hitResult instanceof PartRayTraceResult hit) { 34 | return getPartQuads( 35 | hit.part, 36 | side, 37 | rand, 38 | multipartData.partsAndData().getOrDefault(hit.part, ModelData.EMPTY), 39 | null 40 | ); 41 | } 42 | 43 | var parts = multipartData.tile().getPartList(); 44 | List> quads = new ArrayList<>(parts.size()); 45 | for (MultiPart part : parts) { 46 | var partQuads = getPartQuads(part, side, rand, multipartData.partsAndData().getOrDefault(part, ModelData.EMPTY), renderType); 47 | if (!partQuads.isEmpty()) { 48 | quads.add(partQuads); 49 | } 50 | } 51 | 52 | return ConcatenatedListView.of(quads); 53 | } 54 | 55 | private static List getPartQuads(MultiPart part, @Nullable Direction side, RandomSource rand, ModelData data, @Nullable RenderType renderType) { 56 | var renderer = MultipartClientRegistry.getRenderer(part.getType()); 57 | if (renderer != null) { 58 | return renderer.getQuads(part, side, rand, data, renderType); 59 | } 60 | 61 | return List.of(); 62 | } 63 | 64 | // @formatter:off 65 | @Override public boolean useAmbientOcclusion() { return true; } 66 | @Override public boolean isGui3d() { return true; } 67 | @Override public boolean usesBlockLight() { return true; } 68 | @Override public boolean isCustomRenderer() { return false; } 69 | @Override public TextureAtlasSprite getParticleIcon() { return TextureUtils.getMissingSprite(); } 70 | @Override public ItemOverrides getOverrides() { return ItemOverrides.EMPTY; } 71 | // @formatter:on 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/client/MultipartTileRenderer.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.client; 2 | 3 | import codechicken.lib.render.CCRenderState; 4 | import codechicken.lib.vec.Cuboid6; 5 | import codechicken.multipart.api.MultipartClientRegistry; 6 | import codechicken.multipart.api.part.MultiPart; 7 | import codechicken.multipart.api.part.render.PartRenderer; 8 | import codechicken.multipart.block.TileMultipart; 9 | import com.mojang.blaze3d.vertex.PoseStack; 10 | import net.minecraft.client.renderer.MultiBufferSource; 11 | import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; 12 | import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; 13 | import net.minecraft.world.level.block.entity.BlockEntity; 14 | import net.minecraft.world.phys.AABB; 15 | 16 | import static net.covers1624.quack.util.SneakyUtils.unsafeCast; 17 | 18 | /** 19 | * Created by covers1624 on 31/8/20. 20 | */ 21 | public class MultipartTileRenderer implements BlockEntityRenderer { 22 | 23 | public MultipartTileRenderer(BlockEntityRendererProvider.Context ctx) { 24 | } 25 | 26 | @Override 27 | public void render(BlockEntity t, float partialTicks, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay) { 28 | if (!(t instanceof TileMultipart tile)) return; 29 | CCRenderState ccrs = CCRenderState.instance(); 30 | ccrs.reset(); 31 | ccrs.brightness = packedLight; 32 | ccrs.overlay = packedOverlay; 33 | for (MultiPart p : tile.getPartList()) { 34 | PartRenderer renderer = MultipartClientRegistry.getRenderer(p.getType()); 35 | if (renderer != null) { 36 | renderer.renderDynamic(unsafeCast(p), mStack, buffers, packedLight, packedOverlay, partialTicks); 37 | } 38 | } 39 | } 40 | 41 | @Override 42 | public AABB getRenderBoundingBox(BlockEntity t) { 43 | if (!(t instanceof TileMultipart tile)) return new AABB(t.getBlockPos()); 44 | 45 | Cuboid6 c = Cuboid6.full.copy(); 46 | tile.operate(e -> c.enclose(e.getRenderBounds())); 47 | return c.add(tile.getBlockPos()).aabb(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/client/Shaders.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.client; 2 | 3 | import codechicken.lib.render.shader.CCShaderInstance; 4 | import com.mojang.blaze3d.vertex.DefaultVertexFormat; 5 | import net.covers1624.quack.util.CrashLock; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.neoforged.bus.api.IEventBus; 8 | import net.neoforged.neoforge.client.event.RegisterShadersEvent; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.Objects; 12 | 13 | import static codechicken.multipart.CBMultipart.MOD_ID; 14 | 15 | /** 16 | * Created by covers1624 on 23/1/24. 17 | */ 18 | public class Shaders { 19 | 20 | public static final CrashLock LOCK = new CrashLock("Already Initialised"); 21 | 22 | private static @Nullable CCShaderInstance highlightShader; 23 | 24 | public static void init(IEventBus modBus) { 25 | LOCK.lock(); 26 | modBus.addListener(Shaders::onRegisterShaders); 27 | } 28 | 29 | private static void onRegisterShaders(RegisterShadersEvent event) { 30 | event.registerShader( 31 | CCShaderInstance.create(event.getResourceProvider(), ResourceLocation.fromNamespaceAndPath(MOD_ID, "highlight"), DefaultVertexFormat.BLOCK), 32 | e -> highlightShader = (CCShaderInstance) e 33 | ); 34 | } 35 | 36 | public static CCShaderInstance highlightShader() { 37 | return Objects.requireNonNull(highlightShader, "Highlight shader not loaded yet."); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/client/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.client; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/handler/ControlKeyHandler.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.handler; 2 | 3 | import codechicken.lib.packet.PacketCustom; 4 | import codechicken.multipart.network.MultiPartNetwork; 5 | import codechicken.multipart.util.ControlKeyModifier; 6 | import net.covers1624.quack.util.CrashLock; 7 | import net.minecraft.client.KeyMapping; 8 | import net.minecraft.client.Minecraft; 9 | import net.neoforged.bus.api.IEventBus; 10 | import net.neoforged.neoforge.client.event.ClientTickEvent; 11 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 12 | import net.neoforged.neoforge.common.NeoForge; 13 | import org.lwjgl.glfw.GLFW; 14 | 15 | /** 16 | * Created by covers1624 on 1/9/20. 17 | */ 18 | public class ControlKeyHandler { 19 | 20 | private static final CrashLock LOCK = new CrashLock("Already initialized."); 21 | private static final KeyMapping KEY = new KeyMapping("key.control", GLFW.GLFW_KEY_LEFT_CONTROL, "key.categories.gameplay"); 22 | 23 | private static boolean lastPressed = false; 24 | 25 | public static void init(IEventBus modBus) { 26 | LOCK.lock(); 27 | modBus.addListener(ControlKeyHandler::register); 28 | 29 | NeoForge.EVENT_BUS.addListener(ControlKeyHandler::tick); 30 | } 31 | 32 | private static void register(RegisterKeyMappingsEvent event) { 33 | event.register(KEY); 34 | } 35 | 36 | private static void tick(ClientTickEvent.Post event) { 37 | boolean pressed = KEY.isDown(); 38 | if (pressed != lastPressed) { 39 | lastPressed = pressed; 40 | Minecraft mc = Minecraft.getInstance(); 41 | if (mc.getConnection() != null) { 42 | ControlKeyModifier.setIsControlDown(mc.player, pressed); 43 | PacketCustom packet = new PacketCustom(MultiPartNetwork.NET_CHANNEL, MultiPartNetwork.S_CONTROL_KEY_MODIFIER, mc.player.registryAccess()); 44 | packet.writeBoolean(pressed); 45 | packet.sendToServer(); 46 | } 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/handler/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.handler; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/init/CBMultipartModContent.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.init; 2 | 3 | import codechicken.multipart.block.BlockMultipart; 4 | import codechicken.multipart.block.TileMultipart; 5 | import codechicken.multipart.util.MultipartLoadHandler.TileNBTContainer; 6 | import net.covers1624.quack.util.CrashLock; 7 | import net.minecraft.core.registries.Registries; 8 | import net.minecraft.world.level.block.Block; 9 | import net.minecraft.world.level.block.entity.BlockEntityType; 10 | import net.neoforged.bus.api.EventPriority; 11 | import net.neoforged.bus.api.IEventBus; 12 | import net.neoforged.neoforge.capabilities.BlockCapability; 13 | import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; 14 | import net.neoforged.neoforge.registries.DeferredHolder; 15 | import net.neoforged.neoforge.registries.DeferredRegister; 16 | 17 | import static codechicken.multipart.CBMultipart.MOD_ID; 18 | import static net.covers1624.quack.util.SneakyUtils.unsafeCast; 19 | 20 | /** 21 | * Created by covers1624 on 2/9/20. 22 | */ 23 | 24 | public class CBMultipartModContent { 25 | 26 | private static final CrashLock LOCK = new CrashLock("Already initialized."); 27 | private static final DeferredRegister BLOCKS = DeferredRegister.create(Registries.BLOCK, MOD_ID); 28 | private static final DeferredRegister> TILES = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, MOD_ID); 29 | 30 | public static final DeferredHolder MULTIPART_BLOCK = BLOCKS.register("multipart", BlockMultipart::new); 31 | 32 | public static final DeferredHolder, BlockEntityType> MULTIPART_TILE_TYPE = TILES.register("saved_multipart", () -> 33 | BlockEntityType.Builder.of(TileNBTContainer::new, MULTIPART_BLOCK.get()).build(null)); 34 | 35 | public static void init(IEventBus modBus) { 36 | LOCK.lock(); 37 | BLOCKS.register(modBus); 38 | TILES.register(modBus); 39 | 40 | // TODO This may not be low enough, we can capture the event instance and do this in LoadComplete if it's an issue. 41 | modBus.addListener(EventPriority.LOWEST, CBMultipartModContent::onRegisterCapabilities); 42 | } 43 | 44 | private static void onRegisterCapabilities(RegisterCapabilitiesEvent event) { 45 | for (BlockCapability cap : BlockCapability.getAll()) { 46 | event.registerBlockEntity(cap, CBMultipartModContent.MULTIPART_TILE_TYPE.get(), (tile, ctx) -> { 47 | if (tile instanceof TileMultipart t) { 48 | return unsafeCast(t.getCapability(cap, unsafeCast(ctx))); 49 | } 50 | return null; 51 | }); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/init/ClientInit.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.init; 2 | 3 | import codechicken.multipart.client.ClientEventHandler; 4 | import codechicken.multipart.client.MultipartTileRenderer; 5 | import codechicken.multipart.client.Shaders; 6 | import codechicken.multipart.handler.ControlKeyHandler; 7 | import net.covers1624.quack.util.CrashLock; 8 | import net.minecraft.client.renderer.ItemBlockRenderTypes; 9 | import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; 10 | import net.neoforged.bus.api.IEventBus; 11 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 12 | import net.neoforged.neoforge.client.event.EntityRenderersEvent; 13 | 14 | /** 15 | * Created by covers1624 on 26/6/22. 16 | */ 17 | public class ClientInit { 18 | 19 | private static final CrashLock LOCK = new CrashLock("Already initialized."); 20 | 21 | public static void init(IEventBus modBus) { 22 | LOCK.lock(); 23 | 24 | ControlKeyHandler.init(modBus); 25 | ClientEventHandler.init(); 26 | 27 | modBus.addListener(ClientInit::onClientInit); 28 | modBus.addListener(ClientInit::onRegisterRenderers); 29 | Shaders.init(modBus); 30 | } 31 | 32 | private static void onClientInit(FMLClientSetupEvent event) { 33 | ItemBlockRenderTypes.setRenderLayer(CBMultipartModContent.MULTIPART_BLOCK.get(), e -> true); 34 | } 35 | 36 | private static void onRegisterRenderers(EntityRenderersEvent.RegisterRenderers event) { 37 | BlockEntityRenderers.register(CBMultipartModContent.MULTIPART_TILE_TYPE.get(), MultipartTileRenderer::new); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/init/DataGenerators.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.init; 2 | 3 | import codechicken.lib.datagen.ClassModelLoaderBuilder; 4 | import codechicken.multipart.client.MultipartTileBakedModel; 5 | import net.covers1624.quack.util.CrashLock; 6 | import net.minecraft.data.DataGenerator; 7 | import net.minecraft.data.PackOutput; 8 | import net.neoforged.bus.api.IEventBus; 9 | import net.neoforged.neoforge.client.model.generators.BlockStateProvider; 10 | import net.neoforged.neoforge.client.model.generators.ModelFile; 11 | import net.neoforged.neoforge.common.data.ExistingFileHelper; 12 | import net.neoforged.neoforge.data.event.GatherDataEvent; 13 | 14 | import static codechicken.multipart.CBMultipart.MOD_ID; 15 | 16 | /** 17 | * Created by covers1624 on 21/3/20. 18 | */ 19 | public class DataGenerators { 20 | 21 | private static final CrashLock LOCK = new CrashLock("Already initialized."); 22 | 23 | public static void init(IEventBus modBus) { 24 | LOCK.lock(); 25 | modBus.addListener(DataGenerators::gatherDataGenerators); 26 | } 27 | 28 | public static void gatherDataGenerators(GatherDataEvent event) { 29 | DataGenerator gen = event.getGenerator(); 30 | PackOutput output = gen.getPackOutput(); 31 | ExistingFileHelper files = event.getExistingFileHelper(); 32 | 33 | gen.addProvider(event.includeClient(), new BlockStates(output, files)); 34 | } 35 | 36 | private static class BlockStates extends BlockStateProvider { 37 | 38 | public BlockStates(PackOutput output, ExistingFileHelper exFileHelper) { 39 | super(output, MOD_ID, exFileHelper); 40 | } 41 | 42 | @Override 43 | protected void registerStatesAndModels() { 44 | ModelFile model = models() 45 | .withExistingParent("multipart", "block") 46 | .customLoader(ClassModelLoaderBuilder::new) 47 | .clazz(MultipartTileBakedModel.class) 48 | .end(); 49 | simpleBlock(CBMultipartModContent.MULTIPART_BLOCK.get(), model); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/init/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.init; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/internal/mixin/TileEntityMixin.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.internal.mixin; 2 | 3 | import codechicken.multipart.block.TileMultipart; 4 | import codechicken.multipart.init.CBMultipartModContent; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.core.HolderLookup; 7 | import net.minecraft.nbt.CompoundTag; 8 | import net.minecraft.world.level.block.entity.BlockEntity; 9 | import net.minecraft.world.level.block.state.BlockState; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | /** 16 | * Created by covers1624 on 21/3/21. 17 | */ 18 | @Mixin (BlockEntity.class) 19 | public class TileEntityMixin { 20 | 21 | @Inject ( 22 | method = "loadStatic", 23 | at = @At ("HEAD"), 24 | cancellable = true 25 | ) 26 | private static void onLoadStatic(BlockPos pos, BlockState state, CompoundTag tag, HolderLookup.Provider registries, CallbackInfoReturnable cir) { 27 | String s = tag.getString("id"); 28 | if (CBMultipartModContent.MULTIPART_TILE_TYPE.getId().toString().equals(s)) { 29 | cir.setReturnValue(TileMultipart.fromNBT(tag, pos, registries)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/internal/mixin/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.internal.mixin; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/internal/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.internal; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/minecraft/ClientInit.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.minecraft; 2 | 3 | import codechicken.multipart.api.MultipartClientRegistry; 4 | import codechicken.multipart.api.part.render.PartBakedModelRenderer; 5 | import net.neoforged.bus.api.IEventBus; 6 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 7 | 8 | /** 9 | * Created by covers1624 on 8/11/21. 10 | */ 11 | public class ClientInit { 12 | 13 | public static void init(IEventBus modBus) { 14 | modBus.addListener(ClientInit::onClientSetup); 15 | } 16 | 17 | private static void onClientSetup(FMLClientSetupEvent event) { 18 | MultipartClientRegistry.register(MinecraftMultipartModContent.TORCH_PART.get(), PartBakedModelRenderer.simple()); 19 | MultipartClientRegistry.register(MinecraftMultipartModContent.SOUL_TORCH_PART.get(), PartBakedModelRenderer.simple()); 20 | MultipartClientRegistry.register(MinecraftMultipartModContent.REDSTONE_TORCH_PART.get(), PartBakedModelRenderer.simple()); 21 | MultipartClientRegistry.register(MinecraftMultipartModContent.LEVER_PART.get(), PartBakedModelRenderer.simple()); 22 | MultipartClientRegistry.register(MinecraftMultipartModContent.STONE_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 23 | MultipartClientRegistry.register(MinecraftMultipartModContent.POLISHED_BLACKSTONE_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 24 | MultipartClientRegistry.register(MinecraftMultipartModContent.OAK_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 25 | MultipartClientRegistry.register(MinecraftMultipartModContent.SPRUCE_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 26 | MultipartClientRegistry.register(MinecraftMultipartModContent.BIRCH_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 27 | MultipartClientRegistry.register(MinecraftMultipartModContent.JUNGLE_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 28 | MultipartClientRegistry.register(MinecraftMultipartModContent.ACACIA_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 29 | MultipartClientRegistry.register(MinecraftMultipartModContent.DARK_OAK_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 30 | MultipartClientRegistry.register(MinecraftMultipartModContent.CRIMSON_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 31 | MultipartClientRegistry.register(MinecraftMultipartModContent.WARPED_BUTTON_PART.get(), PartBakedModelRenderer.simple()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/minecraft/McSidedStatePart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.minecraft; 2 | 3 | import codechicken.lib.vec.Vector3; 4 | import codechicken.multipart.api.part.FacePart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.core.Direction; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | 10 | public abstract class McSidedStatePart extends McStatePart implements FacePart { 11 | 12 | public McSidedStatePart() { 13 | } 14 | 15 | public McSidedStatePart(BlockState state) { 16 | super(state); 17 | } 18 | 19 | public abstract Direction getSide(); 20 | 21 | @Override 22 | public void onNeighborBlockChanged(BlockPos from) { 23 | if (!level().isClientSide) { 24 | dropIfCantStay(); 25 | } 26 | } 27 | 28 | public boolean canStay() { 29 | return state.canSurvive(level(), pos()); 30 | } 31 | 32 | public boolean dropIfCantStay() { 33 | if (!canStay()) { 34 | drop(); 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | public void drop() { 41 | TileMultipart.dropItem(getDropStack(), level(), Vector3.fromTileCenter(tile())); 42 | tile().remPart(this); 43 | } 44 | 45 | @Override 46 | public int getSlotMask() { 47 | return 1 << getSide().ordinal(); 48 | } 49 | 50 | @Override 51 | public int redstoneConductionMap() { 52 | return 0x1F; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/minecraft/MinecraftMultipart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.minecraft; 2 | 3 | import net.neoforged.bus.api.IEventBus; 4 | import net.neoforged.fml.common.Mod; 5 | import net.neoforged.fml.loading.FMLEnvironment; 6 | 7 | import static codechicken.multipart.minecraft.MinecraftMultipart.MOD_ID; 8 | 9 | @Mod (MOD_ID) 10 | public class MinecraftMultipart { 11 | 12 | public static final String MOD_ID = "cb_multipart_minecraft"; 13 | 14 | public MinecraftMultipart(IEventBus modBus) { 15 | MinecraftMultipartModContent.init(modBus); 16 | if (FMLEnvironment.dist.isClient()) { 17 | ClientInit.init(modBus); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/minecraft/SoulTorchPart.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.minecraft; 2 | 3 | import codechicken.multipart.api.MultipartType; 4 | import net.minecraft.world.level.block.Block; 5 | import net.minecraft.world.level.block.Blocks; 6 | import net.minecraft.world.level.block.state.BlockState; 7 | 8 | public class SoulTorchPart extends TorchPart { 9 | 10 | public SoulTorchPart() { 11 | } 12 | 13 | public SoulTorchPart(BlockState state) { 14 | super(state); 15 | } 16 | 17 | @Override 18 | protected Block getStandingBlock() { 19 | return Blocks.SOUL_TORCH; 20 | } 21 | 22 | @Override 23 | protected Block getWallBlock() { 24 | return Blocks.SOUL_WALL_TORCH; 25 | } 26 | 27 | @Override 28 | public MultipartType getType() { 29 | return MinecraftMultipartModContent.SOUL_TORCH_PART.get(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/minecraft/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.minecraft; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/network/MultiPartCPH.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.network; 2 | 3 | import codechicken.lib.data.MCDataInput; 4 | import codechicken.lib.packet.ICustomPacketHandler; 5 | import codechicken.lib.packet.PacketCustom; 6 | import codechicken.multipart.api.part.MultiPart; 7 | import codechicken.multipart.block.TileMultipart; 8 | import codechicken.multipart.init.MultiPartRegistries; 9 | import codechicken.multipart.util.MultipartHelper; 10 | import net.minecraft.client.Minecraft; 11 | import net.minecraft.client.multiplayer.ClientPacketListener; 12 | import net.minecraft.core.BlockPos; 13 | 14 | import static codechicken.multipart.network.MultiPartNetwork.*; 15 | 16 | /** 17 | * Created by covers1624 on 4/30/20. 18 | */ 19 | public class MultiPartCPH implements ICustomPacketHandler.IClientPacketHandler { 20 | 21 | @Override 22 | public void handlePacket(PacketCustom packet, Minecraft mc) { 23 | switch (packet.getType()) { 24 | case C_TILE_DESC -> handleTileDescPacket(packet, mc); 25 | case C_ADD_PART -> handleAddPart(packet, mc); 26 | case C_REM_PART -> handleRemPart(packet, mc); 27 | case C_PART_UPDATE -> handleUpdatePacket(packet, mc); 28 | case C_LANDING_EFFECTS -> handleLandingEffects(packet, mc); 29 | } 30 | } 31 | 32 | public static void handleTileDescPacket(MCDataInput packet, Minecraft mc) { 33 | BlockPos pos = packet.readPos(); 34 | TileMultipart.handleDescPacket(mc.level, pos, packet); 35 | } 36 | 37 | public static void handleAddPart(MCDataInput packet, Minecraft mc) { 38 | BlockPos pos = packet.readPos(); 39 | MultipartHelper.addPart(mc.level, pos, MultiPartRegistries.readPart(packet)); 40 | } 41 | 42 | public static void handleRemPart(MCDataInput packet, Minecraft mc) { 43 | byte partIndex = packet.readByte(); 44 | BlockPos pos = packet.readPos(); 45 | if (mc.level.getBlockEntity(pos) instanceof TileMultipart tile) { 46 | tile.remPart_impl(tile.getPartList().get(partIndex)); 47 | } 48 | } 49 | 50 | public static void handleUpdatePacket(MCDataInput packet, Minecraft mc) { 51 | int partIndex = packet.readByte(); 52 | BlockPos pos = packet.readPos(); 53 | if (mc.level.getBlockEntity(pos) instanceof TileMultipart tile) { 54 | MultiPart part = tile.getPartList().get(partIndex); 55 | if (part != null) { 56 | part.readUpdate(packet); 57 | } 58 | } 59 | } 60 | 61 | private void handleLandingEffects(PacketCustom packet, Minecraft mc) { 62 | BlockPos pos = packet.readPos(); 63 | if (mc.level.getBlockEntity(pos) instanceof TileMultipart tile) { 64 | tile.addLandingEffects(packet.readVector(), packet.readVarInt()); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/network/MultiPartNetwork.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.network; 2 | 3 | import codechicken.lib.packet.PacketCustomChannel; 4 | import codechicken.multipart.CBMultipart; 5 | import net.covers1624.quack.util.CrashLock; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.neoforged.bus.api.IEventBus; 8 | 9 | /** 10 | * Created by covers1624 on 4/30/20. 11 | */ 12 | public class MultiPartNetwork { 13 | 14 | private static final CrashLock LOCK = new CrashLock("Already initialized."); 15 | public static final ResourceLocation NET_CHANNEL = ResourceLocation.fromNamespaceAndPath(CBMultipart.MOD_ID, "network"); 16 | public static final PacketCustomChannel channel = new PacketCustomChannel(NET_CHANNEL) 17 | .versioned(CBMultipart.container().getModInfo().getVersion().toString()) 18 | .client(() -> MultiPartCPH::new) 19 | .server(() -> MultiPartSPH::new); 20 | 21 | //Client handled. 22 | public static final int C_TILE_DESC = 1; 23 | public static final int C_ADD_PART = 2; 24 | public static final int C_REM_PART = 3; 25 | public static final int C_PART_UPDATE = 4; 26 | 27 | public static final int C_LANDING_EFFECTS = 10; 28 | 29 | //Server handled. 30 | public static final int S_CONTROL_KEY_MODIFIER = 1; 31 | 32 | public static void init(IEventBus modBus) { 33 | LOCK.lock(); 34 | channel.init(modBus); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/network/MultiPartSPH.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.network; 2 | 3 | import codechicken.lib.data.MCDataOutput; 4 | import codechicken.lib.packet.ICustomPacketHandler; 5 | import codechicken.lib.packet.PacketCustom; 6 | import codechicken.multipart.api.part.MultiPart; 7 | import codechicken.multipart.block.TileMultipart; 8 | import codechicken.multipart.init.MultiPartRegistries; 9 | import codechicken.multipart.util.ControlKeyModifier; 10 | import net.minecraft.server.level.ServerLevel; 11 | import net.minecraft.server.level.ServerPlayer; 12 | 13 | import java.util.function.Consumer; 14 | 15 | import static codechicken.multipart.network.MultiPartNetwork.*; 16 | 17 | /** 18 | * Created by covers1624 on 4/30/20. 19 | */ 20 | public class MultiPartSPH implements ICustomPacketHandler.IServerPacketHandler { 21 | 22 | @Override 23 | public void handlePacket(PacketCustom packet, ServerPlayer sender) { 24 | switch (packet.getType()) { 25 | case S_CONTROL_KEY_MODIFIER -> ControlKeyModifier.setIsControlDown(sender, packet.readBoolean()); 26 | } 27 | } 28 | 29 | //region Send C_TILE_DESC 30 | public static void sendDescUpdate(TileMultipart tile) { 31 | PacketCustom packet = new PacketCustom(NET_CHANNEL, C_TILE_DESC, tile.getLevel().registryAccess()); 32 | packet.writePos(tile.getBlockPos()); 33 | tile.writeDesc(packet); 34 | packet.sendToChunk(tile); 35 | } 36 | //endregion 37 | 38 | //region Send C_ADD_PART 39 | public static void sendAddPart(TileMultipart tile, MultiPart part) { 40 | ServerLevel world = (ServerLevel) tile.getLevel(); 41 | PacketCustom packet = new PacketCustom(NET_CHANNEL, C_ADD_PART, world.registryAccess()); 42 | packet.writePos(tile.getBlockPos()); 43 | MultiPartRegistries.writePart(packet, part); 44 | packet.sendToChunk(tile); 45 | } 46 | //endregion 47 | 48 | //region Send C_REM_PART 49 | public static void sendRemPart(TileMultipart tile, int partIdx) { 50 | PacketCustom packet = new PacketCustom(NET_CHANNEL, C_REM_PART, tile.getLevel().registryAccess()); 51 | packet.writeByte(partIdx); 52 | packet.writePos(tile.getBlockPos()); 53 | packet.sendToChunk(tile); 54 | } 55 | //endregion 56 | 57 | //region Send C_PART_UPDATE 58 | public static void dispatchPartUpdate(MultiPart part, Consumer func) { 59 | ServerLevel world = (ServerLevel) part.level(); 60 | PacketCustom packet = new PacketCustom(NET_CHANNEL, C_PART_UPDATE, world.registryAccess()); 61 | packet.writeByte(part.tile().getPartList().indexOf(part)); 62 | packet.writePos(part.pos()); 63 | func.accept(packet); 64 | packet.sendToChunk(part.tile()); 65 | } 66 | //endregion 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/network/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.network; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TAnimateTickTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.AnimateTickPart; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.util.RandomSource; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by covers1624 on 2/9/20. 14 | */ 15 | public class TAnimateTickTile extends TileMultipart { 16 | 17 | public TAnimateTickTile(BlockPos pos, BlockState state) { 18 | super(pos, state); 19 | } 20 | 21 | @Override 22 | public void animateTick(RandomSource random) { 23 | List jPartList = getPartList(); 24 | //noinspection ForLoopReplaceableByForEach 25 | for (int i = 0; i < jPartList.size(); i++) { 26 | MultiPart part = jPartList.get(i); 27 | if (part instanceof AnimateTickPart) { 28 | ((AnimateTickPart) part).animateTick(random); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TCapabilityTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.CapabilityProviderPart; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.core.Direction; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | import net.neoforged.neoforge.capabilities.BlockCapability; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | /** 13 | * Created by covers1624 on 7/1/21. 14 | */ 15 | public class TCapabilityTile extends TileMultipart { 16 | 17 | public TCapabilityTile(BlockPos pos, BlockState state) { 18 | super(pos, state); 19 | } 20 | 21 | @Override 22 | public @Nullable T getCapability(BlockCapability capability, C context) { 23 | // If the capability uses a Direction for context, we give slotted parts priority. 24 | if (capability.contextClass().equals(Direction.class)) { 25 | @SuppressWarnings ("unchecked") 26 | T result = getSlottedCapability((BlockCapability) capability, (Direction) context); 27 | if (result != null) { 28 | return result; 29 | } 30 | } 31 | // Otherwise, whoever is in the list first gets it, this may need to be a bit more deterministic. 32 | for (MultiPart part : getPartList()) { 33 | if (part instanceof CapabilityProviderPart capPart) { 34 | T result = capPart.getCapability(capability, context); 35 | if (result != null) { 36 | return result; 37 | } 38 | } 39 | } 40 | return null; 41 | } 42 | 43 | @SuppressWarnings ("DataFlowIssue") // Intellij nullability is unable to pass the nullable through to part.getCapability. 44 | private @Nullable T getSlottedCapability(BlockCapability capability, C context) { 45 | int slot = context != null ? context.ordinal() : 6; 46 | if (getSlottedPart(slot) instanceof CapabilityProviderPart part) { 47 | return part.getCapability(capability, context); 48 | } 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TPartialOcclusionTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.api.part.PartialOcclusionPart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.world.level.block.state.BlockState; 8 | import net.minecraft.world.phys.shapes.BooleanOp; 9 | import net.minecraft.world.phys.shapes.Shapes; 10 | import net.minecraft.world.phys.shapes.VoxelShape; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.LinkedList; 14 | import java.util.List; 15 | 16 | /** 17 | * Implementation for the partial occlusion test. 18 | *

19 | * Created by covers1624 on 2/9/20. 20 | */ 21 | public class TPartialOcclusionTile extends TileMultipart { 22 | 23 | // Cached partial occlusion test results for performance 24 | // This cache exists almost entirely for the microblock highlight renderer, due to how expensive combining VoxelShapes is. 25 | // Normal occlusion operations happen infrequently enough that this is not a performance concern during normal gameplay. 26 | // TODO, Figure out how to cleanly nuke this and do caching inside MicroblockRender. 27 | @Nullable 28 | private static Iterable lastTestParts = null; 29 | @Nullable 30 | private static VoxelShape lastTestShape = null; 31 | private static boolean lastTestResult = false; 32 | 33 | public TPartialOcclusionTile(BlockPos pos, BlockState state) { 34 | super(pos, state); 35 | } 36 | 37 | @Override 38 | public void markShapeChange() { 39 | super.markShapeChange(); 40 | // Invalidate cached results on part add, remove, or shape change 41 | lastTestParts = null; 42 | lastTestShape = null; 43 | } 44 | 45 | @Override 46 | public boolean occlusionTest(Iterable parts, MultiPart npart) { 47 | if (npart instanceof PartialOcclusionPart newPart) { 48 | VoxelShape newShape = newPart.getPartialOcclusionShape(); 49 | if (!getLevel().isClientSide() || lastTestParts != parts || lastTestShape != newShape) { 50 | lastTestParts = parts; 51 | lastTestShape = newShape; 52 | lastTestResult = partialOcclusionTest(parts, newPart); 53 | } 54 | if (!lastTestResult) { 55 | return false; 56 | } 57 | } 58 | 59 | return super.occlusionTest(parts, npart); 60 | } 61 | 62 | private static boolean partialOcclusionTest(Iterable allParts, PartialOcclusionPart newPart) { 63 | List parts = new LinkedList<>(); 64 | for (MultiPart part : allParts) { 65 | if (part instanceof PartialOcclusionPart) { 66 | parts.add((PartialOcclusionPart) part); 67 | } 68 | } 69 | parts.add(newPart); 70 | 71 | for (PartialOcclusionPart part1 : parts) { 72 | if (part1.allowCompleteOcclusion()) { 73 | continue; 74 | } 75 | VoxelShape uniqueShape = part1.getPartialOcclusionShape(); 76 | for (PartialOcclusionPart part2 : parts) { 77 | if (part1 != part2) { 78 | uniqueShape = Shapes.join(uniqueShape, part2.getPartialOcclusionShape(), BooleanOp.ONLY_FIRST); 79 | } 80 | } 81 | if (uniqueShape.isEmpty()) { 82 | return false; 83 | } 84 | } 85 | 86 | return true; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TRedstoneTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.EdgePart; 4 | import codechicken.multipart.api.part.FacePart; 5 | import codechicken.multipart.api.part.MultiPart; 6 | import codechicken.multipart.api.part.redstone.RedstonePart; 7 | import codechicken.multipart.block.TileMultipart; 8 | import codechicken.multipart.trait.extern.RedstoneTile; 9 | import net.minecraft.core.BlockPos; 10 | import net.minecraft.world.level.block.state.BlockState; 11 | 12 | import static codechicken.lib.vec.Rotation.rotateSide; 13 | import static codechicken.multipart.api.RedstoneInteractions.connectionMask; 14 | import static codechicken.multipart.api.RedstoneInteractions.otherConnectionMask; 15 | import static codechicken.multipart.util.PartMap.edgeBetween; 16 | 17 | /** 18 | * Created by covers1624 on 31/12/20. 19 | */ 20 | public class TRedstoneTile extends TileMultipart implements RedstoneTile { 21 | 22 | public TRedstoneTile(BlockPos pos, BlockState state) { 23 | super(pos, state); 24 | } 25 | 26 | @Override 27 | public int getDirectSignal(int side) { 28 | int max = 0; 29 | for (MultiPart part : getPartList()) { 30 | if (part instanceof RedstonePart) { 31 | int l = ((RedstonePart) part).strongPowerLevel(side); 32 | if (l > max) { 33 | max = l; 34 | } 35 | } 36 | } 37 | return max; 38 | } 39 | 40 | @Override 41 | public int getSignal(int side) { 42 | return weakPowerLevel(side, otherConnectionMask(getLevel(), getBlockPos(), side, true)); 43 | } 44 | 45 | @Override 46 | public boolean canConnectRedstone(int side) { 47 | return (getConnectionMask(side) & otherConnectionMask(getLevel(), getBlockPos(), side, true)) > 0; 48 | } 49 | 50 | @Override 51 | public int getConnectionMask(int side) { 52 | int mask = openConnections(side); 53 | int res = 0; 54 | for (MultiPart part : getPartList()) { 55 | res |= connectionMask(part, side) & mask; 56 | } 57 | return res; 58 | } 59 | 60 | @Override 61 | public int weakPowerLevel(int side, int mask) { 62 | int tMask = openConnections(side) & mask; 63 | int max = 0; 64 | for (MultiPart part : getPartList()) { 65 | if ((connectionMask(part, side) & tMask) > 0) { 66 | int l = ((RedstonePart) part).weakPowerLevel(side); 67 | if (l > max) { 68 | max = l; 69 | } 70 | } 71 | } 72 | return max; 73 | } 74 | 75 | @Override 76 | public int openConnections(int side) { 77 | int m = 0x10; 78 | 79 | for (int i = 0; i < 4; i++) { 80 | if (redstoneConductionE(edgeBetween(side, rotateSide(side & 6, i)))) { 81 | m |= 1 << i; 82 | } 83 | } 84 | 85 | m &= redstoneConductionF(side); 86 | return m; 87 | } 88 | 89 | private int redstoneConductionF(int i) { 90 | MultiPart part = getSlottedPart(i); 91 | if (part instanceof FacePart) { 92 | return ((FacePart) part).redstoneConductionMap(); 93 | } 94 | return 0x1F; 95 | } 96 | 97 | private boolean redstoneConductionE(int i) { 98 | MultiPart part = getSlottedPart(i); 99 | if (part instanceof EdgePart) { 100 | return ((EdgePart) part).conductsRedstone(); 101 | } 102 | return true; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TSlottedTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.api.part.SlottedPart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.world.level.block.state.BlockState; 8 | 9 | import java.util.Arrays; 10 | 11 | /** 12 | * Created by covers1624 on 1/1/21. 13 | */ 14 | public class TSlottedTile extends TileMultipart { 15 | 16 | private MultiPart[] v_partMap = new MultiPart[27]; 17 | 18 | public TSlottedTile(BlockPos pos, BlockState state) { 19 | super(pos, state); 20 | } 21 | 22 | @Override 23 | public void copyFrom(TileMultipart that) { 24 | super.copyFrom(that); 25 | if (that instanceof TSlottedTile) { 26 | v_partMap = ((TSlottedTile) that).v_partMap; 27 | } 28 | } 29 | 30 | @Override 31 | public void clearParts() { 32 | super.clearParts(); 33 | Arrays.fill(v_partMap, null); 34 | } 35 | 36 | @Override 37 | public MultiPart getSlottedPart(int slot) { 38 | return v_partMap[slot]; 39 | } 40 | 41 | @Override 42 | public void partRemoved(MultiPart part, int p) { 43 | super.partRemoved(part, p); 44 | if (part instanceof SlottedPart) { 45 | for (int i = 0; i < v_partMap.length; i++) { 46 | if (v_partMap[i] == part) { 47 | v_partMap[i] = null; 48 | } 49 | } 50 | } 51 | } 52 | 53 | @Override 54 | public boolean canAddPart(MultiPart part) { 55 | if (part instanceof SlottedPart) { 56 | int mask = ((SlottedPart) part).getSlotMask(); 57 | for (int i = 0; i < v_partMap.length; i++) { 58 | if ((mask & 1 << i) != 0 && getSlottedPart(i) != null) { 59 | return false; 60 | } 61 | } 62 | } 63 | 64 | return super.canAddPart(part); 65 | } 66 | 67 | @Override 68 | public void bindPart(MultiPart part) { 69 | super.bindPart(part); 70 | if (part instanceof SlottedPart) { 71 | int mask = ((SlottedPart) part).getSlotMask(); 72 | for (int i = 0; i < v_partMap.length; i++) { 73 | if ((mask & 1 << i) > 0) { 74 | v_partMap[i] = part; 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TTickableTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.TickablePart; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import codechicken.multipart.api.TickableTile; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by covers1624 on 18/9/20. 15 | */ 16 | public class TTickableTile extends TileMultipart implements TickableTile { 17 | 18 | private final List tickingParts = new ArrayList<>(); 19 | 20 | public TTickableTile(BlockPos pos, BlockState state) { 21 | super(pos, state); 22 | } 23 | 24 | @Override 25 | public void copyFrom(TileMultipart that) { 26 | super.copyFrom(that); 27 | if (that instanceof TTickableTile) { 28 | tickingParts.clear(); 29 | tickingParts.addAll(((TTickableTile) that).tickingParts); 30 | } 31 | } 32 | 33 | @Override 34 | public void bindPart(MultiPart part) { 35 | super.bindPart(part); 36 | if (part instanceof TickablePart p) { 37 | tickingParts.add(p); 38 | } 39 | } 40 | 41 | @Override 42 | public void partRemoved(MultiPart part, int p) { 43 | super.partRemoved(part, p); 44 | if (part instanceof TickablePart) { 45 | tickingParts.remove(part); 46 | } 47 | } 48 | 49 | @Override 50 | public void clearParts() { 51 | super.clearParts(); 52 | tickingParts.clear(); 53 | } 54 | 55 | @Override 56 | public void tick() { 57 | for (int i = 0, tickingPartsSize = tickingParts.size(); i < tickingPartsSize; i++) { 58 | TickablePart part = tickingParts.get(i); 59 | if (((MultiPart) part).tile() != null) { 60 | part.tick(); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TTileChangeTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.lib.math.MathHelper; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.api.part.NeighborTileChangePart; 6 | import codechicken.multipart.block.TileMultipart; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.Direction; 9 | import net.minecraft.world.level.block.state.BlockState; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Created by covers1624 on 23/9/20. 15 | */ 16 | public class TTileChangeTile extends TileMultipart { 17 | 18 | private boolean weakTileChanges = false; 19 | 20 | public TTileChangeTile(BlockPos pos, BlockState state) { 21 | super(pos, state); 22 | } 23 | 24 | @Override 25 | public void copyFrom(TileMultipart that) { 26 | super.copyFrom(that); 27 | if (that instanceof TTileChangeTile) { 28 | weakTileChanges = ((TTileChangeTile) that).weakTileChanges; 29 | } 30 | } 31 | 32 | @Override 33 | public void bindPart(MultiPart part) { 34 | super.bindPart(part); 35 | if (part instanceof NeighborTileChangePart) { 36 | weakTileChanges |= ((NeighborTileChangePart) part).weakTileChanges(); 37 | } 38 | } 39 | 40 | @Override 41 | public void partRemoved(MultiPart part, int p) { 42 | super.partRemoved(part, p); 43 | weakTileChanges = getPartList().stream() 44 | .anyMatch(e -> e instanceof NeighborTileChangePart && ((NeighborTileChangePart) e).weakTileChanges()); 45 | } 46 | 47 | @Override 48 | public boolean getWeakChanges() { 49 | return super.getWeakChanges() || weakTileChanges; 50 | } 51 | 52 | @Override 53 | public void onNeighborTileChange(BlockPos neighborPos) { 54 | super.onNeighborTileChange(neighborPos); 55 | 56 | BlockPos offset = neighborPos.subtract(getBlockPos()); 57 | int diff = MathHelper.absSum(offset); 58 | Direction side = MathHelper.getSide(offset); 59 | 60 | if (side == null || diff <= 0 || diff > 2) { 61 | return; 62 | } 63 | boolean weak = diff == 2; 64 | List jPartList = getPartList(); 65 | for (MultiPart part : jPartList) { 66 | if (part instanceof NeighborTileChangePart) { 67 | ((NeighborTileChangePart) part).onNeighborTileChanged(side, weak); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/TileMultipartClient.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait; 2 | 3 | import codechicken.multipart.api.part.MultiPart; 4 | import codechicken.multipart.block.TileMultipart; 5 | import codechicken.multipart.client.MultipartModelData; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.client.multiplayer.ClientLevel; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.world.level.block.state.BlockState; 10 | import net.neoforged.neoforge.client.model.data.ModelData; 11 | 12 | import java.util.HashMap; 13 | import java.util.IdentityHashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * Manual trait implemented on every client side TileMultiPart. 18 | */ 19 | public class TileMultipartClient extends TileMultipart { 20 | 21 | public TileMultipartClient(BlockPos pos, BlockState state) { 22 | super(pos, state); 23 | } 24 | 25 | @Override 26 | public boolean isClientTile() { 27 | return true; 28 | } 29 | 30 | @Override 31 | public void markRender() { 32 | if (getLevel() instanceof ClientLevel) { 33 | requestModelDataUpdate(); 34 | BlockPos pos = getBlockPos(); 35 | Minecraft.getInstance().levelRenderer.setBlocksDirty(pos.getX(), pos.getY(), pos.getZ(), pos.getX(), pos.getY(), pos.getZ()); 36 | } 37 | } 38 | 39 | @Override 40 | public ModelData getModelData() { 41 | IdentityHashMap partData = new IdentityHashMap<>(); 42 | for (MultiPart part : getPartList()) { 43 | ModelData data = part.getModelData(); 44 | if (data != ModelData.EMPTY) { 45 | partData.put(part, data); 46 | } 47 | } 48 | return ModelData.of( 49 | MultipartModelData.DATA, 50 | new MultipartModelData( 51 | tile(), 52 | partData 53 | ) 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/extern/RedstoneTile.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.trait.extern; 2 | 3 | import codechicken.multipart.api.part.redstone.RedstonePart; 4 | import codechicken.multipart.api.tile.RedstoneConnector; 5 | import codechicken.multipart.block.TileMultipart; 6 | 7 | /** 8 | * Internal interface for {@link TileMultipart} instances hosting {@link RedstonePart}s 9 | */ 10 | public interface RedstoneTile extends RedstoneConnector { 11 | 12 | /** 13 | * Returns the mask of spaces through which a wire could connect on a side. 14 | * 15 | * @param side The side index. 16 | * @return The mask. 17 | */ 18 | int openConnections(int side); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/extern/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.trait.extern; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/trait/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.trait; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/ControlKeyModifier.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | import net.minecraft.world.entity.player.Player; 4 | 5 | import java.util.WeakHashMap; 6 | 7 | /** 8 | * Created by covers1624 on 1/9/20. 9 | */ 10 | public class ControlKeyModifier { 11 | 12 | private static final WeakHashMap playerMap = new WeakHashMap<>(); 13 | 14 | public static void setIsControlDown(Player player, boolean bool) { 15 | playerMap.put(player, bool); 16 | } 17 | 18 | public static boolean isControlDown(Player player) { 19 | Boolean bool = playerMap.get(player); 20 | return bool != null && bool; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/ForgeMixinBackend.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | import codechicken.asm.ClassHierarchyManager; 4 | import codechicken.mixin.api.MixinBackend; 5 | import cpw.mods.modlauncher.TransformingClassLoader; 6 | import net.covers1624.quack.reflect.PrivateLookups; 7 | import net.neoforged.fml.loading.FMLEnvironment; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.lang.invoke.MethodHandle; 11 | import java.lang.invoke.MethodType; 12 | 13 | /** 14 | * Created by covers1624 on 2/11/20. 15 | */ 16 | public class ForgeMixinBackend extends MixinBackend.SimpleMixinBackend { 17 | 18 | private static final TransformingClassLoader cl = (TransformingClassLoader) Thread.currentThread().getContextClassLoader(); 19 | private static final MethodHandle m_buildTransformedClassNodeFor; 20 | 21 | static { 22 | try { 23 | m_buildTransformedClassNodeFor = PrivateLookups.getTrustedLookup() 24 | .findVirtual(TransformingClassLoader.class, "buildTransformedClassNodeFor", MethodType.methodType(byte[].class, String.class, String.class)); 25 | } catch (Throwable e) { 26 | throw new RuntimeException("Unable to retrieve methods via reflection.", e); 27 | } 28 | ClassHierarchyManager.addByteLookupFunc(cName -> getBytesForClass(cName, "computing_frames")); 29 | } 30 | 31 | public ForgeMixinBackend() { 32 | super(cl); 33 | } 34 | 35 | @Override 36 | public byte @Nullable [] getBytes(String name) { 37 | return getBytesForClass(name, "codechicken.multipart.util.ForgeMixinBackend"); 38 | } 39 | 40 | @Override 41 | public boolean filterMethodAnnotations(String annType, String value) { 42 | if (FMLEnvironment.dist == null) { 43 | return false; 44 | } 45 | String side = "net.minecraftforge.api.distmarker.Dist." + FMLEnvironment.dist.name(); 46 | return annType.equals("net.minecraftforge.api.distmarker.OnlyIn") && !value.equals(side); 47 | } 48 | 49 | private static byte @Nullable [] getBytesForClass(String cName, String reason) { 50 | String jName = cName.replace("/", "."); 51 | if (jName.equals("java.lang.Object")) return null; 52 | 53 | try { 54 | return (byte[]) m_buildTransformedClassNodeFor.invokeExact(cl, jName, reason); 55 | } catch (Throwable e) { 56 | throw new RuntimeException("Failed to get bytes for class '" + cName + "'.", e); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/MergedVoxelShapeHolder.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | import net.minecraft.world.phys.shapes.Shapes; 4 | import net.minecraft.world.phys.shapes.VoxelShape; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Collection; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | import java.util.function.Function; 11 | 12 | /** 13 | * Created by covers1624 on 3/10/20. 14 | */ 15 | public class MergedVoxelShapeHolder { 16 | 17 | private final Set shapeParts = new HashSet<>(); 18 | private final Set partCache = new HashSet<>(); 19 | 20 | private final Function postProcess; 21 | 22 | @Nullable 23 | private VoxelShape mergedShape; 24 | 25 | public MergedVoxelShapeHolder(Function postProcess) { 26 | this.postProcess = postProcess; 27 | } 28 | 29 | public void clear() { 30 | shapeParts.clear(); 31 | partCache.clear(); 32 | mergedShape = null; 33 | } 34 | 35 | public VoxelShape update(Collection things, Function extractor) { 36 | synchronized (partCache) { 37 | partCache.clear(); 38 | for (T thing : things) { 39 | partCache.add(extractor.apply(thing)); 40 | } 41 | 42 | if (!partCache.equals(shapeParts) || mergedShape == null) { 43 | shapeParts.clear(); 44 | shapeParts.addAll(partCache); 45 | 46 | //Same as VoxelShapes.or(VoxelShapes.empty(), shapeParts.toArray()); Except we skip useless array creation. 47 | VoxelShape merged = shapeParts.stream().reduce(Shapes.empty(), Shapes::or); 48 | mergedShape = postProcess.apply(merged); 49 | } 50 | } 51 | 52 | return mergedShape; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/MultipartPlaceContext.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | import codechicken.lib.vec.Rotation; 4 | import codechicken.lib.vec.Vector3; 5 | import codechicken.multipart.api.part.MultiPart; 6 | import codechicken.multipart.block.TileMultipart; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.Direction; 9 | import net.minecraft.world.InteractionHand; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.item.context.BlockPlaceContext; 12 | import net.minecraft.world.item.context.UseOnContext; 13 | import net.minecraft.world.phys.BlockHitResult; 14 | import net.minecraft.world.phys.Vec3; 15 | import org.jetbrains.annotations.Contract; 16 | 17 | import java.util.Objects; 18 | 19 | public class MultipartPlaceContext extends BlockPlaceContext { 20 | 21 | private final double hitDepth; 22 | private final BlockPos offsetPos; 23 | 24 | private boolean isOffset = false; 25 | 26 | public MultipartPlaceContext(UseOnContext context) { 27 | this(Objects.requireNonNull(context.getPlayer()), context.getHand(), context.getHitResult()); 28 | } 29 | 30 | public MultipartPlaceContext(Player player, InteractionHand hand, BlockHitResult hit) { 31 | super(player, hand, player.getItemInHand(hand), hit); 32 | 33 | this.hitDepth = calcHitDepth(hit.getLocation(), hit.getBlockPos(), hit.getDirection()); 34 | this.offsetPos = hit.getBlockPos().relative(hit.getDirection()); 35 | } 36 | 37 | /** 38 | * Puts this placement into offset mode 39 | * 40 | * @return this 41 | */ 42 | @Contract("-> this") 43 | public MultipartPlaceContext applyOffset() { 44 | isOffset = true; 45 | return this; 46 | } 47 | 48 | /** 49 | * Distance from the clicked face to that same face of the enclosing block space. 50 | */ 51 | public double getHitDepth() { 52 | return hitDepth; 53 | } 54 | 55 | /** 56 | * False when placement is being run inside the clicked block, true when it is offset by one block. 57 | */ 58 | public boolean isOffset() { 59 | return isOffset; 60 | } 61 | 62 | /** 63 | * Checks if part can be added to the world. Useful for cases where your part can optionally be altered 64 | * if its initially calculated placement state cannot be placed. 65 | *

66 | * For example, Lever parts are rectangular with a long and short side. Occlusion may allow placement in 67 | * one orientation but not another. The initial placement state can be run through this method, and then 68 | * rotated if placement is not possible. 69 | *

70 | * Note that this method does not need to be used if conditional placement states are not required. This is 71 | * explicitly re-checked once you return your candidate part. 72 | * 73 | * @param part The part to test 74 | * @return True if placement is possible (either the space is empty, or occlusion allows placement) 75 | */ 76 | public boolean canPlacePart(MultiPart part) { 77 | return TileMultipart.canPlacePart(this, part); 78 | } 79 | 80 | @Override 81 | public BlockPos getClickedPos() { 82 | return isOffset ? offsetPos : getHitResult().getBlockPos(); 83 | } 84 | 85 | private double calcHitDepth(Vec3 clickLocation, BlockPos clickPos, Direction face) { 86 | Vector3 vHit = new Vector3(clickLocation).subtract(clickPos); 87 | int side = face.ordinal(); 88 | return vHit.scalarProject(Rotation.axes[side]) + (side % 2 ^ 1); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/MultipartVoxelShape.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | import codechicken.lib.raytracer.SubHitBlockHitResult; 4 | import codechicken.multipart.api.part.MultiPart; 5 | import codechicken.multipart.block.TileMultipart; 6 | import it.unimi.dsi.fastutil.doubles.DoubleList; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.Direction; 9 | import net.minecraft.world.phys.BlockHitResult; 10 | import net.minecraft.world.phys.Vec3; 11 | import net.minecraft.world.phys.shapes.CollisionContext; 12 | import net.minecraft.world.phys.shapes.VoxelShape; 13 | 14 | /** 15 | * Created by covers1624 on 3/9/20. 16 | */ 17 | public class MultipartVoxelShape extends VoxelShape { 18 | 19 | private final VoxelShape shape; 20 | private final TileMultipart tile; 21 | 22 | public MultipartVoxelShape(VoxelShape shape, TileMultipart tile) { 23 | super(shape.shape); 24 | this.shape = shape; 25 | this.tile = tile; 26 | } 27 | 28 | @Override 29 | public DoubleList getCoords(Direction.Axis axis) { 30 | return shape.getCoords(axis); 31 | } 32 | 33 | @Override 34 | public BlockHitResult clip(Vec3 start, Vec3 end, BlockPos pos) { 35 | 36 | PartRayTraceResult closest = null; 37 | for (MultiPart part : tile.getPartList()) { 38 | BlockHitResult hit = part.getInteractionShape().clip(start, end, pos); 39 | if (hit == null) { 40 | hit = part.getShape(CollisionContext.empty()).clip(start, end, pos); 41 | } 42 | if (hit == null) continue; 43 | 44 | PartRayTraceResult result; 45 | if (hit instanceof SubHitBlockHitResult sHit) { 46 | result = new PartRayTraceResult(part, sHit); 47 | } else { 48 | result = new PartRayTraceResult(part, hit, start); 49 | } 50 | if (closest == null || result.compareTo(closest) < 0) { 51 | closest = result; 52 | } 53 | } 54 | return closest; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/PartMap.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | /** 4 | * Defines what each slot in a multipart tile corresponds to and provides some utility functions. 5 | * For performance reasons, it is recommended that integer constants be used as opposed to this enum 6 | */ 7 | public enum PartMap { 8 | BOTTOM(0), 9 | TOP(1), 10 | NORTH(2), 11 | SOUTH(3), 12 | WEST(4), 13 | EAST(5), 14 | CENTER(6), 15 | CORNER_NNN(7), //0 16 | CORNER_NPN(8), //1 17 | CORNER_NNP(9), //2 18 | CORNER_NPP(10),//3 19 | CORNER_PNN(11),//4 20 | CORNER_PPN(12),//5 21 | CORNER_PNP(13),//6 22 | CORNER_PPP(14),//7 23 | EDGE_NYN(15), //0 24 | EDGE_NYP(16), //1 25 | EDGE_PYN(17), //2 26 | EDGE_PYP(18), //3 27 | EDGE_NNZ(19), //4 28 | EDGE_PNZ(20), //5 29 | EDGE_NPZ(21), //6 30 | EDGE_PPZ(22), //7 31 | EDGE_XNN(23), //8 32 | EDGE_XPN(24), //9 33 | EDGE_XNP(25), //10 34 | EDGE_XPP(26); //11 35 | 36 | private static final int[] edgeBetweenMap = new int[] { -1, -1, 8, 10, 4, 5, -1, -1, 9, 11, 6, 7, -1, -1, -1, -1, 0, 2, -1, -1, -1, -1, 1, 3 }; 37 | 38 | public final int i; 39 | public final int mask; 40 | 41 | PartMap(int i) { 42 | this.i = i; 43 | mask = 1 << i; 44 | } 45 | 46 | /** 47 | * Don't actually use this. 48 | */ 49 | public static PartMap face(int i) { 50 | return values()[i]; 51 | } 52 | 53 | /** 54 | * Don't actually use this. 55 | */ 56 | public static PartMap edge(int i) { 57 | return values()[i + 15]; 58 | } 59 | 60 | /** 61 | * Don't actually use this. 62 | */ 63 | public static PartMap corner(int i) { 64 | return values()[i + 7]; 65 | } 66 | 67 | /** 68 | * Returns a 3 bit mask of the axis xzy that are variable in this edge. 69 | * For example, the first 4 edges (15-18) are along the Y axis, variable in x and z, so the mask is 110b. Note axis y is 1<<0, z is 1<<1 and x is 1<<2 70 | * Note the parameter e is relative to the first edge slot and can range from 0-11 71 | */ 72 | public static int edgeAxisMask(int e) { 73 | switch (e >> 2) { 74 | case 0: 75 | return 6; 76 | case 1: 77 | return 5; 78 | case 2: 79 | return 3; 80 | } 81 | throw new IllegalArgumentException("Switch Falloff"); 82 | } 83 | 84 | /** 85 | * Unpacks an edge index, to a mask where high values indicate positive positions in that axis. 86 | * Note the parameter e is relative to the first edge slot and can range from 0-11 87 | * For example, edge 1 (slot 16), is EDGE_NYP so the mask returned would be 010 as z is positive. 88 | */ 89 | public static int unpackEdgeBits(int e) { 90 | switch (e >> 2) { 91 | case 0: 92 | return (e & 3) << 1; 93 | case 1: 94 | return (e & 2) >> 1 | (e & 1) << 2; 95 | case 2: 96 | return (e & 3); 97 | } 98 | throw new IllegalArgumentException("Switch Falloff"); 99 | } 100 | 101 | /** 102 | * Repacks a mask of axis bits indicating positive positions, into an edge in along the same axis as e. 103 | * Note the parameter e is relative to the first edge slot and can range from 0-11 104 | */ 105 | public static int packEdgeBits(int e, int bits) { 106 | switch (e >> 2) { 107 | case 0: 108 | return e & 0xC | bits >> 1; 109 | case 1: 110 | return e & 0xC | (bits & 4) >> 2 | (bits & 1) << 1; 111 | case 2: 112 | return e & 0xC | bits & 3; 113 | } 114 | throw new IllegalArgumentException("Switch Falloff"); 115 | } 116 | 117 | /** 118 | * Returns the slot of the edge between 2 sides. 119 | */ 120 | public static int edgeBetween(int s1, int s2) { 121 | if (s2 < s1) { 122 | return edgeBetween(s2, s1); 123 | } 124 | if ((s1 & 6) == (s2 & 6)) { 125 | throw new IllegalArgumentException("Faces " + s1 + " and " + s2 + " are opposites"); 126 | } 127 | return 15 + edgeBetweenMap[s1 * 6 + s2]; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/PartRayTraceResult.java: -------------------------------------------------------------------------------- 1 | package codechicken.multipart.util; 2 | 3 | import codechicken.lib.raytracer.SubHitBlockHitResult; 4 | import codechicken.lib.vec.Vector3; 5 | import codechicken.multipart.api.part.MultiPart; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.core.Direction; 8 | import net.minecraft.world.phys.BlockHitResult; 9 | import net.minecraft.world.phys.Vec3; 10 | 11 | /** 12 | * Created by covers1624 on 2/9/20. 13 | */ 14 | public class PartRayTraceResult extends SubHitBlockHitResult { 15 | 16 | public final MultiPart part; 17 | 18 | public PartRayTraceResult(MultiPart part, BlockHitResult hit, Vec3 start) { 19 | this(part, new Vector3(hit.getLocation()), hit.getDirection(), hit.getBlockPos(), hit.isInside(), null, hit.getLocation().distanceToSqr(start)); 20 | } 21 | 22 | public PartRayTraceResult(MultiPart part, SubHitBlockHitResult hit) { 23 | this(part, new Vector3(hit.getLocation()), hit.getDirection(), hit.getBlockPos(), hit.isInside(), hit.hitInfo, hit.dist); 24 | } 25 | 26 | public PartRayTraceResult(MultiPart part, Vector3 hitVec, Direction faceIn, BlockPos posIn, boolean isInside, Object data, double dist) { 27 | super(hitVec, faceIn, posIn, isInside, data, dist); 28 | this.part = part; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/codechicken/multipart/util/package-info.java: -------------------------------------------------------------------------------- 1 | @FieldsAreNonnullByDefault 2 | @MethodsReturnNonnullByDefault 3 | @ParametersAreNonnullByDefault 4 | package codechicken.multipart.util; 5 | 6 | import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; 7 | import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; 8 | 9 | import javax.annotation.ParametersAreNonnullByDefault; 10 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | COMMENT: This file exists purely for dev time, 2 | anything added here should be mirrored in the build.gradle. 3 | MixinConfigs: mixins.cbmultipart.json 4 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/accesstransformer.cfg: -------------------------------------------------------------------------------- 1 | # CBMultipart Access Transformer 2 | public net.minecraft.world.level.lighting.LevelLightEngine blockEngine 3 | public net.minecraft.world.level.lighting.LevelLightEngine skyEngine 4 | public net.minecraft.world.item.context.UseOnContext getHitResult()Lnet/minecraft/world/phys/BlockHitResult; 5 | public net.minecraft.world.level.chunk.LevelChunk loaded 6 | 7 | public net.minecraft.world.level.block.FaceAttachedHorizontalDirectionalBlock getConnectedDirection(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/core/Direction; 8 | public net.minecraft.world.level.block.LeverBlock makeParticle(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;F)V 9 | public net.minecraft.world.level.block.ButtonBlock ticksToStayPressed 10 | public net.minecraft.world.level.block.ButtonBlock type 11 | public net.minecraft.world.level.block.ButtonBlock playSound(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Z)V 12 | 13 | public net.minecraft.world.level.chunk.LevelChunk updateBlockEntityTicker(Lnet/minecraft/world/level/block/entity/BlockEntity;)V 14 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="[2,)" 3 | issueTrackerURL="https://github.com/TheCBProject/ForgeMultipart" 4 | license="GNU Lesser General Public License v2.1" 5 | 6 | #CBMultipart 7 | [[mods]] 8 | modId="cb_multipart" 9 | displayName="CBMultipart" 10 | version="${file.jarVersion}" 11 | 12 | updateJSONURL="https://version-check.covers1624.net/check/?mod=CBMultipart&mc=${mc_version}" 13 | displayURL="https://github.com/TheCBProject/CBMultipart" 14 | authors="ChickenBones, covers1624" 15 | description="Open source library for facilitation of multiple functional parts in the one block space." 16 | 17 | [[dependencies.cb_multipart]] 18 | modId="neoforge" 19 | type="required" 20 | versionRange="[${forge_version},)" 21 | ordering="NONE" 22 | side="BOTH" 23 | [[dependencies.cb_multipart]] 24 | modId="minecraft" 25 | type="required" 26 | versionRange="[1.21.1]" 27 | ordering="NONE" 28 | side="BOTH" 29 | [[dependencies.cb_multipart]] 30 | modId="codechickenlib" 31 | type="required" 32 | versionRange="${ccl_version_range}" 33 | ordering="AFTER" 34 | side="BOTH" 35 | 36 | #CBMicroblocks 37 | [[mods]] 38 | modId="cb_microblock" 39 | displayName="CBMicroblock" 40 | version="${file.jarVersion}" 41 | 42 | displayURL="https://github.com/TheCBProject/CBMultipart" 43 | authors="ChickenBones, covers1624" 44 | description="Microblocks for CBMultipart." 45 | 46 | [[dependencies.cb_microblock]] 47 | modId="neoforge" 48 | type="required" 49 | versionRange="[${forge_version},)" 50 | ordering="NONE" 51 | side="BOTH" 52 | [[dependencies.cb_microblock]] 53 | modId="minecraft" 54 | type="required" 55 | versionRange="[1.21.1]" 56 | ordering="NONE" 57 | side="BOTH" 58 | [[dependencies.cb_microblock]] 59 | modId="codechickenlib" 60 | type="required" 61 | versionRange="${ccl_version_range}" 62 | ordering="AFTER" 63 | side="BOTH" 64 | [[dependencies.cb_microblock]] 65 | modId="cb_multipart" 66 | type="required" 67 | versionRange="[${file.jarVersion}]" 68 | ordering="AFTER" 69 | side="BOTH" 70 | 71 | #CBMultipartMinecraft 72 | [[mods]] 73 | modId="cb_multipart_minecraft" 74 | displayName="CBMultipart Minecraft" 75 | version="${file.jarVersion}" 76 | 77 | displayURL="https://github.com/TheCBProject/CBMultipart" 78 | authors="ChickenBones, covers1624" 79 | description="Provides multipart versions of some vanilla blocks like torches and buttons." 80 | 81 | [[dependencies.cb_multipart_minecraft]] 82 | modId="neoforge" 83 | type="required" 84 | versionRange="[${forge_version},)" 85 | ordering="NONE" 86 | side="BOTH" 87 | [[dependencies.cb_multipart_minecraft]] 88 | modId="minecraft" 89 | type="required" 90 | versionRange="[1.21.1]" 91 | ordering="NONE" 92 | side="BOTH" 93 | [[dependencies.cb_multipart_minecraft]] 94 | modId="codechickenlib" 95 | type="required" 96 | versionRange="${ccl_version_range}" 97 | ordering="AFTER" 98 | side="BOTH" 99 | [[dependencies.cb_multipart_minecraft]] 100 | modId="cb_multipart" 101 | type="required" 102 | versionRange="[${file.jarVersion}]" 103 | ordering="AFTER" 104 | side="BOTH" 105 | -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/cs_cz.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Kamenná pila", 4 | "item.cb_microblock.iron_saw": "Železná pila", 5 | "item.cb_microblock.diamond_saw": "Diamantová pila", 6 | "item.cb_microblock.stone_rod": "Kamenná tyč", 7 | "item.cb_microblock.face.1": "%s kryt", 8 | "item.cb_microblock.face.2": "%s panel", 9 | "item.cb_microblock.face.4": "%s deska", 10 | "item.cb_microblock.hollow.1": "Dutý %s kryt", 11 | "item.cb_microblock.hollow.2": "Dutý %s panel", 12 | "item.cb_microblock.hollow.4": "Dutá %s deska", 13 | "item.cb_microblock.edge.1": "%s pás", 14 | "item.cb_microblock.edge.2": "%s stojan", 15 | "item.cb_microblock.edge.4": "%s sloup", 16 | "item.cb_microblock.corner.1": "%s kout", 17 | "item.cb_microblock.corner.2": "%s roh", 18 | "item.cb_microblock.corner.4": "%s zářez" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/de_de.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Steinsäge", 4 | "item.cb_microblock.iron_saw": "Eisensäge", 5 | "item.cb_microblock.diamond_saw": "Diamantsäge", 6 | "item.cb_microblock.stone_rod": "Steinstab", 7 | "item.cb_microblock.face.1": "%s-Cover", 8 | "item.cb_microblock.face.2": "%s-Platte", 9 | "item.cb_microblock.face.4": "%s-Scheibe", 10 | "item.cb_microblock.hollow.1": "Hohles %s-Cover", 11 | "item.cb_microblock.hollow.2": "Hohles %s-Platte", 12 | "item.cb_microblock.hollow.4": "Hohle %s-Scheibe", 13 | "item.cb_microblock.edge.1": "%s-Streifen", 14 | "item.cb_microblock.edge.2": "%s-Pfosten", 15 | "item.cb_microblock.edge.4": "%s-Pfeiler", 16 | "item.cb_microblock.corner.1": "%s-Stückchen", 17 | "item.cb_microblock.corner.2": "%s-Ecke", 18 | "item.cb_microblock.corner.4": "%s-Kerbe" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Stone Saw", 4 | "item.cb_microblock.iron_saw": "Iron Saw", 5 | "item.cb_microblock.diamond_saw": "Diamond Saw", 6 | "item.cb_microblock.stone_rod": "Stone Rod", 7 | "item.cb_microblock.face.1": "%s Cover", 8 | "item.cb_microblock.face.2": "%s Panel", 9 | "item.cb_microblock.face.4": "%s Slab", 10 | "item.cb_microblock.hollow.1": "Hollow %s Cover", 11 | "item.cb_microblock.hollow.2": "Hollow %s Panel", 12 | "item.cb_microblock.hollow.4": "Hollow %s Slab", 13 | "item.cb_microblock.edge.1": "%s Strip", 14 | "item.cb_microblock.edge.2": "%s Post", 15 | "item.cb_microblock.edge.4": "%s Pillar", 16 | "item.cb_microblock.corner.1": "%s Nook", 17 | "item.cb_microblock.corner.2": "%s Corner", 18 | "item.cb_microblock.corner.4": "%s Notch" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/es_es.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Sierra de Piedra", 4 | "item.cb_microblock.iron_saw": "Sierra de Hierro", 5 | "item.cb_microblock.diamond_saw": "Sierra de Diamante", 6 | "item.cb_microblock.stone_rod": "Palo de Piedra", 7 | "item.cb_microblock.face.1": "Cubierta de %s", 8 | "item.cb_microblock.face.2": "Panel de %s", 9 | "item.cb_microblock.face.4": "Losa de %s", 10 | "item.cb_microblock.hollow.1": "Cubierta Hueca de %s", 11 | "item.cb_microblock.hollow.2": "Panel Hueco de %s", 12 | "item.cb_microblock.hollow.4": "Losa Hueca de %s", 13 | "item.cb_microblock.edge.1": "Listón de %s", 14 | "item.cb_microblock.edge.2": "Poste de %s", 15 | "item.cb_microblock.edge.4": "Pilar de %s", 16 | "item.cb_microblock.corner.1": "Punta de %s", 17 | "item.cb_microblock.corner.2": "Esquina de %s", 18 | "item.cb_microblock.corner.4": "Cuarto de %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/fr_ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Scie en pierre", 4 | "item.cb_microblock.iron_saw": "Scie en fer", 5 | "item.cb_microblock.diamond_saw": "Scie en diamant", 6 | "item.cb_microblock.stone_rod": "Bâton de pierre", 7 | "item.cb_microblock.face.1": "Couvercle de/d' %s", 8 | "item.cb_microblock.face.2": "Panneau de/d' %s", 9 | "item.cb_microblock.face.4": "Dalle de/d' %s", 10 | "item.cb_microblock.hollow.1": "Couvercle creux de/d' %s", 11 | "item.cb_microblock.hollow.2": "Panneau creux de/d' %s", 12 | "item.cb_microblock.hollow.4": "Dalle creuse de/d' %s", 13 | "item.cb_microblock.edge.1": "Bande de/d' %s", 14 | "item.cb_microblock.edge.2": "Poteau de/d' %s", 15 | "item.cb_microblock.edge.4": "Pilier de/d' %s", 16 | "item.cb_microblock.corner.1": "Recoin de/d' %s", 17 | "item.cb_microblock.corner.2": "Coin de/d' %s", 18 | "item.cb_microblock.corner.4": "Encoche de/d' %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/fr_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Scie en pierre", 4 | "item.cb_microblock.iron_saw": "Scie en fer", 5 | "item.cb_microblock.diamond_saw": "Scie en diamant", 6 | "item.cb_microblock.stone_rod": "Bâtons en pierre", 7 | "item.cb_microblock.face.1": "Couvercle de %s", 8 | "item.cb_microblock.face.2": "Panneau de %s", 9 | "item.cb_microblock.face.4": "Dalle de %s", 10 | "item.cb_microblock.hollow.1": "Couvercle creux de %s", 11 | "item.cb_microblock.hollow.2": "Panneau creux de %s", 12 | "item.cb_microblock.hollow.4": "Dalle creuse de %s", 13 | "item.cb_microblock.edge.1": "Bande de %s", 14 | "item.cb_microblock.edge.2": "Pieu de %s", 15 | "item.cb_microblock.edge.4": "Pilier de %s", 16 | "item.cb_microblock.corner.1": "Coin de %s", 17 | "item.cb_microblock.corner.2": "Bordure de %s", 18 | "item.cb_microblock.corner.4": "Entaille de %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/hr_hr.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Kamena Pila", 4 | "item.cb_microblock.iron_saw": "Željezna Pila", 5 | "item.cb_microblock.diamond_saw": "Dijamantna Pila", 6 | "item.cb_microblock.stone_rod": "Kameni Štap", 7 | "item.cb_microblock.face.1": "%si Pokrivač", 8 | "item.cb_microblock.face.2": "%si Panel", 9 | "item.cb_microblock.face.4": "%sa Ploča", 10 | "item.cb_microblock.hollow.1": "Izdubljen %si Pokrivač", 11 | "item.cb_microblock.hollow.2": "Izdubljen %si Panel", 12 | "item.cb_microblock.hollow.4": "Izdubljena %sa Ploča", 13 | "item.cb_microblock.edge.1": "%sa Pruga", 14 | "item.cb_microblock.edge.2": "%si Post", 15 | "item.cb_microblock.edge.4": "%si Stup", 16 | "item.cb_microblock.corner.1": "%si Kutak", 17 | "item.cb_microblock.corner.2": "%si Ugao", 18 | "item.cb_microblock.corner.4": "%si Usjek" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/it_it.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Seghetto di pietra", 4 | "item.cb_microblock.iron_saw": "Seghetto di ferro", 5 | "item.cb_microblock.diamond_saw": "Seghetto di diamante", 6 | "item.cb_microblock.stone_rod": "Stecca di pietra", 7 | "item.cb_microblock.face.1": "Copertura di %s", 8 | "item.cb_microblock.face.2": "Pannello di %s", 9 | "item.cb_microblock.face.4": "Lastra di %s", 10 | "item.cb_microblock.hollow.1": "Copertura cava di %s", 11 | "item.cb_microblock.hollow.2": "Pannello cavo di %s", 12 | "item.cb_microblock.hollow.4": "Lastra cava di %s", 13 | "item.cb_microblock.edge.1": "Striscia di %s", 14 | "item.cb_microblock.edge.2": "Palo di %s", 15 | "item.cb_microblock.edge.4": "Pilastro di %s", 16 | "item.cb_microblock.corner.1": "Angolino di %s", 17 | "item.cb_microblock.corner.2": "Angoletto di %s", 18 | "item.cb_microblock.corner.4": "Angolo di %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/ko_kr.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "돌 톱", 4 | "item.cb_microblock.iron_saw": "철 톱", 5 | "item.cb_microblock.diamond_saw": "다이아몬드 톱", 6 | "item.cb_microblock.stone_rod": "돌 막대", 7 | "item.cb_microblock.face.1": "%s 덮개", 8 | "item.cb_microblock.face.2": "%s 판", 9 | "item.cb_microblock.face.4": "%s 반블럭", 10 | "item.cb_microblock.hollow.1": "구멍 뚫린 %s 덮개", 11 | "item.cb_microblock.hollow.2": "구멍 뚫린 %s 판", 12 | "item.cb_microblock.hollow.4": "구멍 뚫린 %s 반블럭", 13 | "item.cb_microblock.edge.1": "%s 조각", 14 | "item.cb_microblock.edge.2": "%s 말뚝", 15 | "item.cb_microblock.edge.4": "%s 기둥", 16 | "item.cb_microblock.corner.1": "%s 녹", 17 | "item.cb_microblock.corner.2": "%s 코너", 18 | "item.cb_microblock.corner.4": "%s 노치" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/nl_nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Stenen Zaag", 4 | "item.cb_microblock.iron_saw": "IJzeren Zaag", 5 | "item.cb_microblock.diamond_saw": "Diamanten Zaag", 6 | "item.cb_microblock.stone_rod": "Stenen Stok", 7 | "item.cb_microblock.face.1": "%s Bedekking", 8 | "item.cb_microblock.face.2": "%s Paneel", 9 | "item.cb_microblock.face.4": "%s Plaat", 10 | "item.cb_microblock.hollow.1": "Holle %s Bedekking", 11 | "item.cb_microblock.hollow.2": "Hol %s Paneel", 12 | "item.cb_microblock.hollow.4": "Holle %s Plaat", 13 | "item.cb_microblock.edge.1": "%s Strook", 14 | "item.cb_microblock.edge.2": "%s Paal", 15 | "item.cb_microblock.edge.4": "%s Pilaar", 16 | "item.cb_microblock.corner.1": "%s Hoekje", 17 | "item.cb_microblock.corner.2": "%s Hoek", 18 | "item.cb_microblock.corner.4": "%s Inkeping" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/pl_pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Kamienna piła", 4 | "item.cb_microblock.iron_saw": "Żelazna piła", 5 | "item.cb_microblock.diamond_saw": "Diamentowa piła", 6 | "item.cb_microblock.stone_rod": "Kamienna Rod", 7 | "item.cb_microblock.face.1": "Pokrywka z %s", 8 | "item.cb_microblock.face.2": "Panel z %s", 9 | "item.cb_microblock.face.4": "Płyta z %s", 10 | "item.cb_microblock.hollow.1": "Pusta pokrywka z %s", 11 | "item.cb_microblock.hollow.2": "Pusty panel z %s", 12 | "item.cb_microblock.hollow.4": "Pusta płyta z %s", 13 | "item.cb_microblock.edge.1": "Pasek z %s", 14 | "item.cb_microblock.edge.2": "Słup z %s", 15 | "item.cb_microblock.edge.4": "Filar z %s", 16 | "item.cb_microblock.corner.1": "Kąt z %s", 17 | "item.cb_microblock.corner.2": "Róg z %s", 18 | "item.cb_microblock.corner.4": "Karb z %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/pt_br.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Serra de Pedra", 4 | "item.cb_microblock.iron_saw": "Serra de Ferro", 5 | "item.cb_microblock.diamond_saw": "Serra de Diamante", 6 | "item.cb_microblock.stone_rod": "Vara de Pedra", 7 | "item.cb_microblock.face.1": "Cobertura de %s", 8 | "item.cb_microblock.face.2": "Painel de %s", 9 | "item.cb_microblock.face.4": "Laje de %s", 10 | "item.cb_microblock.hollow.1": "Cobertura Furada %s", 11 | "item.cb_microblock.hollow.2": "Painel Furado de %s", 12 | "item.cb_microblock.hollow.4": "Laje Furada de %s", 13 | "item.cb_microblock.edge.1": "Tira de %s", 14 | "item.cb_microblock.edge.2": "Estaca de %s", 15 | "item.cb_microblock.edge.4": "Pilar de %s", 16 | "item.cb_microblock.corner.1": "Cantinho de %s", 17 | "item.cb_microblock.corner.2": "Canto de %s", 18 | "item.cb_microblock.corner.4": "Entalhe de %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Каменная пила", 4 | "item.cb_microblock.iron_saw": "Железная пила", 5 | "item.cb_microblock.diamond_saw": "Алмазная пила", 6 | "item.cb_microblock.stone_rod": "Каменная палка", 7 | "item.cb_microblock.face.1": "Крышка из %s", 8 | "item.cb_microblock.face.2": "Панель из %s", 9 | "item.cb_microblock.face.4": "Плита из %s", 10 | "item.cb_microblock.hollow.1": "Крышка из %s с выемкой", 11 | "item.cb_microblock.hollow.2": "Панель из %s с выемкой", 12 | "item.cb_microblock.hollow.4": "Плита из %s с выемкой", 13 | "item.cb_microblock.edge.1": "Полоса из %s", 14 | "item.cb_microblock.edge.2": "Столб %s", 15 | "item.cb_microblock.edge.4": "Колонна из %s", 16 | "item.cb_microblock.corner.1": "Уголок из %s", 17 | "item.cb_microblock.corner.2": "Угол из %s", 18 | "item.cb_microblock.corner.4": "Большой угол из %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/tr_tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "Taş Testere", 4 | "item.cb_microblock.iron_saw": "Demir Testere", 5 | "item.cb_microblock.diamond_saw": "Elmas Testere", 6 | "item.cb_microblock.stone_rod": "Taş Çubuk", 7 | "item.cb_microblock.face.1": "%s Kapak", 8 | "item.cb_microblock.face.2": "%s Panel", 9 | "item.cb_microblock.face.4": "Kalın %s", 10 | "item.cb_microblock.hollow.1": "Ortası Boş %s Kapak", 11 | "item.cb_microblock.hollow.2": "Ortası Boş %s Panel", 12 | "item.cb_microblock.hollow.4": "Ortası Boş Kalın %s", 13 | "item.cb_microblock.edge.1": "%s Şerit", 14 | "item.cb_microblock.edge.2": "Kalın Şerit %s", 15 | "item.cb_microblock.edge.4": "%s Sütun", 16 | "item.cb_microblock.corner.1": "%s Köşe", 17 | "item.cb_microblock.corner.2": "Orta Köşe %s", 18 | "item.cb_microblock.corner.4": "Kalın Köşe %s" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "石手锯", 4 | "item.cb_microblock.iron_saw": "铁手锯", 5 | "item.cb_microblock.diamond_saw": "钻石手锯", 6 | "item.cb_microblock.stone_rod": "石棍", 7 | "item.cb_microblock.face.1": "%s盖板", 8 | "item.cb_microblock.face.2": "%s面板", 9 | "item.cb_microblock.face.4": "%s台阶", 10 | "item.cb_microblock.hollow.1": "%s空心盖板", 11 | "item.cb_microblock.hollow.2": "%s空心面板", 12 | "item.cb_microblock.hollow.4": "%s空心台阶", 13 | "item.cb_microblock.edge.1": "%s条", 14 | "item.cb_microblock.edge.2": "%s柱", 15 | "item.cb_microblock.edge.4": "%s支柱", 16 | "item.cb_microblock.corner.1": "%s1/8角", 17 | "item.cb_microblock.corner.2": "%s1/4角", 18 | "item.cb_microblock.corner.4": "%s切口" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/lang/zh_tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemGroup.cb_microblock": "CB MicroBlocks", 3 | "item.cb_microblock.stone_saw": "石鋸子", 4 | "item.cb_microblock.iron_saw": "鐵鋸子", 5 | "item.cb_microblock.diamond_saw": "鑽石鋸子", 6 | "item.cb_microblock.stone_rod": "石棍", 7 | "item.cb_microblock.face.1": "%s 薄板", 8 | "item.cb_microblock.face.2": "%s 面板", 9 | "item.cb_microblock.face.4": "%s 厚板", 10 | "item.cb_microblock.hollow.1": "凹 %s 薄板", 11 | "item.cb_microblock.hollow.2": "凹 %s 面板", 12 | "item.cb_microblock.hollow.4": "凹 %s 厚板", 13 | "item.cb_microblock.edge.1": "%s 條", 14 | "item.cb_microblock.edge.2": "%s 柱", 15 | "item.cb_microblock.edge.4": "%s 支柱", 16 | "item.cb_microblock.corner.1": "%s 角", 17 | "item.cb_microblock.corner.2": "%s 棱角", 18 | "item.cb_microblock.corner.4": "%s 切口" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/textures/item/diamond_saw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CBMultipart/68e51552065a1517c17634f5044f468fd7635e64/src/main/resources/assets/cb_microblock/textures/item/diamond_saw.png -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/textures/item/iron_saw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CBMultipart/68e51552065a1517c17634f5044f468fd7635e64/src/main/resources/assets/cb_microblock/textures/item/iron_saw.png -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/textures/item/saw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CBMultipart/68e51552065a1517c17634f5044f468fd7635e64/src/main/resources/assets/cb_microblock/textures/item/saw.png -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/textures/item/stone_rod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CBMultipart/68e51552065a1517c17634f5044f468fd7635e64/src/main/resources/assets/cb_microblock/textures/item/stone_rod.png -------------------------------------------------------------------------------- /src/main/resources/assets/cb_microblock/textures/item/stone_saw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CBMultipart/68e51552065a1517c17634f5044f468fd7635e64/src/main/resources/assets/cb_microblock/textures/item/stone_saw.png -------------------------------------------------------------------------------- /src/main/resources/assets/cb_multipart/shaders/core/highlight.fsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | uniform sampler2D Sampler0; 4 | 5 | uniform vec4 ColorModulator; 6 | 7 | in vec4 vertexColor; 8 | in vec2 texCoord0; 9 | in vec2 texCoord2; 10 | in vec4 normal; 11 | 12 | out vec4 fragColor; 13 | 14 | void main() { 15 | vec4 color = texture(Sampler0, texCoord0) * vertexColor; 16 | fragColor = color * ColorModulator; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/assets/cb_multipart/shaders/core/highlight.json: -------------------------------------------------------------------------------- 1 | { 2 | "blend": { 3 | "func": "add", 4 | "srcrgb": "srcalpha", 5 | "dstrgb": "1-srcalpha" 6 | }, 7 | "vertex": "cb_multipart:highlight", 8 | "fragment": "cb_multipart:highlight", 9 | "attributes": [ 10 | "Position", 11 | "Color", 12 | "UV0", 13 | "UV2", 14 | "Normal" 15 | ], 16 | "samplers": [ 17 | { "name": "Sampler0" } 18 | ], 19 | "uniforms": [ 20 | { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, 21 | { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, 22 | { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/assets/cb_multipart/shaders/core/highlight.vsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 Position; 4 | in vec4 Color; 5 | in vec2 UV0; 6 | in vec2 UV2; 7 | in vec3 Normal; 8 | 9 | uniform mat4 ModelViewMat; 10 | uniform mat4 ProjMat; 11 | 12 | out vec4 vertexColor; 13 | out vec2 texCoord0; 14 | out vec2 texCoord2; 15 | out vec4 normal; 16 | 17 | void main() { 18 | gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); 19 | 20 | vertexColor = Color; 21 | texCoord0 = UV0; 22 | texCoord2 = UV2; 23 | normal = ProjMat * ModelViewMat * vec4(Normal, 0.0); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/mixins.cbmultipart.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "codechicken.multipart.internal.mixin", 5 | "refmap": "mixins.cbmultipart.refmap.json", 6 | "target": "@env(DEFAULT)", 7 | "compatibilityLevel": "JAVA_17", 8 | "mixins": [ 9 | "TileEntityMixin" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "pack_format": 4, 4 | "description": "CBMultipart resource pack" 5 | } 6 | } 7 | --------------------------------------------------------------------------------