├── .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 | [](https://www.curseforge.com/minecraft/mc-mods/cb-multipart)
4 | [](https://www.curseforge.com/minecraft/mc-mods/cb-multipart/files)
5 | [](https://discord.gg/9nr3qyC)
6 | [](https://nexus.covers1624.net/#browse/browse:maven-hosted:codechicken%2FCBMultipart)
7 | [](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 super T> type, PartRenderer super T> 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 extends TileMultipart> 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 extends TileMultipart> 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 extends TileMultipart> 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 |
--------------------------------------------------------------------------------