Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 402caaf549 | |||
| 42049047f7 | |||
| 4eddb32190 | |||
| ddffd45a44 | |||
| 53f962da1b | |||
| fcf02b68e6 | |||
| 5517d813e7 | |||
| b88a4abfe5 | |||
| ce650abc76 | |||
| 535fd6151e | |||
| 1061431af7 | |||
| 520430d5bc | |||
| 52fb6840ad | |||
| f6b403d852 | |||
| 5430016be4 | |||
| aa3cf6d511 | |||
| 15a8f80210 | |||
| cfdbfd3a6a | |||
| c49a978aa9 | |||
| 6b2ee1dc83 | |||
| 752ee956eb | |||
| d5369823d9 | |||
| c6f2244826 | |||
| 72c9c3511b | |||
| ac2f7def0c | |||
| fa44408836 | |||
| 78b8b6f607 | |||
| 6318fdece0 | |||
| 44f03b2c96 | |||
| c3e0ab16b7 | |||
| d8e4153754 | |||
| 572182e9f0 | |||
| 6f394bbe6f | |||
| b05c0ebd42 | |||
| 4309310c02 | |||
| 74a290fd16 | |||
| a430a8e62b | |||
| 3afee9e501 | |||
| 319d247e4c | |||
| f1af00738e | |||
| 3048f53878 | |||
| f222e4dc24 | |||
| 5c064176b2 | |||
| 186cca3e27 | |||
| 08bde119b2 | |||
| 6922dcc9d9 | |||
| b1ba784ee3 | |||
| c207fb5ae6 | |||
| 5fcb983592 | |||
| bd412bfccd | |||
| 96f08bdd3e | |||
| 394c75f9ed | |||
| e6c9ee63cd | |||
| 239802ce7b | |||
| 5f87489939 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ local.properties
|
|||||||
*-autosave.kra
|
*-autosave.kra
|
||||||
*.kra~
|
*.kra~
|
||||||
/src/generated/
|
/src/generated/
|
||||||
|
/libs/
|
||||||
|
|||||||
16
LICENSE
16
LICENSE
@@ -1,15 +1 @@
|
|||||||
Copyright (c) 2019 B0undarybreaker (Meredith Espinosa)
|
MIT AND LGPL-3.0
|
||||||
Copyright (c) 2024 Adrien1106
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
165
LICENSE.LGPL-3.0
Normal file
165
LICENSE.LGPL-3.0
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
15
LICENSE.MIT
Normal file
15
LICENSE.MIT
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
Copyright (c) 2019 B0undarybreaker (Meredith Espinosa)\
|
||||||
|
Copyright (c) 2024 Adrien1106
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
36
README.md
Normal file
36
README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# ReFramed
|
||||||
|
## Overview
|
||||||
|
This Project is an unofficial port of [FramedBlocks](https://github.com/XFactHD/FramedBlocks)
|
||||||
|
forked from [Templates 2](https://github.com/quat1024/templates-mod).
|
||||||
|
It aims to add the same mechanics as [FramedBlocks](https://github.com/XFactHD/FramedBlocks) into Fabric.
|
||||||
|
|
||||||
|
For a complete Feature list please have a look at the [Modrinth](https://modrinth.com/mod/reframed) page.
|
||||||
|
|
||||||
|
## Information
|
||||||
|
### Where to get it?
|
||||||
|
The mod can be downloaded on [Modrinth](https://modrinth.com/mod/reframed).
|
||||||
|
|
||||||
|
### Issues/requests
|
||||||
|
Any issues/requests may be addressed on this repository in the [Issues](https://github.com/DriHut/ReFramed/issues) section.
|
||||||
|
|
||||||
|
### Out of date?
|
||||||
|
I will be adding new shapes as time passes, but I am currently not planing on keeping up with the newer versions of the game.
|
||||||
|
That said this mod is under permissive licenses and make it easy for anyone to create their own fork.
|
||||||
|
If anyone in the future plans to do so, I will gladly either link it from here and the modrinth page,
|
||||||
|
or based on preferences add the person(s) to the project
|
||||||
|
|
||||||
|
### What Shapes are planed to be added
|
||||||
|
Currently, the list of shapes to be added is pretty simple as the mod is still under development:
|
||||||
|
- Pressure Plate
|
||||||
|
- Carpet (maybe redundant with Layer)
|
||||||
|
- Half Slab (maybe redundant with Layer)
|
||||||
|
- Slabs Stair (a stair with one end being of a second theme, might be done in multiple blocks)
|
||||||
|
|
||||||
|
Any Ideas feel free to make a suggestion [here](https://github.com/DriHut/ReFramed/issues).
|
||||||
|
|
||||||
|
## License
|
||||||
|
This work is dual-licensed under MIT and LGPL 3.0 both applying to different part of this project:
|
||||||
|
- The LGPL 3.0 license applies to all the textures that can be found in [`assets/reframed/textures`](src/main/resources/assets/reframed/textures)
|
||||||
|
- The MIT license applied to everything else so including all the code present within this project
|
||||||
|
|
||||||
|
`SPDX-License-Identifier: MIT AND LGPL-3.0`
|
||||||
23
build.gradle
23
build.gradle
@@ -4,7 +4,7 @@ import fr.altarik.CreateTag
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "com.modrinth.minotaur" version "2.+"
|
id "com.modrinth.minotaur" version "2.+"
|
||||||
id 'fabric-loom' version '1.5-SNAPSHOT'
|
id 'fabric-loom' version '1.6-SNAPSHOT'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +84,9 @@ repositories {
|
|||||||
includeGroup "maven.modrinth"
|
includeGroup "maven.modrinth"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url = "https://jitpack.io"
|
||||||
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
// Add repositories to retrieve artifacts from in here.
|
// Add repositories to retrieve artifacts from in here.
|
||||||
@@ -106,15 +109,23 @@ dependencies {
|
|||||||
// modRuntimeOnly "maven.modrinth:indium:${project.indium_version}+mc${project.minecraft_version}"
|
// modRuntimeOnly "maven.modrinth:indium:${project.indium_version}+mc${project.minecraft_version}"
|
||||||
// modRuntimeOnly "maven.modrinth:sodium:mc${project.minecraft_version}-${project.sodium_version}"
|
// modRuntimeOnly "maven.modrinth:sodium:mc${project.minecraft_version}-${project.sodium_version}"
|
||||||
|
|
||||||
// Athena for connected texture
|
// Athena for connected textures
|
||||||
modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
|
modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
|
||||||
modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
|
modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
|
||||||
|
|
||||||
|
// Continuity for connected textures
|
||||||
|
modCompileOnly "maven.modrinth:continuity:${project.continuity_version}"
|
||||||
|
modRuntimeOnly "maven.modrinth:continuity:${project.continuity_version}"
|
||||||
|
|
||||||
// Chipped to test athena implementation
|
// Chipped to test athena implementation
|
||||||
modRuntimeOnly "com.teamresourceful.resourcefullib:resourcefullib-fabric-${project.minecraft_version}:2.4.7"
|
modRuntimeOnly "com.teamresourceful.resourcefullib:resourcefullib-fabric-${project.minecraft_version}:2.4.7"
|
||||||
modRuntimeOnly "earth.terrarium.chipped:Chipped-fabric-${project.minecraft_version}:3.1.2"
|
modRuntimeOnly "earth.terrarium.chipped:Chipped-fabric-${project.minecraft_version}:3.1.2"
|
||||||
|
|
||||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
// Axiom for blueprint support
|
||||||
|
modCompileOnly "maven.modrinth:N6n5dqoA:YxeYxQyz"
|
||||||
|
modCompileOnly "com.github.moulberry:AxiomClientAPI:1.0.5.3"
|
||||||
|
|
||||||
|
// Fabric API.
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +137,7 @@ processResources {
|
|||||||
inputs.property "athena_version", project.athena_version
|
inputs.property "athena_version", project.athena_version
|
||||||
inputs.property "indium_version", project.indium_version
|
inputs.property "indium_version", project.indium_version
|
||||||
inputs.property "sodium_version", project.sodium_version
|
inputs.property "sodium_version", project.sodium_version
|
||||||
|
inputs.property "continuity_version", project.continuity_version
|
||||||
filteringCharset "UTF-8"
|
filteringCharset "UTF-8"
|
||||||
|
|
||||||
filesMatching("fabric.mod.json") {
|
filesMatching("fabric.mod.json") {
|
||||||
@@ -195,8 +207,8 @@ publishing {
|
|||||||
modrinth {
|
modrinth {
|
||||||
token = getEnv("MODRINTH_TOKEN", local.getProperty("modrinth_token"))
|
token = getEnv("MODRINTH_TOKEN", local.getProperty("modrinth_token"))
|
||||||
projectId = project.modrinth_id
|
projectId = project.modrinth_id
|
||||||
versionNumber = project.mod_version
|
versionNumber = "${project.mod_version}-${project.minecraft_version}"
|
||||||
versionName = "${project.archives_base_name} ${project.mod_version}"
|
versionName = "${project.archives_base_name} ${project.mod_version}-${project.minecraft_version}"
|
||||||
versionType = project.mod_version.endsWith('SNAPSHOT') ? 'beta' : 'release'
|
versionType = project.mod_version.endsWith('SNAPSHOT') ? 'beta' : 'release'
|
||||||
uploadFile = remapJar
|
uploadFile = remapJar
|
||||||
gameVersions = [project.minecraft_version]
|
gameVersions = [project.minecraft_version]
|
||||||
@@ -205,6 +217,7 @@ modrinth {
|
|||||||
required.project "fabric-api"
|
required.project "fabric-api"
|
||||||
optional.version "b1ZV3DIJ", "${project.athena_version}"
|
optional.version "b1ZV3DIJ", "${project.athena_version}"
|
||||||
optional.version "Orvt0mRa", "${project.indium_version}+mc${project.minecraft_version}"
|
optional.version "Orvt0mRa", "${project.indium_version}+mc${project.minecraft_version}"
|
||||||
|
optional.version "1IjD5062", "${project.continuity_version}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,18 +5,18 @@ org.gradle.jvmargs=-Xmx1G
|
|||||||
# check these on https://modmuss50.me/fabric.html
|
# check these on https://modmuss50.me/fabric.html
|
||||||
minecraft_version=1.20.4
|
minecraft_version=1.20.4
|
||||||
yarn_mappings=1.20.4+build.3
|
yarn_mappings=1.20.4+build.3
|
||||||
loader_version=0.15.6
|
loader_version=0.15.11
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
modrinth_id = jCpoCBpn
|
modrinth_id = jCpoCBpn
|
||||||
mod_version = 1.4
|
mod_version = 1.6.2
|
||||||
maven_group = fr.adrien1106
|
maven_group = fr.adrien1106
|
||||||
archives_base_name = ReFramed
|
archives_base_name = ReFramed
|
||||||
mod_id = reframed
|
mod_id = reframed
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
# check this on https://modmuss50.me/fabric.html
|
# check this on https://modmuss50.me/fabric.html
|
||||||
fabric_version=0.95.4+1.20.4
|
fabric_version=0.97.0+1.20.4
|
||||||
|
|
||||||
git_owner=Altarik
|
git_owner=Altarik
|
||||||
git_repo=ReFramed
|
git_repo=ReFramed
|
||||||
@@ -24,3 +24,4 @@ git_repo=ReFramed
|
|||||||
athena_version=3.3.0
|
athena_version=3.3.0
|
||||||
sodium_version=0.5.8
|
sodium_version=0.5.8
|
||||||
indium_version=1.0.30
|
indium_version=1.0.30
|
||||||
|
continuity_version=3.0.0-beta.4+1.20.2
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package fr.adrien1106.reframed;
|
package fr.adrien1106.reframed;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.*;
|
import fr.adrien1106.reframed.block.*;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.item.ReFramedHammerItem;
|
||||||
|
import fr.adrien1106.reframed.item.ReFramedBlueprintItem;
|
||||||
|
import fr.adrien1106.reframed.item.ReFramedBlueprintWrittenItem;
|
||||||
|
import fr.adrien1106.reframed.item.ReFramedScrewdriverItem;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||||
@@ -9,10 +12,7 @@ import net.minecraft.block.AbstractBlock;
|
|||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntityType;
|
import net.minecraft.block.entity.BlockEntityType;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.*;
|
||||||
import net.minecraft.item.Item;
|
|
||||||
import net.minecraft.item.ItemGroup;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.registry.Registries;
|
import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.registry.Registry;
|
import net.minecraft.registry.Registry;
|
||||||
import net.minecraft.sound.BlockSoundGroup;
|
import net.minecraft.sound.BlockSoundGroup;
|
||||||
@@ -23,16 +23,36 @@ import net.minecraft.world.World;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO self culling, fix other models, better connected textures, preload items, better cache
|
* TODO Dynamic Ambient Occlusion -> for v1.6
|
||||||
|
* TODO add minecraft models like wall fence etc -> for v1.6
|
||||||
|
* TODO better connected textures -> maybe v1.6 ?
|
||||||
|
* TODO support continuity overlays -> not scheduled
|
||||||
*/
|
*/
|
||||||
public class ReFramed implements ModInitializer {
|
public class ReFramed implements ModInitializer {
|
||||||
public static final String MODID = "reframed";
|
public static final String MODID = "reframed";
|
||||||
|
|
||||||
public static final ArrayList<Block> BLOCKS = new ArrayList<>();
|
public static final ArrayList<Block> BLOCKS = new ArrayList<>();
|
||||||
public static Block CUBE, STAIRS, DOUBLE_STAIRS, SLAB, DOUBLE_SLAB, STEP, DOUBLE_STEP;
|
public static Block
|
||||||
|
CUBE,
|
||||||
|
SMALL_CUBE, SMALL_CUBES_STEP,
|
||||||
|
STAIR, STAIRS_CUBE,
|
||||||
|
HALF_STAIR, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR,
|
||||||
|
SLAB, SLABS_CUBE,
|
||||||
|
STEP, STEPS_SLAB,
|
||||||
|
LAYER,
|
||||||
|
PILLAR, PILLARS_WALL, WALL,
|
||||||
|
PANE, TRAPDOOR, DOOR,
|
||||||
|
BUTTON,
|
||||||
|
POST, POST_FENCE, FENCE;
|
||||||
|
|
||||||
|
public static final ArrayList<Item> ITEMS = new ArrayList<>();
|
||||||
|
public static Item HAMMER, SCREWDRIVER, BLUEPRINT, BLUEPRINT_WRITTEN;
|
||||||
|
|
||||||
public static ItemGroup ITEM_GROUP;
|
public static ItemGroup ITEM_GROUP;
|
||||||
|
|
||||||
public static BlockEntityType<ReFramedEntity> REFRAMED_BLOCK_ENTITY;
|
public static BlockEntityType<ReFramedEntity> REFRAMED_BLOCK_ENTITY;
|
||||||
@@ -42,18 +62,34 @@ public class ReFramed implements ModInitializer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
//registerReFramed mutates FRAMES as a side effect, which is a List, so order is preserved
|
CUBE = registerBlock("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS)));
|
||||||
//the ordering is used in the creative tab, so they're roughly sorted by encounter order of the
|
SMALL_CUBE = registerBlock("small_cube" , new ReFramedSmallCubeBlock(cp(Blocks.OAK_PLANKS)));
|
||||||
//corresponding vanilla block in the "search" creative tab... with the non-vanilla "post" and
|
SMALL_CUBES_STEP = registerBlock("small_cubes_step" , new ReFramedSmallCubesStepBlock(cp(Blocks.OAK_PLANKS)));
|
||||||
//"vertical slab" inserted where they fit ...and i moved the lever way up next to the pressureplate
|
STAIR = registerBlock("stair" , new ReFramedStairBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
//and button, because they're redstoney... hopefully this ordering makes sense lol
|
STAIRS_CUBE = registerBlock("stairs_cube" , new ReFramedStairsCubeBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
CUBE = registerReFramed("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS)));
|
HALF_STAIR = registerBlock("half_stair" , new ReFramedHalfStairBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
STAIRS = registerReFramed("stairs" , new ReFramedStairsBlock(cp(Blocks.OAK_STAIRS)));
|
HALF_STAIRS_SLAB = registerBlock("half_stairs_slab" , new ReFramedHalfStairsSlabBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
DOUBLE_STAIRS = registerReFramed("double_stairs" , new ReFramedDoubleStairsBlock(cp(Blocks.OAK_STAIRS)));
|
HALF_STAIRS_STAIR = registerBlock("half_stairs_stair" , new ReFramedHalfStairsStairBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
SLAB = registerReFramed("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB)));
|
LAYER = registerBlock("layer" , new ReFramedLayerBlock(cp(Blocks.OAK_SLAB)));
|
||||||
DOUBLE_SLAB = registerReFramed("double_slab" , new ReFramedDoubleSlabBlock(cp(Blocks.OAK_SLAB)));
|
SLAB = registerBlock("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB)));
|
||||||
STEP = registerReFramed("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB)));
|
SLABS_CUBE = registerBlock("slabs_cube" , new ReFramedSlabsCubeBlock(cp(Blocks.OAK_SLAB)));
|
||||||
DOUBLE_STEP = registerReFramed("double_step" , new ReFramedDoubleStepBlock(cp(Blocks.OAK_SLAB)));
|
STEP = registerBlock("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB)));
|
||||||
|
STEPS_SLAB = registerBlock("steps_slab" , new ReFramedStepsSlabBlock(cp(Blocks.OAK_SLAB)));
|
||||||
|
PILLAR = registerBlock("pillar" , new ReFramedPillarBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
PILLARS_WALL = registerBlock("pillars_wall" , new ReFramedPillarsWallBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
WALL = registerBlock("wall" , new ReFramedWallBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
PANE = registerBlock("pane" , new ReFramedPaneBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
TRAPDOOR = registerBlock("trapdoor" , new ReFramedTrapdoorBlock(cp(Blocks.OAK_TRAPDOOR)));
|
||||||
|
DOOR = registerBlock("door" , new ReFramedDoorBlock(cp(Blocks.OAK_DOOR)));
|
||||||
|
BUTTON = registerBlock("button" , new ReFramedButtonBlock(cp(Blocks.OAK_BUTTON)));
|
||||||
|
POST = registerBlock("post" , new ReFramedPostBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
FENCE = registerBlock("fence" , new ReFramedFenceBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
POST_FENCE = registerBlock("post_fence" , new ReFramedPostFenceBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
|
||||||
|
HAMMER = registerItem("hammer" , new ReFramedHammerItem(new Item.Settings().maxCount(1)));
|
||||||
|
SCREWDRIVER = registerItem("screwdriver" , new ReFramedScrewdriverItem(new Item.Settings().maxCount(1)));
|
||||||
|
BLUEPRINT = registerItem("blueprint" , new ReFramedBlueprintItem(new Item.Settings()));
|
||||||
|
BLUEPRINT_WRITTEN = registerItem("blueprint_written" , new ReFramedBlueprintWrittenItem(new Item.Settings().maxCount(1)));
|
||||||
|
|
||||||
REFRAMED_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, id("camo"),
|
REFRAMED_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, id("camo"),
|
||||||
FabricBlockEntityTypeBuilder.create(
|
FabricBlockEntityTypeBuilder.create(
|
||||||
@@ -70,25 +106,37 @@ public class ReFramed implements ModInitializer {
|
|||||||
.filter(block -> block instanceof ReFramedDoubleBlock)
|
.filter(block -> block instanceof ReFramedDoubleBlock)
|
||||||
.toArray(Block[]::new)).build(null)
|
.toArray(Block[]::new)).build(null)
|
||||||
);
|
);
|
||||||
|
|
||||||
ITEM_GROUP = Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder()
|
ITEM_GROUP = Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder()
|
||||||
.displayName(Text.translatable("itemGroup.reframed.tab"))
|
.displayName(Text.translatable("itemGroup.reframed.tab"))
|
||||||
.icon(() -> new ItemStack(SLAB))
|
.icon(() -> new ItemStack(SLAB))
|
||||||
.entries((ctx, e) -> e.addAll(BLOCKS.stream().map(ItemStack::new).collect(Collectors.toList()))).build()
|
.entries((ctx, e) -> e.addAll(
|
||||||
|
Stream.concat(
|
||||||
|
ITEMS.stream().filter(item -> item != BLUEPRINT_WRITTEN),
|
||||||
|
BLOCKS.stream().map(Block::asItem)
|
||||||
|
).map(Item::getDefaultStack).toList())
|
||||||
|
).build()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractBlock.Settings cp(Block base) {
|
private static AbstractBlock.Settings cp(Block base) {
|
||||||
return AbstractBlock.Settings.copy(base)
|
return AbstractBlock.Settings.copy(base)
|
||||||
.luminance(BlockHelper::luminance)
|
.luminance(state -> state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
.sounds(BlockSoundGroup.WOOD)
|
.sounds(BlockSoundGroup.WOOD)
|
||||||
.hardness(0.2f)
|
.hardness(0.2f)
|
||||||
.suffocates((a,b,c) -> false)
|
.suffocates((a,b,c) -> false)
|
||||||
.blockVision((a,b,c) -> false);
|
.blockVision((a,b,c) -> false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <I extends Item> I registerItem(String path, I item) {
|
||||||
|
Identifier id = id(path);
|
||||||
|
Registry.register(Registries.ITEM, id, item);
|
||||||
|
ITEMS.add(item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
private static <B extends Block> B registerReFramed(String path, B block) {
|
private static <B extends Block> B registerBlock(String path, B block) {
|
||||||
Identifier id = id(path);
|
Identifier id = id(path);
|
||||||
|
|
||||||
Registry.register(Registries.BLOCK, id, block);
|
Registry.register(Registries.BLOCK, id, block);
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.state.property.BooleanProperty;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import org.apache.commons.lang3.function.TriFunction;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
import static net.minecraft.state.property.Properties.SOUTH;
|
||||||
|
|
||||||
|
public abstract class ConnectingReFramedBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public ConnectingReFramedBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(EAST, false)
|
||||||
|
.with(NORTH, false)
|
||||||
|
.with(WEST, false)
|
||||||
|
.with(SOUTH, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EAST, NORTH, SOUTH, WEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
|
||||||
|
return placementState(new_state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
|
||||||
|
return placementState(state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(rotation.rotate(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(mirror.apply(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean connectsTo(BlockState state, boolean fs, Direction dir);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context);
|
||||||
|
|
||||||
|
public static BooleanProperty getConnectionProperty(Direction dir) {
|
||||||
|
return switch (dir) {
|
||||||
|
case NORTH -> NORTH;
|
||||||
|
case EAST -> EAST;
|
||||||
|
case SOUTH -> SOUTH;
|
||||||
|
case WEST -> WEST;
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockState placementState(BlockState state, BlockView world, BlockPos pos, TriFunction<BlockState, Boolean, Direction, Boolean> connectsTo) {
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
BlockState neighbor = world.getBlockState(pos.offset(dir));
|
||||||
|
state = state.with(getConnectionProperty(dir), connectsTo.apply(
|
||||||
|
neighbor,
|
||||||
|
neighbor.isSideSolidFullSquare(world, pos.offset(dir), dir.getOpposite()),
|
||||||
|
dir
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public abstract class PillarReFramedBlock extends WaterloggableReFramedBlock {
|
||||||
|
public PillarReFramedBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder< Block, BlockState > builder) {
|
||||||
|
super.appendProperties(builder.add(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(AXIS, mirror.apply(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.RecipeSetter;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
|
||||||
import net.minecraft.block.*;
|
import net.minecraft.block.*;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.Items;
|
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
import net.minecraft.nbt.NbtHelper;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.state.StateManager;
|
import net.minecraft.state.StateManager;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
@@ -31,19 +27,21 @@ import net.minecraft.world.GameRules;
|
|||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.LIGHT;
|
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
|
||||||
|
|
||||||
public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter {
|
public class ReFramedBlock extends Block implements BlockEntityProvider {
|
||||||
|
|
||||||
public ReFramedBlock(Settings settings) {
|
public ReFramedBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(LIGHT, false));
|
setDefaultState(getDefaultState().with(LIGHT, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
//For addon devs: override this so your blocks don't end up trying to place my block entity, my BlockEntityType only handles blocks internal to the mod
|
|
||||||
//Just make your own BlockEntityType, it's fine, you can even use the same ReFramedEntity class
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||||
return ReFramed.REFRAMED_BLOCK_ENTITY.instantiate(pos, state);
|
return ReFramed.REFRAMED_BLOCK_ENTITY.instantiate(pos, state);
|
||||||
@@ -62,25 +60,20 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
if (!canUse(world, pos, player)) return superUse(state, world, pos, player, hand, hit);
|
if (!canUse(world, pos, player)) return ActionResult.PASS;
|
||||||
ActionResult result = BlockHelper.useUpgrade(state, world, pos, player, hand);
|
ActionResult result = BlockHelper.useUpgrade(state, world, pos, player, hand);
|
||||||
if (result.isAccepted()) return result;
|
if (result.isAccepted()) return result;
|
||||||
return BlockHelper.useCamo(state, world, pos, player, hand, hit, 1);
|
return BlockHelper.useCamo(state, world, pos, player, hand, hit, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't like this but might be useful
|
|
||||||
protected ActionResult superUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
|
||||||
return super.onUse(state, world, pos, player, hand, hit);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean canUse(World world, BlockPos pos, PlayerEntity player) {
|
protected boolean canUse(World world, BlockPos pos, PlayerEntity player) {
|
||||||
return player.canModifyBlocks() && world.canPlayerModifyAt(player, pos);
|
return player.canModifyBlocks() && world.canPlayerModifyAt(player, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
if(!state.isOf(newState.getBlock()) &&
|
if(!(new_state.getBlock() instanceof ReFramedBlock) &&
|
||||||
world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity &&
|
world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity &&
|
||||||
world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
|
world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
|
||||||
) {
|
) {
|
||||||
@@ -91,28 +84,56 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
|
|||||||
if(theme.getBlock() != Blocks.AIR) drops.add(new ItemStack(theme.getBlock()));
|
if(theme.getBlock() != Blocks.AIR) drops.add(new ItemStack(theme.getBlock()));
|
||||||
});
|
});
|
||||||
|
|
||||||
if(frame_entity.emitsRedstone()
|
|
||||||
&& themes.stream().noneMatch(theme -> theme.getWeakRedstonePower(world, pos, Direction.NORTH) != 0))
|
|
||||||
drops.add(new ItemStack(Items.REDSTONE_TORCH));
|
|
||||||
if(frame_entity.emitsLight()
|
|
||||||
&& themes.stream().noneMatch(theme -> theme.getLuminance() != 0))
|
|
||||||
drops.add(new ItemStack(Items.GLOWSTONE_DUST));
|
|
||||||
if(!frame_entity.isSolid()
|
|
||||||
&& themes.stream().anyMatch(theme -> theme.isSolid()))
|
|
||||||
drops.add(new ItemStack(Items.POPPED_CHORUS_FRUIT));
|
|
||||||
|
|
||||||
ItemScatterer.spawn(world, pos, drops);
|
ItemScatterer.spawn(world, pos, drops);
|
||||||
}
|
}
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) {
|
||||||
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
|
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)) {
|
||||||
if(world.isClient && world.getBlockEntity(pos) instanceof ReFramedEntity be) {
|
onPlaced(world, pos, state, placer, stack);
|
||||||
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
|
return;
|
||||||
if(tag != null) be.readNbt(tag);
|
|
||||||
}
|
}
|
||||||
super.onPlaced(world, pos, state, placer, stack);
|
|
||||||
|
// apply state change keeping the old information
|
||||||
|
if (old_state.getBlock() instanceof ReFramedBlock old_frame_block
|
||||||
|
&& old_entity instanceof ReFramedEntity old_frame_entity) {
|
||||||
|
Map<Integer, Integer> theme_map = old_frame_block.getThemeMap(old_state, state);
|
||||||
|
theme_map.forEach((self, other) ->
|
||||||
|
frame_entity.setTheme(old_frame_entity.getTheme(self), other)
|
||||||
|
);
|
||||||
|
|
||||||
|
// apply any changes needed to keep previous properties
|
||||||
|
if (old_frame_entity.emitsLight() && !frame_entity.emitsLight()) {
|
||||||
|
frame_entity.toggleLight();
|
||||||
|
world.setBlockState(pos, state.with(LIGHT, true));
|
||||||
|
}
|
||||||
|
if (old_frame_entity.emitsRedstone() && !frame_entity.emitsRedstone()) {
|
||||||
|
frame_entity.toggleRedstone();
|
||||||
|
world.updateNeighbors(pos, this);
|
||||||
|
}
|
||||||
|
if (old_frame_entity.isSolid() && !frame_entity.isSolid()) frame_entity.toggleSolidity();
|
||||||
|
|
||||||
|
// apply themes from item
|
||||||
|
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
|
||||||
|
if(tag != null) {
|
||||||
|
// determine a list of themes than can be used
|
||||||
|
Iterator<Integer> free_themes = IntStream
|
||||||
|
.rangeClosed(1, frame_entity.getThemes().size())
|
||||||
|
.filter(value -> !theme_map.containsValue(value))
|
||||||
|
.iterator();
|
||||||
|
// apply all the themes possible from item
|
||||||
|
for (int i = 1; tag.contains(BLOCKSTATE_KEY + i) && free_themes.hasNext(); i++) {
|
||||||
|
BlockState theme = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), tag.getCompound(BLOCKSTATE_KEY + i));
|
||||||
|
if (theme == null || theme.getBlock() == Blocks.AIR) continue;
|
||||||
|
frame_entity.setTheme(theme, free_themes.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(world.isClient) { // prevents flashing with default texture before server sends the update
|
||||||
|
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
|
||||||
|
if(tag != null) frame_entity.readNbt(tag);
|
||||||
|
}
|
||||||
|
onPlaced(world, pos, state, placer, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -148,21 +169,20 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
|
|||||||
return getWeakRedstonePower(state, view, pos, dir);
|
return getWeakRedstonePower(state, view, pos, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param state - the block state to get the top theme index from
|
||||||
|
* @return the index of the top theme to use for the block
|
||||||
|
*/
|
||||||
public int getTopThemeIndex(BlockState state) {
|
public int getTopThemeIndex(BlockState state) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
* @param state - the block state of the block that is being replaced
|
||||||
ShapedRecipeJsonBuilder
|
* @param new_state - the block state of the block that is replacing the block
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this)
|
* @return a map of the theme indexes to map when changing state so that the themes are preserved
|
||||||
.pattern("III")
|
*/
|
||||||
.pattern("I~I")
|
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
|
||||||
.pattern("III")
|
return Map.of();
|
||||||
.input('I', Items.BAMBOO)
|
|
||||||
.input('~', Items.STRING)
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(Items.BAMBOO), FabricRecipeProvider.conditionsFromItem(Items.BAMBOO))
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.enums.BlockFace;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.projectile.PersistentProjectileEntity;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import net.minecraft.world.WorldView;
|
||||||
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
import net.minecraft.world.explosion.Explosion;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class ReFramedButtonBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] BUTTON_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedButtonBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(HORIZONTAL_FACING, Direction.NORTH)
|
||||||
|
.with(BLOCK_FACE, BlockFace.WALL)
|
||||||
|
.with(POWERED, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(HORIZONTAL_FACING, BLOCK_FACE, POWERED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
|
||||||
|
return canPlaceAt(world, pos, getDirection(state).getOpposite());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canPlaceAt(WorldView world, BlockPos pos, Direction direction) {
|
||||||
|
BlockPos other_pos = pos.offset(direction);
|
||||||
|
return world.getBlockState(other_pos).isSideSolidFullSquare(world, other_pos, direction.getOpposite());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
Direction side = ctx.getSide();
|
||||||
|
return state
|
||||||
|
.with(HORIZONTAL_FACING, side.getAxis() == Direction.Axis.Y
|
||||||
|
? ctx.getHorizontalPlayerFacing()
|
||||||
|
: side
|
||||||
|
)
|
||||||
|
.with(BLOCK_FACE, side.getAxis() != Direction.Axis.Y
|
||||||
|
? BlockFace.WALL
|
||||||
|
: side == Direction.UP ? BlockFace.FLOOR : BlockFace.CEILING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos other_pos) {
|
||||||
|
return getDirection(state).getOpposite() == direction && !state.canPlaceAt(world, pos)
|
||||||
|
? Blocks.AIR.getDefaultState()
|
||||||
|
: super.getStateForNeighborUpdate(state, direction, other_state, world, pos, other_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
|
||||||
|
if (state.get(POWERED)) return ActionResult.CONSUME;
|
||||||
|
powerOn(state, world, pos);
|
||||||
|
playClickSound(player, world, pos, true);
|
||||||
|
world.emitGameEvent(player, GameEvent.BLOCK_ACTIVATE, pos);
|
||||||
|
|
||||||
|
return ActionResult.success(world.isClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExploded(BlockState state, World world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) {
|
||||||
|
if (explosion.getDestructionType() == Explosion.DestructionType.TRIGGER_BLOCK && !world.isClient() && !(Boolean)state.get(POWERED)) {
|
||||||
|
powerOn(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onExploded(state, world, pos, explosion, stackMerger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void powerOn(BlockState state, World world, BlockPos pos) {
|
||||||
|
world.setBlockState(pos, state.with(POWERED, true), 3);
|
||||||
|
updateNeighbors(state, world, pos);
|
||||||
|
world.scheduleBlockTick(pos, this, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void playClickSound(@Nullable PlayerEntity player, WorldAccess world, BlockPos pos, boolean powered) {
|
||||||
|
world.playSound(
|
||||||
|
powered ? player : null,
|
||||||
|
pos,
|
||||||
|
powered ? BlockSetType.OAK.buttonClickOn() : BlockSetType.OAK.buttonClickOff(),
|
||||||
|
SoundCategory.BLOCKS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return BUTTON_VOXELS[
|
||||||
|
(state.get(POWERED) ? 12 : 0) +
|
||||||
|
(4 * state.get(BLOCK_FACE).ordinal()) +
|
||||||
|
state.get(HORIZONTAL_FACING).ordinal() - 2
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(HORIZONTAL_FACING, rotation.rotate(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(HORIZONTAL_FACING, mirror.apply(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, false);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) {
|
||||||
|
if (!moved && state.get(POWERED)) updateNeighbors(state, world, pos);
|
||||||
|
world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeakRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) {
|
||||||
|
return state.get(POWERED) ? 15 : super.getWeakRedstonePower(state, view, pos, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStrongRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) {
|
||||||
|
return dir == getDirection(state) ? state.getWeakRedstonePower(view, pos, dir) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean emitsRedstonePower(BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||||
|
if (state.get(POWERED)) tryPowerWithProjectiles(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
|
||||||
|
if (!world.isClient && !state.get(POWERED)) tryPowerWithProjectiles(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void tryPowerWithProjectiles(BlockState state, World world, BlockPos pos) {
|
||||||
|
PersistentProjectileEntity projectile = world.getNonSpectatingEntities(
|
||||||
|
PersistentProjectileEntity.class,
|
||||||
|
state.getOutlineShape(world, pos).getBoundingBox().offset(pos)
|
||||||
|
).stream().findFirst().orElse(null);
|
||||||
|
boolean has_projectile = projectile != null;
|
||||||
|
if (has_projectile != state.get(POWERED)) {
|
||||||
|
world.setBlockState(pos, state.with(POWERED, has_projectile), 3);
|
||||||
|
this.updateNeighbors(state, world, pos);
|
||||||
|
this.playClickSound(null, world, pos, has_projectile);
|
||||||
|
world.emitGameEvent(projectile, has_projectile ? GameEvent.BLOCK_ACTIVATE : GameEvent.BLOCK_DEACTIVATE, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_projectile) {
|
||||||
|
world.scheduleBlockTick(pos, this, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateNeighbors(BlockState state, World world, BlockPos pos) {
|
||||||
|
world.updateNeighborsAlways(pos, this);
|
||||||
|
world.updateNeighborsAlways(pos.offset(getDirection(state).getOpposite()), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Direction getDirection(BlockState state) {
|
||||||
|
return switch (state.get(BLOCK_FACE)) {
|
||||||
|
case CEILING -> Direction.DOWN;
|
||||||
|
case FLOOR -> Direction.UP;
|
||||||
|
default -> state.get(HORIZONTAL_FACING);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape SHAPE = createCuboidShape(5, 0, 6, 11, 2, 10);
|
||||||
|
VoxelShape POWERED_SHAPE = createCuboidShape(5, 0, 6, 11, 1, 10);
|
||||||
|
BUTTON_VOXELS = VoxelHelper.VoxelListBuilder.create(SHAPE, 24)
|
||||||
|
.add()
|
||||||
|
.add(0, VoxelHelper::rotateY)
|
||||||
|
.add()
|
||||||
|
.add(VoxelHelper::rotateZ, VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(0, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.add(2, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.add(POWERED_SHAPE)
|
||||||
|
.add()
|
||||||
|
.add(12, VoxelHelper::rotateY)
|
||||||
|
.add()
|
||||||
|
.add(VoxelHelper::rotateZ, VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(12, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.add(13, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.block.enums.DoorHinge;
|
||||||
|
import net.minecraft.block.enums.DoubleBlockHalf;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import net.minecraft.world.WorldView;
|
||||||
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
import net.minecraft.world.explosion.Explosion;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class ReFramedDoorBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] DOOR_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedDoorBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(HORIZONTAL_FACING, Direction.NORTH)
|
||||||
|
.with(DOOR_HINGE, DoorHinge.LEFT)
|
||||||
|
.with(DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER)
|
||||||
|
.with(OPEN, false)
|
||||||
|
.with(POWERED, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(HORIZONTAL_FACING, DOOR_HINGE, DOUBLE_BLOCK_HALF, OPEN, POWERED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
|
||||||
|
BlockPos pos_down = pos.down();
|
||||||
|
BlockState state_down = world.getBlockState(pos_down);
|
||||||
|
return state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER ? !state_down.isAir() : state_down.isOf(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block source, BlockPos sourcePos, boolean notify) {
|
||||||
|
if (world.isClient) return;
|
||||||
|
boolean powered = world.isReceivingRedstonePower(pos)
|
||||||
|
|| world.isReceivingRedstonePower(
|
||||||
|
state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER
|
||||||
|
? pos.up()
|
||||||
|
: pos.down()
|
||||||
|
);
|
||||||
|
if (!getDefaultState().isOf(source) && powered != state.get(POWERED)) {
|
||||||
|
if (state.get(OPEN) != powered)
|
||||||
|
playToggleSound(null, world, pos, powered);
|
||||||
|
|
||||||
|
world.setBlockState(pos, state.with(POWERED, powered).with(OPEN, powered), 2);
|
||||||
|
if (state.get(WATERLOGGED)) {
|
||||||
|
world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
Direction facing = ctx.getHorizontalPlayerFacing().getOpposite();
|
||||||
|
if (pos.getY() >= world.getTopY() - 1 || !world.getBlockState(pos.up()).canReplace(ctx)) return null;
|
||||||
|
BlockState state = super.getPlacementState(ctx)
|
||||||
|
.with(DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER)
|
||||||
|
.with(HORIZONTAL_FACING, facing);
|
||||||
|
|
||||||
|
if (world.isReceivingRedstonePower(pos) || world.isReceivingRedstonePower(pos.up()))
|
||||||
|
state = state.with(OPEN, true).with(POWERED, true);
|
||||||
|
|
||||||
|
|
||||||
|
return state.with(DOOR_HINGE, getHinge(facing, pos, world, BlockHelper.getRelativePos(ctx.getHitPos(), pos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) {
|
||||||
|
world.setBlockState(
|
||||||
|
pos.up(),
|
||||||
|
state
|
||||||
|
.with(DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER)
|
||||||
|
.with(WATERLOGGED, world.getFluidState(pos.up()).isOf(Fluids.WATER)),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||||
|
if (!world.isClient() && (player.isCreative() || player.canHarvest(state))) {
|
||||||
|
DoubleBlockHalf half = state.get(DOUBLE_BLOCK_HALF);
|
||||||
|
BlockPos other_pos = half == DoubleBlockHalf.LOWER ? pos.up() : pos.down();
|
||||||
|
BlockState other_state = world.getBlockState(other_pos);
|
||||||
|
if (other_state.isOf(this) && other_state.get(DOUBLE_BLOCK_HALF) != half) {
|
||||||
|
world.setBlockState(other_pos, other_state.get(WATERLOGGED) ? Blocks.WATER.getDefaultState(): Blocks.AIR.getDefaultState(), 35);
|
||||||
|
world.syncWorldEvent(player, 2001, other_pos, Block.getRawIdFromState(other_state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onBreak(world, pos, state, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState other, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
if (direction.getAxis() == Direction.Axis.Y
|
||||||
|
&& other.isOf(this)
|
||||||
|
&& other.get(DOUBLE_BLOCK_HALF) != state.get(DOUBLE_BLOCK_HALF)
|
||||||
|
&& other.get(OPEN) != state.get(OPEN)
|
||||||
|
) return state.cycle(OPEN);
|
||||||
|
Direction facing = state.get(HORIZONTAL_FACING);
|
||||||
|
if (direction == (
|
||||||
|
state.get(DOOR_HINGE) == DoorHinge.RIGHT
|
||||||
|
? facing.rotateYClockwise()
|
||||||
|
: facing.rotateYCounterclockwise())
|
||||||
|
&& other.isOf(this)
|
||||||
|
&& other.get(DOUBLE_BLOCK_HALF) == state.get(DOUBLE_BLOCK_HALF)
|
||||||
|
&& other.get(DOOR_HINGE) != state.get(DOOR_HINGE)
|
||||||
|
&& !state.get(POWERED)
|
||||||
|
) return state.with(OPEN, other.get(OPEN));
|
||||||
|
return super.getStateForNeighborUpdate(state, direction, other, world, pos, moved);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
flip(state, world, pos, player);
|
||||||
|
return ActionResult.success(world.isClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
|
||||||
|
return switch (type) {
|
||||||
|
case LAND, AIR -> state.get(OPEN);
|
||||||
|
case WATER -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExploded(BlockState state, World world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stack_merger) {
|
||||||
|
if (explosion.getDestructionType() == Explosion.DestructionType.TRIGGER_BLOCK
|
||||||
|
&& !world.isClient()
|
||||||
|
&& !state.get(POWERED)
|
||||||
|
) flip(state, world, pos, null);
|
||||||
|
|
||||||
|
super.onExploded(state, world, pos, explosion, stack_merger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flip(BlockState state, World world, BlockPos pos, @Nullable PlayerEntity player) {
|
||||||
|
state = state.cycle(OPEN);
|
||||||
|
world.setBlockState(pos, state, 10);
|
||||||
|
|
||||||
|
this.playToggleSound(player, world, pos, state.get(OPEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void playToggleSound(@Nullable PlayerEntity player, World world, BlockPos pos, boolean open) {
|
||||||
|
world.playSound(player, pos, open ? BlockSetType.OAK.doorOpen() : BlockSetType.OAK.doorClose(), SoundCategory.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.1F + 0.9F);
|
||||||
|
world.emitGameEvent(player, open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
Direction direction = state.get(HORIZONTAL_FACING);
|
||||||
|
if (state.get(OPEN)) direction = switch (state.get(DOOR_HINGE)) {
|
||||||
|
case RIGHT -> direction.rotateYCounterclockwise();
|
||||||
|
case LEFT -> direction.rotateYClockwise();
|
||||||
|
};
|
||||||
|
return DOOR_VOXELS[direction.ordinal() - 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(HORIZONTAL_FACING, rotation.rotate(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return mirror == BlockMirror.NONE ? state : state.with(HORIZONTAL_FACING, mirror.apply(state.get(HORIZONTAL_FACING))).cycle(DOOR_HINGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRenderingSeed(BlockState state, BlockPos pos) {
|
||||||
|
return MathHelper.hashCode(pos.getX(), pos.down(state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER ? 0 : 1).getY(), pos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DoorHinge getHinge(Direction facing, BlockPos pos, World world, Vec3d hit_pos) {
|
||||||
|
Direction left = facing.rotateYClockwise();
|
||||||
|
BlockPos left_pos = pos.offset(left);
|
||||||
|
BlockState left_state = world.getBlockState(left_pos);
|
||||||
|
Direction right = facing.rotateYCounterclockwise();
|
||||||
|
BlockPos right_pos = pos.offset(right);
|
||||||
|
BlockState right_state = world.getBlockState(right_pos);
|
||||||
|
DoorHinge hinge = null;
|
||||||
|
|
||||||
|
if (left_state.isSideSolidFullSquare(world, left_pos, right))
|
||||||
|
hinge = DoorHinge.LEFT;
|
||||||
|
if (right_state.isSideSolidFullSquare(world, right_pos, left))
|
||||||
|
hinge = hinge == DoorHinge.LEFT ? null : DoorHinge.RIGHT;
|
||||||
|
|
||||||
|
if (hinge != null) return hinge;
|
||||||
|
|
||||||
|
if (left_state.isOf(this)
|
||||||
|
&& left_state.get(HORIZONTAL_FACING) == facing
|
||||||
|
&& left_state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER
|
||||||
|
&& left_state.get(DOOR_HINGE) == DoorHinge.LEFT
|
||||||
|
) hinge = DoorHinge.RIGHT;
|
||||||
|
if (right_state.isOf(this)
|
||||||
|
&& right_state.get(HORIZONTAL_FACING) == facing
|
||||||
|
&& right_state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER
|
||||||
|
&& right_state.get(DOOR_HINGE) == DoorHinge.RIGHT
|
||||||
|
) hinge = hinge == DoorHinge.RIGHT ? null : DoorHinge.LEFT;
|
||||||
|
|
||||||
|
if (hinge != null) return hinge;
|
||||||
|
|
||||||
|
return switch (facing.getAxis()) {
|
||||||
|
case Z -> {
|
||||||
|
if (left.getDirection() == Direction.AxisDirection.POSITIVE)
|
||||||
|
yield hit_pos.getX() < 0.5 ? DoorHinge.RIGHT : DoorHinge.LEFT;
|
||||||
|
else // left.getDirection() == Direction.AxisDirection.NEGATIVE
|
||||||
|
yield hit_pos.getX() < 0.5 ? DoorHinge.LEFT : DoorHinge.RIGHT;
|
||||||
|
}
|
||||||
|
case X -> {
|
||||||
|
if (left.getDirection() == Direction.AxisDirection.POSITIVE)
|
||||||
|
yield hit_pos.getZ() < 0.5 ? DoorHinge.RIGHT : DoorHinge.LEFT;
|
||||||
|
else // left.getDirection() == Direction.AxisDirection.NEGATIVE
|
||||||
|
yield hit_pos.getZ() < 0.5 ? DoorHinge.LEFT : DoorHinge.RIGHT;
|
||||||
|
}
|
||||||
|
default -> DoorHinge.LEFT;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape SHAPE = createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 3.0);
|
||||||
|
DOOR_VOXELS = VoxelHelper.VoxelListBuilder.create(SHAPE, 4)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@@ -31,8 +31,11 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock {
|
|||||||
return ReFramed.REFRAMED_DOUBLE_BLOCK_ENTITY.instantiate(pos, state);
|
return ReFramed.REFRAMED_DOUBLE_BLOCK_ENTITY.instantiate(pos, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getHitShape(BlockState state, BlockHitResult hit) {
|
public int getHitShape(BlockState state, BlockHitResult hit) {
|
||||||
Direction side = hit.getSide();
|
return getHitShape(state, hit.getPos(), hit.getBlockPos(), hit.getSide());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHitShape(BlockState state, Vec3d hit, BlockPos pos, Direction side) {
|
||||||
VoxelShape first_shape = getShape(state, 1);
|
VoxelShape first_shape = getShape(state, 1);
|
||||||
VoxelShape second_shape = getShape(state, 2);
|
VoxelShape second_shape = getShape(state, 2);
|
||||||
|
|
||||||
@@ -40,13 +43,20 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock {
|
|||||||
if (isFaceFullSquare(first_shape, side)) return 1;
|
if (isFaceFullSquare(first_shape, side)) return 1;
|
||||||
if (isFaceFullSquare(second_shape, side)) return 2;
|
if (isFaceFullSquare(second_shape, side)) return 2;
|
||||||
|
|
||||||
Vec3d pos = BlockHelper.getRelativePos(hit.getPos(), hit.getBlockPos());
|
Vec3d rel = BlockHelper.getRelativePos(hit, pos);
|
||||||
// System.out.println(side.getAxis().choose(hit.getPos().x, hit.getPos().y, hit.getPos().z));
|
if (BlockHelper.cursorMatchesFace(first_shape, rel)) return 1;
|
||||||
if (BlockHelper.cursorMatchesFace(first_shape, pos)) return 1;
|
if (BlockHelper.cursorMatchesFace(second_shape, rel)) return 2;
|
||||||
if (BlockHelper.cursorMatchesFace(second_shape, pos)) return 2;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean matchesShape(Vec3d hit, BlockPos pos, BlockState state, int i) {
|
||||||
|
Vec3d rel = BlockHelper.getRelativePos(hit, pos);
|
||||||
|
return BlockHelper.cursorMatchesFace(
|
||||||
|
getShape(state, i),
|
||||||
|
rel
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) {
|
public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) {
|
||||||
return world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity
|
return world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity
|
||||||
@@ -59,17 +69,17 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
return getCullingShape(state, view, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
|
||||||
return isGhost(view, pos) ? empty() : fullCube();
|
return isGhost(view, pos) ? empty() : fullCube();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
||||||
|
return getCollisionShape(state, view, pos, ShapeContext.absent());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
if (!canUse(world, pos, player)) return superUse(state, world, pos, player, hand, hit);
|
if (!canUse(world, pos, player)) return ActionResult.PASS;
|
||||||
ActionResult result = BlockHelper.useUpgrade(state, world, pos, player, hand);
|
ActionResult result = BlockHelper.useUpgrade(state, world, pos, player, hand);
|
||||||
if (result.isAccepted()) return result;
|
if (result.isAccepted()) return result;
|
||||||
return BlockHelper.useCamo(state, world, pos, player, hand, hit, getHitShape(state, hit));
|
return BlockHelper.useCamo(state, world, pos, player, hand, hit, getHitShape(state, hit));
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class ReFramedDoubleEntity extends ReFramedEntity {
|
|||||||
public void readNbt(NbtCompound nbt) {
|
public void readNbt(NbtCompound nbt) {
|
||||||
super.readNbt(nbt);
|
super.readNbt(nbt);
|
||||||
|
|
||||||
BlockState rendered_state = second_state;// keep previous state to check if rerender is needed
|
BlockState rendered_state = second_state;// keep previous state_key to check if rerender is needed
|
||||||
second_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 2));
|
second_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 2));
|
||||||
|
|
||||||
// Force a chunk remesh on the client if the displayed blockstate has changed
|
// Force a chunk remesh on the client if the displayed blockstate has changed
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
|
||||||
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
|
||||||
import net.minecraft.state.StateManager;
|
|
||||||
import net.minecraft.state.property.Properties;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*;
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
|
|
||||||
import static net.minecraft.state.property.Properties.AXIS;
|
|
||||||
|
|
||||||
public class ReFramedDoubleSlabBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
|
||||||
public ReFramedDoubleSlabBlock(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
setDefaultState(getDefaultState().with(Properties.AXIS, Direction.Axis.Y));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
|
||||||
super.appendProperties(builder.add(Properties.AXIS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
|
||||||
return super.getPlacementState(ctx).with(Properties.AXIS, ctx.getSide().getAxis());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoxelShape getShape(BlockState state, int i) {
|
|
||||||
return switch (state.get(Properties.AXIS)) {
|
|
||||||
case Y -> i == 2 ? UP : DOWN;
|
|
||||||
case Z -> i == 2 ? NORTH : SOUTH;
|
|
||||||
case X -> i == 2 ? EAST : WEST;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTopThemeIndex(BlockState state) {
|
|
||||||
// when the side is shared just return one
|
|
||||||
return state.get(AXIS) == Direction.Axis.Y ? 2: super.getTopThemeIndex(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
|
||||||
Identifier model_id = ReFramed.id("double_slab_special");
|
|
||||||
return MultipartBlockStateSupplier.create(this)
|
|
||||||
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
|
|
||||||
GBlockstate.variant(model_id, true, R0, R0))
|
|
||||||
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
|
|
||||||
GBlockstate.variant(model_id, true, R90, R0))
|
|
||||||
.with(GBlockstate.when(AXIS, Direction.Axis.X),
|
|
||||||
GBlockstate.variant(model_id, true, R90, R90));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
|
||||||
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE);
|
|
||||||
ShapelessRecipeJsonBuilder
|
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this)
|
|
||||||
.input(ReFramed.SLAB, 2)
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
|
||||||
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
|
||||||
import net.minecraft.state.StateManager;
|
|
||||||
import net.minecraft.util.function.BooleanBiFunction;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraft.world.WorldAccess;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.block.ReFramedStairsBlock.*;
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.STAIR_SHAPE;
|
|
||||||
import static fr.adrien1106.reframed.util.property.StairShape.STRAIGHT;
|
|
||||||
|
|
||||||
public class ReFramedDoubleStairsBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
|
||||||
|
|
||||||
private static final List<VoxelShape> COMPLEMENT_LIST = new ArrayList<>(52);
|
|
||||||
|
|
||||||
public ReFramedDoubleStairsBlock(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
|
||||||
super.appendProperties(builder.add(CORNER, STAIR_SHAPE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighbor_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
|
||||||
return super.getStateForNeighborUpdate(state, direction, neighbor_state, world, pos, moved)
|
|
||||||
.with(STAIR_SHAPE, BlockHelper.getStairsShape(this, state.get(CORNER), world, pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
|
||||||
Corner face = BlockHelper.getPlacementCorner(ctx);
|
|
||||||
StairShape shape = BlockHelper.getStairsShape(this, face, ctx.getWorld(), ctx.getBlockPos());
|
|
||||||
return super.getPlacementState(ctx).with(CORNER, face).with(STAIR_SHAPE, shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoxelShape getShape(BlockState state, int i) {
|
|
||||||
return i == 2 ? getComplementOutline(state) : getOutline(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
private VoxelShape getComplementOutline(BlockState state) {
|
|
||||||
StairShape shape = state.get(STAIR_SHAPE);
|
|
||||||
Corner direction = state.get(CORNER);
|
|
||||||
return switch (shape) {
|
|
||||||
case STRAIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_SOUTH -> COMPLEMENT_LIST.get(0);
|
|
||||||
case NORTH_DOWN -> COMPLEMENT_LIST.get(1);
|
|
||||||
case UP_NORTH -> COMPLEMENT_LIST.get(2);
|
|
||||||
case SOUTH_UP -> COMPLEMENT_LIST.get(3);
|
|
||||||
case DOWN_EAST -> COMPLEMENT_LIST.get(4);
|
|
||||||
case WEST_DOWN -> COMPLEMENT_LIST.get(5);
|
|
||||||
case UP_WEST -> COMPLEMENT_LIST.get(6);
|
|
||||||
case EAST_UP -> COMPLEMENT_LIST.get(7);
|
|
||||||
case NORTH_EAST -> COMPLEMENT_LIST.get(8);
|
|
||||||
case EAST_SOUTH -> COMPLEMENT_LIST.get(9);
|
|
||||||
case SOUTH_WEST -> COMPLEMENT_LIST.get(10);
|
|
||||||
case WEST_NORTH -> COMPLEMENT_LIST.get(11);
|
|
||||||
};
|
|
||||||
case INNER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case WEST_DOWN, NORTH_DOWN -> COMPLEMENT_LIST.get(44);
|
|
||||||
case DOWN_EAST -> COMPLEMENT_LIST.get(45);
|
|
||||||
case DOWN_SOUTH -> COMPLEMENT_LIST.get(47);
|
|
||||||
case UP_WEST, UP_NORTH, WEST_NORTH -> COMPLEMENT_LIST.get(48);
|
|
||||||
case EAST_UP, NORTH_EAST -> COMPLEMENT_LIST.get(49);
|
|
||||||
case EAST_SOUTH -> COMPLEMENT_LIST.get(50);
|
|
||||||
case SOUTH_UP, SOUTH_WEST -> COMPLEMENT_LIST.get(51);
|
|
||||||
};
|
|
||||||
case INNER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case WEST_NORTH -> COMPLEMENT_LIST.get(44);
|
|
||||||
case NORTH_DOWN, NORTH_EAST -> COMPLEMENT_LIST.get(45);
|
|
||||||
case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> COMPLEMENT_LIST.get(46);
|
|
||||||
case WEST_DOWN, SOUTH_WEST -> COMPLEMENT_LIST.get(47);
|
|
||||||
case UP_NORTH -> COMPLEMENT_LIST.get(49);
|
|
||||||
case EAST_UP, SOUTH_UP -> COMPLEMENT_LIST.get(50);
|
|
||||||
case UP_WEST -> COMPLEMENT_LIST.get(51);
|
|
||||||
};
|
|
||||||
case OUTER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_EAST -> COMPLEMENT_LIST.get(43);
|
|
||||||
case WEST_DOWN, NORTH_DOWN -> COMPLEMENT_LIST.get(42);
|
|
||||||
case DOWN_SOUTH -> COMPLEMENT_LIST.get(41);
|
|
||||||
case EAST_UP, NORTH_EAST -> COMPLEMENT_LIST.get(39);
|
|
||||||
case UP_WEST, UP_NORTH, WEST_NORTH -> COMPLEMENT_LIST.get(38);
|
|
||||||
case SOUTH_UP, SOUTH_WEST -> COMPLEMENT_LIST.get(37);
|
|
||||||
case EAST_SOUTH -> COMPLEMENT_LIST.get(36);
|
|
||||||
};
|
|
||||||
case OUTER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case NORTH_DOWN, NORTH_EAST -> COMPLEMENT_LIST.get(43);
|
|
||||||
case WEST_NORTH -> COMPLEMENT_LIST.get(42);
|
|
||||||
case WEST_DOWN, SOUTH_WEST -> COMPLEMENT_LIST.get(41);
|
|
||||||
case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> COMPLEMENT_LIST.get(40);
|
|
||||||
case UP_NORTH -> COMPLEMENT_LIST.get(39);
|
|
||||||
case UP_WEST -> COMPLEMENT_LIST.get(37);
|
|
||||||
case EAST_UP, SOUTH_UP -> COMPLEMENT_LIST.get(36);
|
|
||||||
};
|
|
||||||
case FIRST_OUTER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case WEST_DOWN, NORTH_DOWN -> COMPLEMENT_LIST.get(14);
|
|
||||||
case SOUTH_UP -> COMPLEMENT_LIST.get(17);
|
|
||||||
case EAST_UP -> COMPLEMENT_LIST.get(19);
|
|
||||||
case EAST_SOUTH -> COMPLEMENT_LIST.get(20);
|
|
||||||
case DOWN_SOUTH -> COMPLEMENT_LIST.get(22);
|
|
||||||
case UP_NORTH, WEST_NORTH -> COMPLEMENT_LIST.get(25);
|
|
||||||
case SOUTH_WEST -> COMPLEMENT_LIST.get(28);
|
|
||||||
case UP_WEST -> COMPLEMENT_LIST.get(31);
|
|
||||||
case DOWN_EAST -> COMPLEMENT_LIST.get(34);
|
|
||||||
case NORTH_EAST -> COMPLEMENT_LIST.get(35);
|
|
||||||
};
|
|
||||||
case FIRST_OUTER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case NORTH_DOWN -> COMPLEMENT_LIST.get(15);
|
|
||||||
case SOUTH_UP, EAST_UP -> COMPLEMENT_LIST.get(16);
|
|
||||||
case WEST_DOWN -> COMPLEMENT_LIST.get(13);
|
|
||||||
case DOWN_SOUTH, EAST_SOUTH -> COMPLEMENT_LIST.get(23);
|
|
||||||
case UP_NORTH -> COMPLEMENT_LIST.get(24);
|
|
||||||
case WEST_NORTH -> COMPLEMENT_LIST.get(26);
|
|
||||||
case UP_WEST -> COMPLEMENT_LIST.get(28);
|
|
||||||
case SOUTH_WEST -> COMPLEMENT_LIST.get(29);
|
|
||||||
case DOWN_EAST -> COMPLEMENT_LIST.get(33);
|
|
||||||
case NORTH_EAST -> COMPLEMENT_LIST.get(34);
|
|
||||||
};
|
|
||||||
case SECOND_OUTER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_EAST -> COMPLEMENT_LIST.get(15);
|
|
||||||
case DOWN_SOUTH -> COMPLEMENT_LIST.get(13);
|
|
||||||
case UP_WEST, UP_NORTH -> COMPLEMENT_LIST.get(18);
|
|
||||||
case SOUTH_UP, SOUTH_WEST -> COMPLEMENT_LIST.get(21);
|
|
||||||
case NORTH_EAST -> COMPLEMENT_LIST.get(24);
|
|
||||||
case NORTH_DOWN -> COMPLEMENT_LIST.get(26);
|
|
||||||
case WEST_DOWN -> COMPLEMENT_LIST.get(30);
|
|
||||||
case WEST_NORTH -> COMPLEMENT_LIST.get(31);
|
|
||||||
case EAST_SOUTH -> COMPLEMENT_LIST.get(32);
|
|
||||||
case EAST_UP -> COMPLEMENT_LIST.get(35);
|
|
||||||
};
|
|
||||||
case SECOND_OUTER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_SOUTH, DOWN_EAST -> COMPLEMENT_LIST.get(12);
|
|
||||||
case UP_WEST -> COMPLEMENT_LIST.get(17);
|
|
||||||
case UP_NORTH -> COMPLEMENT_LIST.get(19);
|
|
||||||
case SOUTH_UP -> COMPLEMENT_LIST.get(20);
|
|
||||||
case SOUTH_WEST -> COMPLEMENT_LIST.get(22);
|
|
||||||
case NORTH_EAST, NORTH_DOWN -> COMPLEMENT_LIST.get(27);
|
|
||||||
case WEST_DOWN -> COMPLEMENT_LIST.get(29);
|
|
||||||
case WEST_NORTH -> COMPLEMENT_LIST.get(30);
|
|
||||||
case EAST_UP -> COMPLEMENT_LIST.get(32);
|
|
||||||
case EAST_SOUTH -> COMPLEMENT_LIST.get(33);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
|
||||||
return getStairMultipart(this, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
|
||||||
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE);
|
|
||||||
ShapelessRecipeJsonBuilder
|
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this)
|
|
||||||
.input(ReFramed.STAIRS)
|
|
||||||
.input(ReFramed.STEP)
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
VOXEL_LIST.forEach(shape -> COMPLEMENT_LIST.add(VoxelShapes.combineAndSimplify(VoxelShapes.fullCube(), shape, BooleanBiFunction.ONLY_FIRST)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.block.ShapeContext;
|
|
||||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
|
||||||
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
|
||||||
import net.minecraft.state.StateManager;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.math.Direction.Axis;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
|
||||||
import net.minecraft.world.BlockView;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*;
|
|
||||||
import static fr.adrien1106.reframed.block.ReFramedStepBlock.STEP_VOXELS;
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
|
||||||
import static net.minecraft.state.property.Properties.FACING;
|
|
||||||
import static net.minecraft.state.property.Properties.AXIS;
|
|
||||||
import static net.minecraft.util.shape.VoxelShapes.empty;
|
|
||||||
|
|
||||||
public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
|
|
||||||
public ReFramedDoubleStepBlock(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
|
||||||
super.appendProperties(builder.add(FACING, AXIS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
|
||||||
Vec3d pos = BlockHelper.getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
|
||||||
return super.getPlacementState(ctx)
|
|
||||||
.with(FACING, ctx.getSide().getOpposite())
|
|
||||||
.with(AXIS, BlockHelper.getHitAxis(pos, ctx.getSide()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
|
||||||
return isGhost(view, pos) ? empty() : getSlabShape(state.get(FACING));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
|
||||||
return getSlabShape(state.get(FACING));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoxelShape getShape(BlockState state, int i) {
|
|
||||||
Axis axis = state.get(AXIS);
|
|
||||||
return STEP_VOXELS.get(switch (state.get(FACING)) {
|
|
||||||
case DOWN -> axis == Axis.Z ? (i == 1 ? 0 : 1): (i == 1 ? 4 : 5 );
|
|
||||||
case UP -> axis == Axis.Z ? (i == 1 ? 3 : 2): (i == 1 ? 7 : 6 );
|
|
||||||
case NORTH -> axis == Axis.Y ? (i == 1 ? 1 : 2): (i == 1 ? 11 : 8 );
|
|
||||||
case SOUTH -> axis == Axis.Y ? (i == 1 ? 0 : 3): (i == 1 ? 9 : 10);
|
|
||||||
case EAST -> axis == Axis.Y ? (i == 1 ? 4 : 7): (i == 1 ? 8 : 9 );
|
|
||||||
case WEST -> axis == Axis.Y ? (i == 1 ? 5 : 6): (i == 1 ? 10 : 11);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
|
||||||
Identifier step_id = ReFramed.id("double_step_special");
|
|
||||||
Identifier step_side_id = ReFramed.id("double_step_side_special");
|
|
||||||
return MultipartBlockStateSupplier.create(this)
|
|
||||||
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.X),
|
|
||||||
GBlockstate.variant(step_id, true, R0, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.Z),
|
|
||||||
GBlockstate.variant(step_id, true, R0, R90))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.X),
|
|
||||||
GBlockstate.variant(step_id, true, R180, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.Z),
|
|
||||||
GBlockstate.variant(step_id, true, R180, R90))
|
|
||||||
|
|
||||||
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Z),
|
|
||||||
GBlockstate.variant(step_side_id, true, R0, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Y),
|
|
||||||
GBlockstate.variant(step_side_id, true, R90, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.X),
|
|
||||||
GBlockstate.variant(step_side_id, true, R0, R90))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.Y),
|
|
||||||
GBlockstate.variant(step_side_id, true, R90, R90))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Z),
|
|
||||||
GBlockstate.variant(step_side_id, true, R0, R180))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Y),
|
|
||||||
GBlockstate.variant(step_side_id, true, R90, R180))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Axis.X),
|
|
||||||
GBlockstate.variant(step_side_id, true, R0, R270))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Axis.Y),
|
|
||||||
GBlockstate.variant(step_side_id, true, R90, R270));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
|
||||||
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
|
|
||||||
ShapelessRecipeJsonBuilder
|
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this)
|
|
||||||
.input(ReFramed.STEP, 2)
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.util.BlockProperties;
|
import fr.adrien1106.reframed.util.blocks.BlockProperties;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@@ -27,7 +27,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
//Keeping the weight of this block entity down, both in terms of memory consumption and NBT sync traffic,
|
//Keeping the weight of this block entity down, both in terms of memory consumption and NBT sync traffic,
|
||||||
//is pretty important since players might place a lot of them. There were tons and tons of these at Blanketcon.
|
//is pretty important since players might place a lot of them. There were tons and tons of these at Blanketcon.
|
||||||
//To that end, most of the state has been crammed into a bitfield.
|
//To that end, most of the state_key has been crammed into a bitfield.
|
||||||
public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity {
|
public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity {
|
||||||
protected BlockState first_state = Blocks.AIR.getDefaultState();
|
protected BlockState first_state = Blocks.AIR.getDefaultState();
|
||||||
protected byte bit_field = SOLIDITY_MASK;
|
protected byte bit_field = SOLIDITY_MASK;
|
||||||
@@ -47,7 +47,7 @@ public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity
|
|||||||
public void readNbt(NbtCompound nbt) {
|
public void readNbt(NbtCompound nbt) {
|
||||||
super.readNbt(nbt);
|
super.readNbt(nbt);
|
||||||
|
|
||||||
BlockState rendered_state = first_state; // keep previous state to check if rerender is needed
|
BlockState rendered_state = first_state; // keep previous state_key to check if rerender is needed
|
||||||
first_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 1));
|
first_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 1));
|
||||||
if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY);
|
if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.FenceGateBlock;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.item.LeadItem;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class ReFramedFenceBlock extends ConnectingReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] FENCE_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedFenceBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean connectsTo(BlockState state, boolean fs, Direction dir) {
|
||||||
|
return fs || state.isIn(BlockTags.FENCES)
|
||||||
|
|| (state.getBlock() instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[0];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[5];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() + 4]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCameraCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getOutlineShape(state, world, pos, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
||||||
|
return getOutlineShape(state, view, pos, ShapeContext.absent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
if (world.isClient) {
|
||||||
|
ItemStack itemStack = player.getStackInHand(hand);
|
||||||
|
return itemStack.isOf(Items.LEAD) ? ActionResult.SUCCESS : ActionResult.PASS;
|
||||||
|
} else {
|
||||||
|
return LeadItem.attachHeldMobsToBlock(player, world, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape POST = createCuboidShape(6, 0, 6, 10, 16, 10);
|
||||||
|
VoxelShape POST_COLLISION = createCuboidShape(6, 0, 6, 10, 24, 10);
|
||||||
|
VoxelShape SIDE = VoxelShapes.combineAndSimplify(
|
||||||
|
createCuboidShape(7, 12, 0, 9, 15, 6),
|
||||||
|
createCuboidShape(7, 6, 0, 9, 9, 6),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
VoxelShape SIDE_COLLISION = createCuboidShape(7, 0, 0, 9, 24, 6);
|
||||||
|
FENCE_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 5)
|
||||||
|
.add(SIDE)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(POST_COLLISION)
|
||||||
|
.add(SIDE_COLLISION)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.*;
|
||||||
|
import static net.minecraft.state.property.Properties.WATERLOGGED;
|
||||||
|
|
||||||
|
public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] HALF_STAIR_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedHalfStairBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN).with(CORNER_FACE, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(CORNER,CORNER_FACE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||||
|
if (context.getPlayer() == null) return false;
|
||||||
|
Direction dir = state.get(CORNER).getDirection(state.get(CORNER_FACE));
|
||||||
|
return !(
|
||||||
|
context.getPlayer().isSneaking()
|
||||||
|
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|
||||||
|
|| (
|
||||||
|
!(
|
||||||
|
block_item.getBlock() == this
|
||||||
|
&& ((ReFramedHalfStairsStairBlock) ReFramed.HALF_STAIRS_STAIR)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.HALF_STAIRS_STAIR.getDefaultState()
|
||||||
|
.with(EDGE, state.get(CORNER).getEdge(dir)),
|
||||||
|
dir.getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
&& !(
|
||||||
|
block_item.getBlock() == ReFramed.SMALL_CUBE
|
||||||
|
&& BlockHelper.cursorMatchesFace(
|
||||||
|
ReFramed.SMALL_CUBE.getOutlineShape(
|
||||||
|
ReFramed.SMALL_CUBE.getDefaultState()
|
||||||
|
.with(CORNER, state.get(CORNER).getOpposite(state.get(CORNER_FACE))),
|
||||||
|
context.getWorld(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ShapeContext.absent()
|
||||||
|
),
|
||||||
|
BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos());
|
||||||
|
if (current_state.isOf(ReFramed.SMALL_CUBE)) {
|
||||||
|
Corner corner = current_state.get(CORNER).getOpposite(ctx.getSide().getOpposite());
|
||||||
|
return ReFramed.HALF_STAIRS_SLAB.getDefaultState()
|
||||||
|
.with(CORNER, corner)
|
||||||
|
.with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite()))
|
||||||
|
.with(WATERLOGGED, current_state.get(WATERLOGGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_state.isOf(this))
|
||||||
|
return ReFramed.HALF_STAIRS_STAIR.getDefaultState()
|
||||||
|
.with(EDGE, current_state.get(CORNER).getEdge(current_state.get(CORNER).getDirection(current_state.get(CORNER_FACE))))
|
||||||
|
.with(WATERLOGGED, current_state.get(WATERLOGGED));
|
||||||
|
|
||||||
|
Corner corner = BlockHelper.getPlacementCorner(ctx);
|
||||||
|
return super.getPlacementState(ctx)
|
||||||
|
.with(CORNER, corner)
|
||||||
|
.with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return HALF_STAIR_VOXELS[state.get(CORNER_FACE) + state.get(CORNER).getID() * 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
Corner corner = state.get(CORNER).rotate(rotation);
|
||||||
|
Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE));
|
||||||
|
return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(rotation.rotate(face)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
Corner corner = state.get(CORNER).mirror(mirror);
|
||||||
|
Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE));
|
||||||
|
return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(mirror.apply(face)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
|
||||||
|
if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 1);
|
||||||
|
if (new_state.isOf(ReFramed.HALF_STAIRS_STAIR))
|
||||||
|
return Map.of(
|
||||||
|
1,
|
||||||
|
state.get(CORNER)
|
||||||
|
.getDirection(state.get(CORNER_FACE))
|
||||||
|
.getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1
|
||||||
|
);
|
||||||
|
return super.getThemeMap(state, new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
final VoxelShape HALF_STAIR = VoxelShapes.combineAndSimplify(
|
||||||
|
createCuboidShape(8, 0, 0, 16, 16, 8),
|
||||||
|
createCuboidShape(0, 0, 0, 8, 8, 8),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
HALF_STAIR_VOXELS = VoxelListBuilder.create(HALF_STAIR, 24)
|
||||||
|
.add(0 , VoxelHelper::rotateY, VoxelHelper::mirrorZ)
|
||||||
|
.add(0 , VoxelHelper::rotateCX, VoxelHelper::mirrorZ)
|
||||||
|
|
||||||
|
.add(0 , VoxelHelper::rotateY)
|
||||||
|
.add(1 , VoxelHelper::rotateY)
|
||||||
|
.add(2 , VoxelHelper::rotateY)
|
||||||
|
|
||||||
|
.add(3 , VoxelHelper::rotateY)
|
||||||
|
.add(4 , VoxelHelper::rotateY)
|
||||||
|
.add(5 , VoxelHelper::rotateY)
|
||||||
|
|
||||||
|
.add(6 , VoxelHelper::rotateY)
|
||||||
|
.add(7 , VoxelHelper::rotateY)
|
||||||
|
.add(8 , VoxelHelper::rotateY)
|
||||||
|
|
||||||
|
.add(0 , VoxelHelper::mirrorY)
|
||||||
|
.add(1 , VoxelHelper::mirrorY)
|
||||||
|
.add(2 , VoxelHelper::mirrorY)
|
||||||
|
|
||||||
|
.add(12, VoxelHelper::rotateY)
|
||||||
|
.add(13, VoxelHelper::rotateY)
|
||||||
|
.add(14, VoxelHelper::rotateY)
|
||||||
|
|
||||||
|
.add(15, VoxelHelper::rotateY)
|
||||||
|
.add(16, VoxelHelper::rotateY)
|
||||||
|
.add(17, VoxelHelper::rotateY)
|
||||||
|
|
||||||
|
.add(18, VoxelHelper::rotateY)
|
||||||
|
.add(19, VoxelHelper::rotateY)
|
||||||
|
.add(20, VoxelHelper::rotateY)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.HALF_STAIR_VOXELS;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedSmallCubeBlock.SMALL_CUBE_VOXELS;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER_FACE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.NORTH_EAST_DOWN;
|
||||||
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
|
public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedHalfStairsSlabBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN).with(CORNER_FACE, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(CORNER,CORNER_FACE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
Corner corner = BlockHelper.getPlacementCorner(ctx);
|
||||||
|
return super.getPlacementState(ctx)
|
||||||
|
.with(CORNER, corner)
|
||||||
|
.with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
return isGhost(view, pos) ? empty(): getSlabShape(state.get(CORNER).getDirection(state.get(CORNER_FACE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getSlabShape(state.get(CORNER).getDirection(state.get(CORNER_FACE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
Corner corner = state.get(CORNER).rotate(rotation);
|
||||||
|
Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE));
|
||||||
|
return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(rotation.rotate(face)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
Corner corner = state.get(CORNER).mirror(mirror);
|
||||||
|
Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE));
|
||||||
|
return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(mirror.apply(face)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
Corner corner = state.get(CORNER);
|
||||||
|
int face = state.get(CORNER_FACE);
|
||||||
|
return i == 2
|
||||||
|
? SMALL_CUBE_VOXELS[corner.getOpposite(face).getID()]
|
||||||
|
: HALF_STAIR_VOXELS[face + corner.getID() * 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Edge;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.StairShape;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.HALF_STAIR_VOXELS;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedStairBlock.getStairShape;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.*;
|
||||||
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
|
public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
public ReFramedHalfStairsStairBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(EDGE, NORTH_DOWN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EDGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
return isGhost(view, pos) ? empty(): getStairShape(state.get(EDGE), StairShape.STRAIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getStairShape(state.get(EDGE), StairShape.STRAIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(EDGE, state.get(EDGE).rotate(rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(EDGE, state.get(EDGE).mirror(mirror));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
Edge edge = state.get(EDGE);
|
||||||
|
Direction side = i == 1
|
||||||
|
? edge.getRightDirection()
|
||||||
|
: edge.getLeftDirection();
|
||||||
|
Corner corner = Corner.getByDirections(
|
||||||
|
edge.getFirstDirection(),
|
||||||
|
edge.getSecondDirection(),
|
||||||
|
side
|
||||||
|
|
||||||
|
);
|
||||||
|
return HALF_STAIR_VOXELS[corner.getID() * 3 + corner.getDirectionIndex(side)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopThemeIndex(BlockState state) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.loot.context.LootContextParameterSet;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
|
import static net.minecraft.state.property.Properties.LAYERS;
|
||||||
|
|
||||||
|
public class ReFramedLayerBlock extends ReFramedSlabBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] LAYER_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedLayerBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(LAYERS, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDroppedStacks(BlockState state, LootContextParameterSet.Builder builder) {
|
||||||
|
List<ItemStack> drops = super.getDroppedStacks(state, builder);
|
||||||
|
drops.forEach((stack) -> {
|
||||||
|
if (stack.getItem() instanceof BlockItem bi && bi.getBlock() instanceof ReFramedLayerBlock)
|
||||||
|
stack.setCount(state.get(LAYERS));
|
||||||
|
});
|
||||||
|
return drops;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(LAYERS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return LAYER_VOXELS[state.get(FACING).getId() * 8 + state.get(LAYERS) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||||
|
if (context.getPlayer() == null) return false;
|
||||||
|
return !(
|
||||||
|
context.getPlayer().isSneaking()
|
||||||
|
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|
||||||
|
|| !(block_item.getBlock() == this && state.get(LAYERS) < 8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState previous = ctx.getWorld().getBlockState(ctx.getBlockPos());
|
||||||
|
if (!previous.isOf(this)) return super.getPlacementState(ctx);
|
||||||
|
return previous.with(LAYERS, previous.get(LAYERS) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(FACING, rotation.rotate(state.get(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(FACING, mirror.apply(state.get(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelListBuilder builder = VoxelListBuilder.create(createCuboidShape(0, 0, 0, 16, 2, 16), 48)
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 4, 16))
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 6, 16))
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 8, 16))
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 10, 16))
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 12, 16))
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 14, 16))
|
||||||
|
.add(createCuboidShape(0, 0, 0, 16, 16, 16));
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
builder.add(i, VoxelHelper::mirrorY);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
builder.add(i, VoxelHelper::rotateX);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
builder.add(i, VoxelHelper::rotateCX);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
builder.add(i, VoxelHelper::rotateCZ);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
builder.add(i, VoxelHelper::rotateZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAYER_VOXELS = builder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.PaneBlock;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
|
||||||
|
public class ReFramedPaneBlock extends ConnectingReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] PANE_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedPaneBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = PANE_VOXELS[0];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, PANE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean connectsTo(BlockState state, boolean fs, Direction dir) {
|
||||||
|
return !cannotConnect(state) && fs || state.getBlock() instanceof PaneBlock || state.isIn(BlockTags.WALLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape POST = createCuboidShape(7, 0, 7, 9, 16, 9);
|
||||||
|
VoxelShape SIDE = createCuboidShape(7, 0, 0, 9, 16, 7);
|
||||||
|
PANE_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 5)
|
||||||
|
.add(SIDE)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class ReFramedPillarBlock extends PillarReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] PILLAR_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedPillarBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getPillarShape(state.get(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VoxelShape getPillarShape(Direction.Axis axis) {
|
||||||
|
return PILLAR_VOXELS[axis.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
final VoxelShape PILLAR = createCuboidShape(0, 4, 4, 16, 12, 12);
|
||||||
|
PILLAR_VOXELS = VoxelHelper.VoxelListBuilder.create(PILLAR, 3)
|
||||||
|
.add(VoxelHelper::rotateZ)
|
||||||
|
.add(VoxelHelper::rotateX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.block.enums.WallShape;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedWallBlock.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
|
public class ReFramedPillarsWallBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedPillarsWallBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(EAST_WALL_SHAPE, WallShape.NONE)
|
||||||
|
.with(NORTH_WALL_SHAPE, WallShape.NONE)
|
||||||
|
.with(WEST_WALL_SHAPE, WallShape.NONE)
|
||||||
|
.with(SOUTH_WALL_SHAPE, WallShape.NONE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
BlockState top_state = dir == Direction.UP? other_state: world.getBlockState(pos.up());
|
||||||
|
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
||||||
|
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
||||||
|
Map<Direction, BlockState> neighbors = Direction.Type.HORIZONTAL.stream()
|
||||||
|
.collect(Collectors.toMap(d -> d, d -> {
|
||||||
|
if (d == dir) return other_state;
|
||||||
|
return world.getBlockState(pos.offset(d));
|
||||||
|
}));
|
||||||
|
return getWallState(new_state, top_state, neighbors, top_shape, fs, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
|
||||||
|
BlockState top_state = world.getBlockState(pos.up());
|
||||||
|
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
||||||
|
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
||||||
|
|
||||||
|
Map<Direction, BlockState> neighbors = Direction.Type.HORIZONTAL.stream()
|
||||||
|
.collect(Collectors.toMap(d -> d, d -> world.getBlockState(pos.offset(d))));
|
||||||
|
return getWallState(state, top_state, neighbors, top_shape, fs, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
if (isGhost(view, pos)) return empty();
|
||||||
|
VoxelShape shape = WALL_VOXELS[9];
|
||||||
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getWallShape(dir)) != WallShape.NONE)
|
||||||
|
shape = VoxelShapes.union(shape, WALL_VOXELS[8 + dir.ordinal()]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
||||||
|
return isGhost(view, pos) ? empty(): getOutlineShape(state, view, pos, ShapeContext.absent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = WALL_VOXELS[0];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
WallShape wall_shape = state.get(getWallShape(dir));
|
||||||
|
if (wall_shape != WallShape.NONE)
|
||||||
|
shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getWallShape(rotation.rotate(dir)), state.get(getWallShape(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getWallShape(mirror.apply(dir)), state.get(getWallShape(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
if (i == 1) return WALL_VOXELS[0];
|
||||||
|
VoxelShape shape = VoxelShapes.empty();
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
WallShape wall_shape = state.get(getWallShape(dir));
|
||||||
|
if (wall_shape != WallShape.NONE)
|
||||||
|
shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class ReFramedPostBlock extends PillarReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] POST_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedPostBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getPillarShape(state.get(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VoxelShape getPillarShape(Direction.Axis axis) {
|
||||||
|
return POST_VOXELS[axis.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
final VoxelShape POST = createCuboidShape(0, 6, 6, 16, 10, 10);
|
||||||
|
POST_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 3)
|
||||||
|
.add(VoxelHelper::rotateZ)
|
||||||
|
.add(VoxelHelper::rotateX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.FenceGateBlock;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.item.LeadItem;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ConnectingReFramedBlock.getConnectionProperty;
|
||||||
|
import static fr.adrien1106.reframed.block.ConnectingReFramedBlock.placementState;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedFenceBlock.FENCE_VOXELS;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
import static net.minecraft.state.property.Properties.WEST;
|
||||||
|
|
||||||
|
public class ReFramedPostFenceBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedPostFenceBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(EAST, false)
|
||||||
|
.with(NORTH, false)
|
||||||
|
.with(WEST, false)
|
||||||
|
.with(SOUTH, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EAST, NORTH, SOUTH, WEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
|
||||||
|
return placementState(new_state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
|
||||||
|
return placementState(state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(rotation.rotate(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(mirror.apply(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean connectsTo(BlockState state, boolean fs, Direction dir) {
|
||||||
|
return fs || state.isIn(BlockTags.FENCES)
|
||||||
|
|| (state.getBlock() instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
if (i == 1) return FENCE_VOXELS[0];
|
||||||
|
VoxelShape shape = VoxelShapes.empty();
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[0];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[5];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() + 4]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCameraCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getOutlineShape(state, world, pos, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
||||||
|
return getOutlineShape(state, view, pos, ShapeContext.absent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
if (world.isClient) {
|
||||||
|
ItemStack itemStack = player.getStackInHand(hand);
|
||||||
|
return itemStack.isOf(Items.LEAD) ? ActionResult.SUCCESS : ActionResult.PASS;
|
||||||
|
} else {
|
||||||
|
return LeadItem.attachHeldMobsToBlock(player, world, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
|
||||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
|
||||||
import net.minecraft.state.StateManager;
|
import net.minecraft.state.StateManager;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
@@ -22,10 +16,12 @@ import net.minecraft.util.shape.VoxelShapes;
|
|||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
import static net.minecraft.state.property.Properties.FACING;
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
|
|
||||||
public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
public class ReFramedSlabBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
protected static final VoxelShape DOWN = VoxelShapes.cuboid(0f, 0f, 0f, 1f, 0.5f, 1f);
|
protected static final VoxelShape DOWN = VoxelShapes.cuboid(0f, 0f, 0f, 1f, 0.5f, 1f);
|
||||||
protected static final VoxelShape UP = VoxelShapes.cuboid(0f, 0.5f, 0f, 1f, 1f, 1f);
|
protected static final VoxelShape UP = VoxelShapes.cuboid(0f, 0.5f, 0f, 1f, 1f, 1f);
|
||||||
@@ -43,10 +39,34 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(FACING));
|
super.appendProperties(builder.add(FACING));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||||
|
if (context.getPlayer() == null) return false;
|
||||||
|
return !(
|
||||||
|
context.getPlayer().isSneaking()
|
||||||
|
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|
||||||
|
|| !(
|
||||||
|
block_item.getBlock() == this
|
||||||
|
&& ((ReFramedSlabsCubeBlock) ReFramed.SLABS_CUBE)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.SLABS_CUBE.getDefaultState().with(AXIS, state.get(FACING).getAxis()),
|
||||||
|
state.get(FACING).getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos());
|
||||||
|
if (current_state.isOf(this))
|
||||||
|
return ReFramed.SLABS_CUBE.getDefaultState()
|
||||||
|
.with(AXIS, current_state.get(FACING).getAxis());
|
||||||
|
|
||||||
return super.getPlacementState(ctx).with(FACING, ctx.getSide().getOpposite());
|
return super.getPlacementState(ctx).with(FACING, ctx.getSide().getOpposite());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +75,16 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
return getSlabShape(state.get(FACING));
|
return getSlabShape(state.get(FACING));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(FACING, rotation.rotate(state.get(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(FACING, mirror.apply(state.get(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
public static VoxelShape getSlabShape(Direction side) {
|
public static VoxelShape getSlabShape(Direction side) {
|
||||||
return switch (side) {
|
return switch (side) {
|
||||||
case DOWN -> DOWN;
|
case DOWN -> DOWN;
|
||||||
@@ -67,32 +97,8 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
|
||||||
Identifier model_id = ReFramed.id("slab_special");
|
if (new_state.isOf(ReFramed.SLABS_CUBE)) return Map.of(1, state.get(FACING).getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1);
|
||||||
return MultipartBlockStateSupplier.create(this)
|
return super.getThemeMap(state, new_state);
|
||||||
.with(GBlockstate.when(FACING, Direction.DOWN),
|
|
||||||
GBlockstate.variant(model_id, true, R0, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.SOUTH),
|
|
||||||
GBlockstate.variant(model_id, true, R90, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.UP),
|
|
||||||
GBlockstate.variant(model_id, true, R180, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.NORTH),
|
|
||||||
GBlockstate.variant(model_id, true, R270, R0))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.WEST),
|
|
||||||
GBlockstate.variant(model_id, true, R90, R90))
|
|
||||||
.with(GBlockstate.when(FACING, Direction.EAST),
|
|
||||||
GBlockstate.variant(model_id, true, R90, R270));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
|
||||||
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
|
|
||||||
ShapedRecipeJsonBuilder
|
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this, 6)
|
|
||||||
.pattern("III")
|
|
||||||
.input('I', ReFramed.CUBE)
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedSlabsCubeBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(AXIS, mirror.apply(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
return switch (state.get(AXIS)) {
|
||||||
|
case Y -> i == 2 ? UP : DOWN;
|
||||||
|
case Z -> i == 2 ? SOUTH : NORTH;
|
||||||
|
case X -> i == 2 ? EAST : WEST;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopThemeIndex(BlockState state) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.*;
|
||||||
|
import static net.minecraft.state.property.Properties.WATERLOGGED;
|
||||||
|
|
||||||
|
public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] SMALL_CUBE_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedSmallCubeBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(CORNER));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||||
|
if (context.getPlayer() == null) return false;
|
||||||
|
Corner corner = state.get(CORNER);
|
||||||
|
return !(
|
||||||
|
context.getPlayer().isSneaking()
|
||||||
|
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|
||||||
|
|| (
|
||||||
|
!(
|
||||||
|
block_item.getBlock() == ReFramed.HALF_STAIR
|
||||||
|
&& !(corner.hasDirection(context.getSide())
|
||||||
|
|| (corner.hasDirection(context.getSide().getOpposite())
|
||||||
|
&& BlockHelper.cursorMatchesFace(
|
||||||
|
getOutlineShape(state, context.getWorld(), context.getBlockPos(), null),
|
||||||
|
BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
&& !(
|
||||||
|
block_item.getBlock() == this
|
||||||
|
&& (
|
||||||
|
((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.SMALL_CUBES_STEP.getDefaultState().with(EDGE, corner.getEdge(corner.getFirstDirection())),
|
||||||
|
corner.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
|| ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.SMALL_CUBES_STEP.getDefaultState().with(EDGE, corner.getEdge(corner.getSecondDirection())),
|
||||||
|
corner.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
|| ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.SMALL_CUBES_STEP.getDefaultState().with(EDGE, corner.getEdge(corner.getThirdDirection())),
|
||||||
|
corner.getThirdDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
BlockState current_state = ctx.getWorld().getBlockState(pos);
|
||||||
|
if (current_state.isOf(ReFramed.HALF_STAIR))
|
||||||
|
return ReFramed.HALF_STAIRS_SLAB.getDefaultState()
|
||||||
|
.with(CORNER, current_state.get(CORNER))
|
||||||
|
.with(CORNER_FACE, current_state.get(CORNER_FACE))
|
||||||
|
.with(WATERLOGGED, current_state.get(WATERLOGGED));
|
||||||
|
|
||||||
|
|
||||||
|
if (current_state.isOf(this)) {
|
||||||
|
Vec3d hit = ctx.getHitPos();
|
||||||
|
Corner corner = current_state.get(CORNER);
|
||||||
|
ReFramedSmallCubesStepBlock block = ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP);
|
||||||
|
BlockState state = block.getDefaultState()
|
||||||
|
.with(EDGE, corner.getEdge(corner.getFirstDirection()))
|
||||||
|
.with(WATERLOGGED, current_state.get(WATERLOGGED));
|
||||||
|
if (block.matchesShape(
|
||||||
|
hit, pos, state,
|
||||||
|
corner.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)) return state;
|
||||||
|
state = state.with(EDGE, corner.getEdge(corner.getSecondDirection()));
|
||||||
|
if (block.matchesShape(
|
||||||
|
hit, pos, state,
|
||||||
|
corner.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)) return state;
|
||||||
|
return state.with(EDGE, corner.getEdge(corner.getThirdDirection()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return SMALL_CUBE_VOXELS[state.get(CORNER).getID()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(CORNER, state.get(CORNER).rotate(rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(CORNER, state.get(CORNER).mirror(mirror));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
|
||||||
|
if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 2);
|
||||||
|
if (new_state.isOf(ReFramed.SMALL_CUBES_STEP))
|
||||||
|
return Map.of(
|
||||||
|
1,
|
||||||
|
state.get(CORNER)
|
||||||
|
.getOtherDirection(new_state.get(EDGE))
|
||||||
|
.getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1
|
||||||
|
);
|
||||||
|
return super.getThemeMap(state, new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
final VoxelShape SMALL_CUBE = VoxelShapes.cuboid(.5f, 0f, 0f, 1f, .5f, .5f);
|
||||||
|
|
||||||
|
SMALL_CUBE_VOXELS = VoxelListBuilder.create(SMALL_CUBE, 8)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
|
||||||
|
.add(SMALL_CUBE, VoxelHelper::mirrorY)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Edge;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedSmallCubeBlock.SMALL_CUBE_VOXELS;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
|
public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedSmallCubesStepBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EDGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
return isGhost(view, pos) ? empty(): getStepShape(state.get(EDGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getStepShape(state.get(EDGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(EDGE, state.get(EDGE).rotate(rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(EDGE, state.get(EDGE).mirror(mirror));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
Edge edge = state.get(EDGE);
|
||||||
|
return SMALL_CUBE_VOXELS[Corner.getByDirections(
|
||||||
|
edge.getFirstDirection(),
|
||||||
|
edge.getSecondDirection(),
|
||||||
|
i == 1
|
||||||
|
? edge.getRightDirection()
|
||||||
|
: edge.getLeftDirection()
|
||||||
|
).getID()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopThemeIndex(BlockState state) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Edge;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.StairShape;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
|
||||||
|
|
||||||
|
public class ReFramedStairBlock extends WaterloggableReFramedBlock {
|
||||||
|
public static final VoxelShape[] STAIR_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedStairBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EDGE, STAIR_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||||
|
if (context.getPlayer() == null) return false;
|
||||||
|
return !(
|
||||||
|
context.getPlayer().isSneaking()
|
||||||
|
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|
||||||
|
|| !(
|
||||||
|
block_item.getBlock() == ReFramed.STEP
|
||||||
|
&& ((ReFramedStairsCubeBlock) ReFramed.STAIRS_CUBE)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
state,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighbor_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
return super.getStateForNeighborUpdate(state, direction, neighbor_state, world, pos, moved)
|
||||||
|
.with(STAIR_SHAPE, BlockHelper.getStairsShape(state.get(EDGE), world, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos());
|
||||||
|
if (current_state.isOf(ReFramed.STEP)) {
|
||||||
|
Edge edge = current_state.get(EDGE).opposite();
|
||||||
|
StairShape shape = BlockHelper.getStairsShape(edge, ctx.getWorld(), ctx.getBlockPos());
|
||||||
|
return ReFramed.STAIRS_CUBE.getDefaultState()
|
||||||
|
.with(EDGE, edge)
|
||||||
|
.with(STAIR_SHAPE, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge edge = BlockHelper.getPlacementEdge(ctx);
|
||||||
|
StairShape shape = BlockHelper.getStairsShape(edge, ctx.getWorld(), ctx.getBlockPos());
|
||||||
|
return super.getPlacementState(ctx).with(EDGE, edge).with(STAIR_SHAPE, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getStairShape(state.get(EDGE), state.get(STAIR_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
Edge prev_edge = state.get(EDGE);
|
||||||
|
Edge edge = prev_edge.rotate(rotation);
|
||||||
|
if (prev_edge.getAxis() == Direction.Axis.Y) return state.with(EDGE, edge);
|
||||||
|
|
||||||
|
if (prev_edge.getFace().getDirection() == edge.getFace().getDirection()) // 90° rotations
|
||||||
|
state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror());
|
||||||
|
else state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).flip());
|
||||||
|
|
||||||
|
if (prev_edge.getAxis() == edge.getAxis()) // 180° rotation
|
||||||
|
state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror());
|
||||||
|
|
||||||
|
return state.with(EDGE, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
Edge prev_edge = state.get(EDGE);
|
||||||
|
Edge edge = prev_edge.mirror(mirror);
|
||||||
|
return state
|
||||||
|
.with(STAIR_SHAPE, prev_edge == edge ? state.get(STAIR_SHAPE).mirror() : state.get(STAIR_SHAPE).flip())
|
||||||
|
.with(EDGE, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VoxelShape getStairShape(Edge edge, StairShape shape) {
|
||||||
|
return STAIR_VOXELS[edge.getID() * 9 + shape.getID()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
|
||||||
|
if (new_state.isOf(ReFramed.STAIRS_CUBE)) return Map.of(1, 1);
|
||||||
|
return super.getThemeMap(state, new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
final VoxelShape STRAIGHT = VoxelShapes.combineAndSimplify(
|
||||||
|
createCuboidShape(0, 8, 0, 16, 16, 8),
|
||||||
|
createCuboidShape(0, 0, 0, 16, 8, 16),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
final VoxelShape INNER = Stream.of(
|
||||||
|
createCuboidShape(0, 8, 0, 16, 16, 8),
|
||||||
|
createCuboidShape(0, 8, 8, 8, 16, 16),
|
||||||
|
createCuboidShape(0, 0, 0, 16, 8, 16)
|
||||||
|
).reduce((v1, v2) -> VoxelShapes.combineAndSimplify(v1, v2, BooleanBiFunction.OR)).get();
|
||||||
|
final VoxelShape OUTER = Stream.of(
|
||||||
|
createCuboidShape(0, 8, 0, 8, 16, 8),
|
||||||
|
createCuboidShape(8, 0, 0, 16, 8, 8),
|
||||||
|
createCuboidShape(0, 0, 0, 8, 8, 16)
|
||||||
|
).reduce((v1, v2) -> VoxelShapes.combineAndSimplify(v1, v2, BooleanBiFunction.OR)).get();
|
||||||
|
final VoxelShape JUNCTION = VoxelShapes.combineAndSimplify(
|
||||||
|
createCuboidShape(0, 8, 0, 8, 16, 8),
|
||||||
|
createCuboidShape(0, 0, 0, 16, 8, 16),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
|
||||||
|
STAIR_VOXELS = VoxelListBuilder.create(STRAIGHT, 108)
|
||||||
|
.add(INNER).add(VoxelHelper::rotateY)
|
||||||
|
.add(OUTER).add(VoxelHelper::rotateY)
|
||||||
|
.add(JUNCTION).add(VoxelHelper::rotateY)
|
||||||
|
.add(JUNCTION, VoxelHelper::rotateX, VoxelHelper::rotateZ).add(VoxelHelper::rotateZ)
|
||||||
|
// DOWN_SOUTH
|
||||||
|
.add(0, VoxelHelper::rotateCX)
|
||||||
|
.add(1, VoxelHelper::rotateCX).add(2, VoxelHelper::rotateCX)
|
||||||
|
.add(3, VoxelHelper::rotateCX).add(4, VoxelHelper::rotateCX)
|
||||||
|
.add(5, VoxelHelper::rotateCX).add(6, VoxelHelper::rotateCX)
|
||||||
|
.add(7, VoxelHelper::rotateCX).add(8, VoxelHelper::rotateCX)
|
||||||
|
// SOUTH_UP
|
||||||
|
.add(9, VoxelHelper::rotateCX)
|
||||||
|
.add(10, VoxelHelper::rotateCX).add(11, VoxelHelper::rotateCX)
|
||||||
|
.add(12, VoxelHelper::rotateCX).add(13, VoxelHelper::rotateCX)
|
||||||
|
.add(14, VoxelHelper::rotateCX).add(15, VoxelHelper::rotateCX)
|
||||||
|
.add(16, VoxelHelper::rotateCX).add(17, VoxelHelper::rotateCX)
|
||||||
|
// UP_NORTH
|
||||||
|
.add(18, VoxelHelper::rotateCX)
|
||||||
|
.add(19, VoxelHelper::rotateCX).add(20, VoxelHelper::rotateCX)
|
||||||
|
.add(21, VoxelHelper::rotateCX).add(22, VoxelHelper::rotateCX)
|
||||||
|
.add(23, VoxelHelper::rotateCX).add(24, VoxelHelper::rotateCX)
|
||||||
|
.add(25, VoxelHelper::rotateCX).add(26, VoxelHelper::rotateCX)
|
||||||
|
// WEST_DOWN
|
||||||
|
.add(0, VoxelHelper::rotateCY)
|
||||||
|
.add(1).add(10)
|
||||||
|
.add(3).add(12)
|
||||||
|
.add(5).add(16)
|
||||||
|
.add(8, VoxelHelper::rotateCY).add(7, VoxelHelper::rotateCY)
|
||||||
|
// DOWN_EAST
|
||||||
|
.add(36, VoxelHelper::rotateZ)
|
||||||
|
.add(2).add(11)
|
||||||
|
.add(4).add(13)
|
||||||
|
.add(41, VoxelHelper::rotateZ).add(42, VoxelHelper::rotateZ)
|
||||||
|
.add(6).add(17)
|
||||||
|
// EAST_UP
|
||||||
|
.add(45, VoxelHelper::rotateZ)
|
||||||
|
.add(29).add(20)
|
||||||
|
.add(31).add(22)
|
||||||
|
.add(35).add(24)
|
||||||
|
.add(52, VoxelHelper::rotateZ).add(53, VoxelHelper::rotateZ)
|
||||||
|
// UP_WEST
|
||||||
|
.add(54, VoxelHelper::rotateZ)
|
||||||
|
.add(28).add(19)
|
||||||
|
.add(30).add(21)
|
||||||
|
.add(59, VoxelHelper::rotateZ).add(60, VoxelHelper::rotateZ)
|
||||||
|
.add(34).add(23)
|
||||||
|
// WEST_NORTH
|
||||||
|
.add(0, VoxelHelper::rotateCZ)
|
||||||
|
.add(1).add(28)
|
||||||
|
.add(3).add(30)
|
||||||
|
.add(7).add(32)
|
||||||
|
.add(43).add(68)
|
||||||
|
// NORTH_EAST
|
||||||
|
.add(72, VoxelHelper::rotateY)
|
||||||
|
.add(2).add(29)
|
||||||
|
.add(4).add(31)
|
||||||
|
.add(50).add(61)
|
||||||
|
.add(8).add(33)
|
||||||
|
// EAST_SOUTH
|
||||||
|
.add(81, VoxelHelper::rotateY)
|
||||||
|
.add(11).add(20)
|
||||||
|
.add(13).add(22)
|
||||||
|
.add(15).add(26)
|
||||||
|
.add(51).add(62)
|
||||||
|
// SOUTH_WEST
|
||||||
|
.add(90, VoxelHelper::rotateY)
|
||||||
|
.add(10).add(19)
|
||||||
|
.add(12).add(21)
|
||||||
|
.add(44).add(69)
|
||||||
|
.add(14).add(25)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,525 +0,0 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
|
||||||
import fr.adrien1106.reframed.util.VoxelHelper;
|
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.block.ShapeContext;
|
|
||||||
import net.minecraft.data.client.*;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
|
||||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
|
||||||
import net.minecraft.state.StateManager;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.function.BooleanBiFunction;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.math.Direction.Axis;
|
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
|
||||||
import net.minecraft.world.BlockView;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraft.world.WorldAccess;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.*;
|
|
||||||
import static fr.adrien1106.reframed.util.property.StairShape.*;
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
|
||||||
import static fr.adrien1106.reframed.util.property.Corner.*;
|
|
||||||
|
|
||||||
public class ReFramedStairsBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
|
||||||
|
|
||||||
public static final List<VoxelShape> VOXEL_LIST = new ArrayList<>(52);
|
|
||||||
|
|
||||||
public ReFramedStairsBlock(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
|
||||||
super.appendProperties(builder.add(CORNER, STAIR_SHAPE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighbor_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
|
||||||
return super.getStateForNeighborUpdate(state, direction, neighbor_state, world, pos, moved)
|
|
||||||
.with(STAIR_SHAPE, BlockHelper.getStairsShape(state.getBlock(), state.get(CORNER), world, pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override // Pretty happy of how clean it is (also got it on first try :) )
|
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
|
||||||
Corner face = BlockHelper.getPlacementCorner(ctx);
|
|
||||||
StairShape shape = BlockHelper.getStairsShape(this, face, ctx.getWorld(), ctx.getBlockPos());
|
|
||||||
return super.getPlacementState(ctx).with(CORNER, face).with(STAIR_SHAPE, shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------- DON'T GO FURTHER IF YOU LIKE HAVING EYES ---------------------------------- */
|
|
||||||
@Override
|
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
|
||||||
return getOutline(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VoxelShape getOutline(BlockState state) {
|
|
||||||
StairShape shape = state.get(STAIR_SHAPE);
|
|
||||||
Corner direction = state.get(CORNER);
|
|
||||||
return switch (shape) {
|
|
||||||
case STRAIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_SOUTH -> VOXEL_LIST.get(0);
|
|
||||||
case NORTH_DOWN -> VOXEL_LIST.get(1);
|
|
||||||
case UP_NORTH -> VOXEL_LIST.get(2);
|
|
||||||
case SOUTH_UP -> VOXEL_LIST.get(3);
|
|
||||||
case DOWN_EAST -> VOXEL_LIST.get(4);
|
|
||||||
case WEST_DOWN -> VOXEL_LIST.get(5);
|
|
||||||
case UP_WEST -> VOXEL_LIST.get(6);
|
|
||||||
case EAST_UP -> VOXEL_LIST.get(7);
|
|
||||||
case NORTH_EAST -> VOXEL_LIST.get(8);
|
|
||||||
case EAST_SOUTH -> VOXEL_LIST.get(9);
|
|
||||||
case SOUTH_WEST -> VOXEL_LIST.get(10);
|
|
||||||
case WEST_NORTH -> VOXEL_LIST.get(11);
|
|
||||||
};
|
|
||||||
case INNER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case WEST_DOWN, NORTH_DOWN -> VOXEL_LIST.get(44);
|
|
||||||
case DOWN_EAST -> VOXEL_LIST.get(45);
|
|
||||||
case DOWN_SOUTH -> VOXEL_LIST.get(47);
|
|
||||||
case UP_WEST, UP_NORTH, WEST_NORTH -> VOXEL_LIST.get(48);
|
|
||||||
case EAST_UP, NORTH_EAST -> VOXEL_LIST.get(49);
|
|
||||||
case EAST_SOUTH -> VOXEL_LIST.get(50);
|
|
||||||
case SOUTH_UP, SOUTH_WEST -> VOXEL_LIST.get(51);
|
|
||||||
};
|
|
||||||
case INNER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case WEST_NORTH -> VOXEL_LIST.get(44);
|
|
||||||
case NORTH_DOWN, NORTH_EAST -> VOXEL_LIST.get(45);
|
|
||||||
case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> VOXEL_LIST.get(46);
|
|
||||||
case WEST_DOWN, SOUTH_WEST -> VOXEL_LIST.get(47);
|
|
||||||
case UP_NORTH -> VOXEL_LIST.get(49);
|
|
||||||
case EAST_UP, SOUTH_UP -> VOXEL_LIST.get(50);
|
|
||||||
case UP_WEST -> VOXEL_LIST.get(51);
|
|
||||||
};
|
|
||||||
case OUTER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_EAST -> VOXEL_LIST.get(43);
|
|
||||||
case WEST_DOWN, NORTH_DOWN -> VOXEL_LIST.get(42);
|
|
||||||
case DOWN_SOUTH -> VOXEL_LIST.get(41);
|
|
||||||
case EAST_UP, NORTH_EAST -> VOXEL_LIST.get(39);
|
|
||||||
case UP_WEST, UP_NORTH, WEST_NORTH -> VOXEL_LIST.get(38);
|
|
||||||
case SOUTH_UP, SOUTH_WEST -> VOXEL_LIST.get(37);
|
|
||||||
case EAST_SOUTH -> VOXEL_LIST.get(36);
|
|
||||||
};
|
|
||||||
case OUTER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case NORTH_DOWN, NORTH_EAST -> VOXEL_LIST.get(43);
|
|
||||||
case WEST_NORTH -> VOXEL_LIST.get(42);
|
|
||||||
case WEST_DOWN, SOUTH_WEST -> VOXEL_LIST.get(41);
|
|
||||||
case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> VOXEL_LIST.get(40);
|
|
||||||
case UP_NORTH -> VOXEL_LIST.get(39);
|
|
||||||
case UP_WEST -> VOXEL_LIST.get(37);
|
|
||||||
case EAST_UP, SOUTH_UP -> VOXEL_LIST.get(36);
|
|
||||||
};
|
|
||||||
case FIRST_OUTER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case WEST_DOWN, NORTH_DOWN -> VOXEL_LIST.get(14);
|
|
||||||
case SOUTH_UP -> VOXEL_LIST.get(17);
|
|
||||||
case EAST_UP -> VOXEL_LIST.get(19);
|
|
||||||
case EAST_SOUTH -> VOXEL_LIST.get(20);
|
|
||||||
case DOWN_SOUTH -> VOXEL_LIST.get(22);
|
|
||||||
case UP_NORTH, WEST_NORTH -> VOXEL_LIST.get(25);
|
|
||||||
case SOUTH_WEST -> VOXEL_LIST.get(28);
|
|
||||||
case UP_WEST -> VOXEL_LIST.get(31);
|
|
||||||
case DOWN_EAST -> VOXEL_LIST.get(34);
|
|
||||||
case NORTH_EAST -> VOXEL_LIST.get(35);
|
|
||||||
};
|
|
||||||
case FIRST_OUTER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case NORTH_DOWN -> VOXEL_LIST.get(15);
|
|
||||||
case SOUTH_UP, EAST_UP -> VOXEL_LIST.get(16);
|
|
||||||
case WEST_DOWN -> VOXEL_LIST.get(13);
|
|
||||||
case DOWN_SOUTH, EAST_SOUTH -> VOXEL_LIST.get(23);
|
|
||||||
case UP_NORTH -> VOXEL_LIST.get(24);
|
|
||||||
case WEST_NORTH -> VOXEL_LIST.get(26);
|
|
||||||
case UP_WEST -> VOXEL_LIST.get(28);
|
|
||||||
case SOUTH_WEST -> VOXEL_LIST.get(29);
|
|
||||||
case DOWN_EAST -> VOXEL_LIST.get(33);
|
|
||||||
case NORTH_EAST -> VOXEL_LIST.get(34);
|
|
||||||
};
|
|
||||||
case SECOND_OUTER_LEFT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_EAST -> VOXEL_LIST.get(15);
|
|
||||||
case DOWN_SOUTH -> VOXEL_LIST.get(13);
|
|
||||||
case UP_WEST, UP_NORTH -> VOXEL_LIST.get(18);
|
|
||||||
case SOUTH_UP, SOUTH_WEST -> VOXEL_LIST.get(21);
|
|
||||||
case NORTH_EAST -> VOXEL_LIST.get(24);
|
|
||||||
case NORTH_DOWN -> VOXEL_LIST.get(26);
|
|
||||||
case WEST_DOWN -> VOXEL_LIST.get(30);
|
|
||||||
case WEST_NORTH -> VOXEL_LIST.get(31);
|
|
||||||
case EAST_SOUTH -> VOXEL_LIST.get(32);
|
|
||||||
case EAST_UP -> VOXEL_LIST.get(35);
|
|
||||||
};
|
|
||||||
case SECOND_OUTER_RIGHT ->
|
|
||||||
switch (direction) {
|
|
||||||
case DOWN_SOUTH, DOWN_EAST -> VOXEL_LIST.get(12);
|
|
||||||
case UP_WEST -> VOXEL_LIST.get(17);
|
|
||||||
case UP_NORTH -> VOXEL_LIST.get(19);
|
|
||||||
case SOUTH_UP -> VOXEL_LIST.get(20);
|
|
||||||
case SOUTH_WEST -> VOXEL_LIST.get(22);
|
|
||||||
case NORTH_EAST, NORTH_DOWN -> VOXEL_LIST.get(27);
|
|
||||||
case WEST_DOWN -> VOXEL_LIST.get(29);
|
|
||||||
case WEST_NORTH -> VOXEL_LIST.get(30);
|
|
||||||
case EAST_UP -> VOXEL_LIST.get(32);
|
|
||||||
case EAST_SOUTH -> VOXEL_LIST.get(33);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
|
||||||
return getStairMultipart(this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MultipartBlockStateSupplier getStairMultipart(Block block, boolean is_double) {
|
|
||||||
String prefix = is_double ? "double_" : "";
|
|
||||||
Identifier straight_id = ReFramed.id(prefix + "stairs_special");
|
|
||||||
Identifier double_outer_id = ReFramed.id(prefix + "outers_stairs_special");
|
|
||||||
Identifier inner_id = ReFramed.id(prefix + "inner_stairs_special");
|
|
||||||
Identifier outer_id = ReFramed.id(prefix + "outer_stairs_special");
|
|
||||||
Identifier outer_side_id = ReFramed.id(prefix + "outer_side_stairs_special");
|
|
||||||
return MultipartBlockStateSupplier.create(block)
|
|
||||||
/* STRAIGHT X AXIS */
|
|
||||||
.with(GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R0, R0))
|
|
||||||
.with(GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R180, R0))
|
|
||||||
.with(GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R180, R180))
|
|
||||||
.with(GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R0, R180))
|
|
||||||
/* STRAIGHT Y AXIS */
|
|
||||||
.with(GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R90, R0))
|
|
||||||
.with(GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R90, R90))
|
|
||||||
.with(GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R90, R180))
|
|
||||||
.with(GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R90, R270))
|
|
||||||
/* STRAIGHT Z AXIS */
|
|
||||||
.with(GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R0, R90))
|
|
||||||
.with(GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R0, R270))
|
|
||||||
.with(GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R180, R270))
|
|
||||||
.with(GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, STRAIGHT),
|
|
||||||
GBlockstate.variant(straight_id, true, R180, R90))
|
|
||||||
/* INNER BOTTOM */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R0, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R0, R270))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R0, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R0, R90))
|
|
||||||
/* INNER TOP */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, INNER_RIGHT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R180, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, INNER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, INNER_RIGHT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R180, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, INNER_RIGHT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R180, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, INNER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, INNER_LEFT)),
|
|
||||||
GBlockstate.variant(inner_id, true, R180, R270))
|
|
||||||
/* OUTER BOTTOM */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R0, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R0, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R0, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R0, R270))
|
|
||||||
/* OUTER TOP */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R180, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R180, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R180, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_id, true, R180, R270))
|
|
||||||
/* OUTER EAST */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R0, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R90, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R180, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R270, R0))
|
|
||||||
/* OUTER SOUTH */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R0, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R90, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R180, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R270, R90))
|
|
||||||
/* OUTER WEST */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R0, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R90, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R180, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R270, R180))
|
|
||||||
/* OUTER NORTH */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R0, R270))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R90, R270))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R180, R270))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(outer_side_id, true, R270, R270))
|
|
||||||
/* OUTER BOTTOM */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R0, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R0, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R0, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, OUTER_RIGHT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R0, R270))
|
|
||||||
/* OUTER TOP */
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R180, R0))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R180, R90))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, OUTER_RIGHT),
|
|
||||||
GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R180, R180))
|
|
||||||
.with(When.anyOf(
|
|
||||||
GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, OUTER_LEFT),
|
|
||||||
GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)),
|
|
||||||
GBlockstate.variant(double_outer_id, true, R180, R270));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
|
||||||
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE);
|
|
||||||
ShapedRecipeJsonBuilder
|
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this, 4)
|
|
||||||
.pattern("I ")
|
|
||||||
.pattern("II ")
|
|
||||||
.pattern("III")
|
|
||||||
.input('I', ReFramed.CUBE)
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
final VoxelShape STRAIGHT = Stream.of(
|
|
||||||
VoxelShapes.cuboid(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f),
|
|
||||||
VoxelShapes.cuboid(0.0f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f)
|
|
||||||
).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get();
|
|
||||||
final VoxelShape JUNCTION = Stream.of(
|
|
||||||
VoxelShapes.cuboid(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f),
|
|
||||||
VoxelShapes.cuboid(0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f)
|
|
||||||
).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get();
|
|
||||||
final VoxelShape OUTER = Stream.of(
|
|
||||||
VoxelShapes.cuboid(0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f),
|
|
||||||
VoxelShapes.cuboid(0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.5f),
|
|
||||||
VoxelShapes.cuboid(0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f),
|
|
||||||
VoxelShapes.cuboid(0.5f, 0.0f, 0.5f, 1.0f, 0.5f, 1.0f)
|
|
||||||
).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get();
|
|
||||||
final VoxelShape INNER = Stream.of(
|
|
||||||
VoxelShapes.cuboid(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f),
|
|
||||||
VoxelShapes.cuboid(0.0f, 0.5f, 0.0f, 0.5f, 1.0f, 1.0f),
|
|
||||||
VoxelShapes.cuboid(0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.5f)
|
|
||||||
).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get();
|
|
||||||
|
|
||||||
VOXEL_LIST.add(STRAIGHT);
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(STRAIGHT, Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.X), Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.X));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y), Axis.Z), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y), Axis.Z));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z), Axis.Y), Axis.Z));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(JUNCTION);
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(JUNCTION, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(JUNCTION, Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.Y));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(JUNCTION, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(JUNCTION, Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.mirror(JUNCTION, Axis.Y), Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(JUNCTION, Axis.Y), Axis.Y));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z), Axis.Z));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X), Axis.X));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(OUTER);
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(OUTER, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(OUTER, Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(OUTER, Axis.Y));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(OUTER, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(OUTER, Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(OUTER, Axis.Y), Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(OUTER, Axis.Y), Axis.Y));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(INNER);
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(INNER, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(INNER, Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(INNER, Axis.Y));
|
|
||||||
|
|
||||||
VOXEL_LIST.add(VoxelHelper.mirror(INNER, Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(INNER, Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(INNER, Axis.Y), Axis.Y), Axis.Y));
|
|
||||||
VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(INNER, Axis.Y), Axis.Y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Edge;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.StairShape;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedStairBlock.*;
|
||||||
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
|
||||||
|
|
||||||
|
public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock {
|
||||||
|
|
||||||
|
private static final VoxelShape[] STAIRS_CUBE_VOXELS = VoxelListBuilder.buildFrom(STAIR_VOXELS);
|
||||||
|
|
||||||
|
public ReFramedStairsCubeBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN).with(STAIR_SHAPE, StairShape.STRAIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EDGE, STAIR_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighbor_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
return super.getStateForNeighborUpdate(state, direction, neighbor_state, world, pos, moved)
|
||||||
|
.with(STAIR_SHAPE, BlockHelper.getStairsShape(state.get(EDGE), world, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
Edge face = BlockHelper.getPlacementEdge(ctx);
|
||||||
|
StairShape shape = BlockHelper.getStairsShape(face, ctx.getWorld(), ctx.getBlockPos());
|
||||||
|
return super.getPlacementState(ctx).with(EDGE, face).with(STAIR_SHAPE, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
Edge prev_edge = state.get(EDGE);
|
||||||
|
Edge edge = prev_edge.rotate(rotation);
|
||||||
|
if (prev_edge.getAxis() == Direction.Axis.Y) return state.with(EDGE, edge);
|
||||||
|
|
||||||
|
if (prev_edge.getFace().getDirection() == edge.getFace().getDirection()) // 90° rotations
|
||||||
|
state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror());
|
||||||
|
else state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).flip());
|
||||||
|
|
||||||
|
if (prev_edge.getAxis() == edge.getAxis()) // 180° rotation
|
||||||
|
state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror());
|
||||||
|
|
||||||
|
return state.with(EDGE, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
Edge prev_edge = state.get(EDGE);
|
||||||
|
Edge edge = prev_edge.mirror(mirror);
|
||||||
|
return state
|
||||||
|
.with(STAIR_SHAPE, prev_edge == edge ? state.get(STAIR_SHAPE).mirror() : state.get(STAIR_SHAPE).flip())
|
||||||
|
.with(EDGE, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
Edge edge = state.get(EDGE);
|
||||||
|
StairShape shape = state.get(STAIR_SHAPE);
|
||||||
|
return i == 2 ? STAIRS_CUBE_VOXELS[edge.getID() * 9 + shape.getID()] : getStairShape(edge, shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,136 +1,177 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
|
||||||
import fr.adrien1106.reframed.util.VoxelHelper;
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import fr.adrien1106.reframed.util.blocks.Edge;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
|
||||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
|
||||||
import net.minecraft.state.StateManager;
|
import net.minecraft.state.StateManager;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Map;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
import static fr.adrien1106.reframed.util.property.Corner.*;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
import static net.minecraft.state.property.Properties.WATERLOGGED;
|
||||||
|
|
||||||
public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
public class ReFramedStepBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
public static final List<VoxelShape> STEP_VOXELS = new ArrayList<>(12);
|
public static final VoxelShape[] STEP_VOXELS;
|
||||||
|
|
||||||
public ReFramedStepBlock(Settings settings) {
|
public ReFramedStepBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN));
|
setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(CORNER));
|
super.appendProperties(builder.add(EDGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||||
|
if (context.getPlayer() == null) return false;
|
||||||
|
Edge edge = state.get(EDGE);
|
||||||
|
return !(
|
||||||
|
context.getPlayer().isSneaking()
|
||||||
|
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|
||||||
|
|| (
|
||||||
|
!(
|
||||||
|
block_item.getBlock() == ReFramed.STAIR
|
||||||
|
&& ((ReFramedStairsCubeBlock) ReFramed.STAIRS_CUBE)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.STAIRS_CUBE.getDefaultState().with(EDGE, edge.opposite()),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
&& !(
|
||||||
|
block_item.getBlock() == this
|
||||||
|
&& (
|
||||||
|
((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.STEPS_SLAB.getDefaultState()
|
||||||
|
.with(FACING, edge.getFirstDirection())
|
||||||
|
.with(AXIS, edge.getSecondDirection().getAxis()),
|
||||||
|
edge.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
|| ((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB)
|
||||||
|
.matchesShape(
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
ReFramed.STEPS_SLAB.getDefaultState()
|
||||||
|
.with(FACING, edge.getSecondDirection())
|
||||||
|
.with(AXIS, edge.getFirstDirection().getAxis()),
|
||||||
|
edge.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx));
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
BlockState current_state = ctx.getWorld().getBlockState(pos);
|
||||||
|
if (current_state.isOf(ReFramed.STAIR))
|
||||||
|
return ReFramed.STAIRS_CUBE.getDefaultState()
|
||||||
|
.with(EDGE, current_state.get(EDGE))
|
||||||
|
.with(STAIR_SHAPE, current_state.get(STAIR_SHAPE));
|
||||||
|
|
||||||
|
|
||||||
|
if (current_state.isOf(this)) {
|
||||||
|
Vec3d hit = ctx.getHitPos();
|
||||||
|
Edge edge = current_state.get(EDGE);
|
||||||
|
Direction dir = edge.getFirstDirection();
|
||||||
|
ReFramedStepsSlabBlock block = ((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB);
|
||||||
|
BlockState state = block.getDefaultState()
|
||||||
|
.with(FACING, dir)
|
||||||
|
.with(AXIS, edge.getOtherDirection(dir).getAxis())
|
||||||
|
.with(WATERLOGGED, current_state.get(WATERLOGGED));
|
||||||
|
if (!block.matchesShape(
|
||||||
|
hit, pos,
|
||||||
|
state,
|
||||||
|
edge.getOtherDirection(dir).getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
|
||||||
|
)) {
|
||||||
|
dir = edge.getSecondDirection();
|
||||||
|
state = state
|
||||||
|
.with(FACING, dir)
|
||||||
|
.with(AXIS, edge.getOtherDirection(dir).getAxis());
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
return switch (state.get(CORNER)) {
|
return getStepShape(state.get(EDGE));
|
||||||
case DOWN_SOUTH -> STEP_VOXELS.get(0);
|
|
||||||
case NORTH_DOWN -> STEP_VOXELS.get(1);
|
|
||||||
case UP_NORTH -> STEP_VOXELS.get(2);
|
|
||||||
case SOUTH_UP -> STEP_VOXELS.get(3);
|
|
||||||
case DOWN_EAST -> STEP_VOXELS.get(4);
|
|
||||||
case WEST_DOWN -> STEP_VOXELS.get(5);
|
|
||||||
case UP_WEST -> STEP_VOXELS.get(6);
|
|
||||||
case EAST_UP -> STEP_VOXELS.get(7);
|
|
||||||
case NORTH_EAST -> STEP_VOXELS.get(8);
|
|
||||||
case EAST_SOUTH -> STEP_VOXELS.get(9);
|
|
||||||
case SOUTH_WEST -> STEP_VOXELS.get(10);
|
|
||||||
case WEST_NORTH -> STEP_VOXELS.get(11);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
Identifier step_id = ReFramed.id("step_special");
|
return state.with(EDGE, state.get(EDGE).rotate(rotation));
|
||||||
return MultipartBlockStateSupplier.create(this)
|
|
||||||
/* X AXIS */
|
|
||||||
.with(GBlockstate.when(CORNER, DOWN_EAST),
|
|
||||||
GBlockstate.variant(step_id, true, R0, R0))
|
|
||||||
.with(GBlockstate.when(CORNER, EAST_UP),
|
|
||||||
GBlockstate.variant(step_id, true, R180, R0))
|
|
||||||
.with(GBlockstate.when(CORNER, UP_WEST),
|
|
||||||
GBlockstate.variant(step_id, true, R180, R180))
|
|
||||||
.with(GBlockstate.when(CORNER, WEST_DOWN),
|
|
||||||
GBlockstate.variant(step_id, true, R0, R180))
|
|
||||||
/* Y AXIS */
|
|
||||||
.with(GBlockstate.when(CORNER, EAST_SOUTH),
|
|
||||||
GBlockstate.variant(step_id, true, R90, R0))
|
|
||||||
.with(GBlockstate.when(CORNER, SOUTH_WEST),
|
|
||||||
GBlockstate.variant(step_id, true, R90, R90))
|
|
||||||
.with(GBlockstate.when(CORNER, WEST_NORTH),
|
|
||||||
GBlockstate.variant(step_id, true, R90, R180))
|
|
||||||
.with(GBlockstate.when(CORNER, NORTH_EAST),
|
|
||||||
GBlockstate.variant(step_id, true, R90, R270))
|
|
||||||
/* Z AXIS */
|
|
||||||
.with(GBlockstate.when(CORNER, DOWN_SOUTH),
|
|
||||||
GBlockstate.variant(step_id, true, R0, R90))
|
|
||||||
.with(GBlockstate.when(CORNER, NORTH_DOWN),
|
|
||||||
GBlockstate.variant(step_id, true, R0, R270))
|
|
||||||
.with(GBlockstate.when(CORNER, UP_NORTH),
|
|
||||||
GBlockstate.variant(step_id, true, R180, R270))
|
|
||||||
.with(GBlockstate.when(CORNER, SOUTH_UP),
|
|
||||||
GBlockstate.variant(step_id, true, R180, R90));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRecipe(RecipeExporter exporter) {
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 4);
|
return state.with(EDGE, state.get(EDGE).mirror(mirror));
|
||||||
ShapedRecipeJsonBuilder
|
}
|
||||||
.create(RecipeCategory.BUILDING_BLOCKS, this, 8)
|
|
||||||
.pattern("II")
|
public static VoxelShape getStepShape(Edge edge) {
|
||||||
.input('I', ReFramed.CUBE)
|
return STEP_VOXELS[edge.getID()];
|
||||||
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
}
|
||||||
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
|
|
||||||
.offerTo(exporter);
|
@Override
|
||||||
|
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
|
||||||
|
if (new_state.isOf(ReFramed.STAIRS_CUBE)) return Map.of(1, 2);
|
||||||
|
if (new_state.isOf(ReFramed.STEPS_SLAB))
|
||||||
|
return Map.of(
|
||||||
|
1,
|
||||||
|
state.get(EDGE)
|
||||||
|
.getOtherDirection(new_state.get(FACING))
|
||||||
|
.getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1
|
||||||
|
);
|
||||||
|
return super.getThemeMap(state, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final VoxelShape STEP = VoxelShapes.cuboid(0f, 0f, .5f, 1f, .5f, 1f);
|
final VoxelShape STEP = createCuboidShape(0, 0, 0, 16, 8, 8);
|
||||||
|
|
||||||
STEP_VOXELS.add(STEP);
|
STEP_VOXELS = VoxelListBuilder.create(STEP, 12)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(STEP, Direction.Axis.Z));
|
.add(VoxelHelper::rotateCX)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.X), Direction.Axis.Z));
|
.add(VoxelHelper::rotateCX)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.X));
|
.add(VoxelHelper::rotateCX)
|
||||||
|
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y));
|
.add(STEP, VoxelHelper::rotateCY)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.X));
|
.add(VoxelHelper::rotateZ)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.Z), Direction.Axis.X));
|
.add(VoxelHelper::rotateZ)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.Z));
|
.add(VoxelHelper::rotateZ)
|
||||||
|
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y));
|
.add(STEP, VoxelHelper::rotateCZ)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z));
|
.add(VoxelHelper::rotateY)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y));
|
.add(VoxelHelper::rotateY)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y), Direction.Axis.Z));
|
.add(VoxelHelper::rotateY)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Edge;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Direction.Axis;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
|
public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedStepsSlabBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(FACING, AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
Vec3d pos = BlockHelper.getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
||||||
|
return super.getPlacementState(ctx)
|
||||||
|
.with(FACING, ctx.getSide().getOpposite())
|
||||||
|
.with(AXIS, BlockHelper.getHitAxis(pos, ctx.getSide()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
return isGhost(view, pos) ? empty() : getSlabShape(state.get(FACING));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getSlabShape(state.get(FACING));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state
|
||||||
|
.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis())
|
||||||
|
.with(FACING, rotation.rotate(state.get(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
if (state.get(FACING).getAxis() != Axis.Y)
|
||||||
|
return state.with(FACING, mirror.apply(state.get(FACING)));
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
Axis axis = state.get(AXIS);
|
||||||
|
return getStepShape(Edge.getByDirections(
|
||||||
|
state.get(FACING),
|
||||||
|
switch (axis) {
|
||||||
|
case X -> i == 1 ? Direction.WEST : Direction.EAST;
|
||||||
|
case Y -> i == 1 ? Direction.DOWN : Direction.UP;
|
||||||
|
case Z -> i == 1 ? Direction.NORTH : Direction.SOUTH;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopThemeIndex(BlockState state) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.enums.BlockHalf;
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
import net.minecraft.world.explosion.Explosion;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class ReFramedTrapdoorBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] TRAPDOOR_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedTrapdoorBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(HORIZONTAL_FACING, Direction.NORTH)
|
||||||
|
.with(BLOCK_HALF, BlockHalf.BOTTOM)
|
||||||
|
.with(OPEN, false)
|
||||||
|
.with(POWERED, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(HORIZONTAL_FACING, BLOCK_HALF, OPEN, POWERED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block source, BlockPos sourcePos, boolean notify) {
|
||||||
|
if (world.isClient) return;
|
||||||
|
boolean powered = world.isReceivingRedstonePower(pos);
|
||||||
|
if (powered != state.get(POWERED)) {
|
||||||
|
if (state.get(OPEN) != powered) {
|
||||||
|
state = state.with(OPEN, powered);
|
||||||
|
playToggleSound(null, world, pos, powered);
|
||||||
|
}
|
||||||
|
|
||||||
|
world.setBlockState(pos, state.with(POWERED, powered), 2);
|
||||||
|
if (state.get(WATERLOGGED)) {
|
||||||
|
world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
Direction side = ctx.getSide();
|
||||||
|
|
||||||
|
if (side.getAxis().isVertical()) state = state
|
||||||
|
.with(HORIZONTAL_FACING, ctx.getHorizontalPlayerFacing().getOpposite())
|
||||||
|
.with(BLOCK_HALF, side == Direction.UP ? BlockHalf.BOTTOM : BlockHalf.TOP);
|
||||||
|
else state = state
|
||||||
|
.with(HORIZONTAL_FACING, side)
|
||||||
|
.with(BLOCK_HALF, ctx.getHitPos().getY() - pos.getY() > 0.5 ? BlockHalf.TOP : BlockHalf.BOTTOM);
|
||||||
|
|
||||||
|
if (world.isReceivingRedstonePower(pos)) state = state.with(OPEN, true).with(POWERED, true);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
flip(state, world, pos, player);
|
||||||
|
return ActionResult.success(world.isClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
|
||||||
|
return switch (type) {
|
||||||
|
case LAND, AIR -> state.get(OPEN);
|
||||||
|
case WATER -> state.get(WATERLOGGED);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExploded(BlockState state, World world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stack_merger) {
|
||||||
|
if (explosion.getDestructionType() == Explosion.DestructionType.TRIGGER_BLOCK
|
||||||
|
&& !world.isClient()
|
||||||
|
&& !state.get(POWERED)
|
||||||
|
) flip(state, world, pos, null);
|
||||||
|
|
||||||
|
super.onExploded(state, world, pos, explosion, stack_merger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flip(BlockState state, World world, BlockPos pos, @Nullable PlayerEntity player) {
|
||||||
|
state = state.cycle(OPEN);
|
||||||
|
world.setBlockState(pos, state, 2);
|
||||||
|
|
||||||
|
this.playToggleSound(player, world, pos, state.get(OPEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void playToggleSound(@Nullable PlayerEntity player, World world, BlockPos pos, boolean open) {
|
||||||
|
world.playSound(player, pos, open ? BlockSetType.OAK.trapdoorOpen() : BlockSetType.OAK.trapdoorClose(), SoundCategory.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.1F + 0.9F);
|
||||||
|
world.emitGameEvent(player, open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
int index;
|
||||||
|
if (!state.get(OPEN)) index = state.get(BLOCK_HALF) == BlockHalf.BOTTOM ? 0 : 1;
|
||||||
|
else index = state.get(HORIZONTAL_FACING).ordinal();
|
||||||
|
return TRAPDOOR_VOXELS[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(HORIZONTAL_FACING, rotation.rotate(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(HORIZONTAL_FACING, mirror.apply(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape SHAPE = createCuboidShape(0, 0, 0, 16, 3, 16);
|
||||||
|
TRAPDOOR_VOXELS = VoxelHelper.VoxelListBuilder.create(SHAPE, 6)
|
||||||
|
.add(VoxelHelper::mirrorY)
|
||||||
|
.add(VoxelHelper::rotateX)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.enums.WallShape;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.state.property.Property;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import net.minecraft.world.WorldView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class ReFramedWallBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] WALL_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedWallBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(UP, true)
|
||||||
|
.with(EAST_WALL_SHAPE, WallShape.NONE)
|
||||||
|
.with(NORTH_WALL_SHAPE, WallShape.NONE)
|
||||||
|
.with(WEST_WALL_SHAPE, WallShape.NONE)
|
||||||
|
.with(SOUTH_WALL_SHAPE, WallShape.NONE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(UP, EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
BlockState top_state = dir == Direction.UP? other_state: world.getBlockState(pos.up());
|
||||||
|
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
||||||
|
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
||||||
|
|
||||||
|
Map<Direction, BlockState> neighbors = Direction.Type.HORIZONTAL.stream()
|
||||||
|
.collect(Collectors.toMap(d -> d, d -> {
|
||||||
|
if (d == dir) return other_state;
|
||||||
|
return world.getBlockState(pos.offset(d));
|
||||||
|
}));
|
||||||
|
new_state = getWallState(new_state, top_state, neighbors, top_shape, fs, world, pos);
|
||||||
|
return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
|
||||||
|
BlockState top_state = world.getBlockState(pos.up());
|
||||||
|
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
||||||
|
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
||||||
|
|
||||||
|
Map<Direction, BlockState> neighbors = Direction.Type.HORIZONTAL.stream()
|
||||||
|
.collect(Collectors.toMap(d -> d, d -> world.getBlockState(pos.offset(d))));
|
||||||
|
state = getWallState(state, top_state, neighbors, top_shape, fs, world, pos);
|
||||||
|
return state.with(UP, shouldHavePost(state, top_state, top_shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = state.get(UP) ? WALL_VOXELS[0]: VoxelShapes.empty();
|
||||||
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
|
WallShape wall_shape = state.get(getWallShape(dir));
|
||||||
|
if (wall_shape != WallShape.NONE)
|
||||||
|
shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
if (isGhost(view, pos)) return VoxelShapes.empty();
|
||||||
|
VoxelShape shape = state.get(UP) ? WALL_VOXELS[9]: VoxelShapes.empty();
|
||||||
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getWallShape(dir)) != WallShape.NONE)
|
||||||
|
shape = VoxelShapes.union(shape, WALL_VOXELS[8 + dir.ordinal()]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getWallShape(rotation.rotate(dir)), state.get(getWallShape(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getWallShape(mirror.apply(dir)), state.get(getWallShape(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockState getWallState(BlockState state, BlockState top_state, Map<Direction, BlockState> neighbors, VoxelShape top_shape, boolean fs, WorldView world, BlockPos pos) {
|
||||||
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
|
BlockPos offset = pos.offset(dir);
|
||||||
|
BlockState neighbor = neighbors.get(dir);
|
||||||
|
boolean side_full = neighbor.isSideSolidFullSquare(world, offset, dir.getOpposite());
|
||||||
|
Property<WallShape> wall_shape = getWallShape(dir);
|
||||||
|
if (shouldConnectTo(neighbor, side_full, dir.getOpposite())) {
|
||||||
|
state = state.with(
|
||||||
|
wall_shape,
|
||||||
|
fs
|
||||||
|
|| (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE)
|
||||||
|
|| shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
|
||||||
|
? WallShape.TALL
|
||||||
|
: WallShape.LOW
|
||||||
|
);
|
||||||
|
} else state = state.with(wall_shape, WallShape.NONE);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldHavePost(BlockState state, BlockState top_state, VoxelShape top_shape) {
|
||||||
|
// above has post
|
||||||
|
if ((top_state.contains(UP) && top_state.get(UP)) || (!top_state.contains(UP) && top_state.contains(NORTH_WALL_SHAPE))) return true;
|
||||||
|
|
||||||
|
if (Stream.of(Direction.SOUTH, Direction.EAST) // Opposites are different
|
||||||
|
.anyMatch(dir -> state.get(getWallShape(dir)) != state.get(getWallShape(dir.getOpposite())))
|
||||||
|
) return true;
|
||||||
|
|
||||||
|
// no sides
|
||||||
|
if (Direction.Type.HORIZONTAL.stream().allMatch(dir -> state.get(getWallShape(dir)) == WallShape.NONE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Matching sides
|
||||||
|
if (Stream.of(Direction.SOUTH, Direction.EAST)
|
||||||
|
.anyMatch(dir ->
|
||||||
|
state.get(getWallShape(dir)) == state.get(getWallShape(dir.getOpposite()))
|
||||||
|
)) return false;
|
||||||
|
|
||||||
|
return top_state.isIn(BlockTags.WALL_POST_OVERRIDE) || top_shape == null || shouldUseTall(WALL_VOXELS[0], top_shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldConnectTo(BlockState state, boolean side_full, Direction side) {
|
||||||
|
Block block = state.getBlock();
|
||||||
|
boolean bl = block instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, side);
|
||||||
|
return state.isIn(BlockTags.WALLS) || !WallBlock.cannotConnect(state) && side_full || block instanceof PaneBlock || bl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldUseTall(VoxelShape self_shape, VoxelShape other_shape) {
|
||||||
|
return !VoxelShapes.matchesAnywhere(
|
||||||
|
self_shape,
|
||||||
|
other_shape,
|
||||||
|
BooleanBiFunction.ONLY_FIRST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Property<WallShape> getWallShape(Direction dir) {
|
||||||
|
return switch (dir) {
|
||||||
|
case EAST -> EAST_WALL_SHAPE;
|
||||||
|
case NORTH -> NORTH_WALL_SHAPE;
|
||||||
|
case WEST -> WEST_WALL_SHAPE;
|
||||||
|
case SOUTH -> SOUTH_WALL_SHAPE;
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape POST = createCuboidShape(4, 0, 4, 12, 16, 12);
|
||||||
|
VoxelShape POST_COLLISION = createCuboidShape(4, 0, 4, 12, 24, 12);
|
||||||
|
VoxelShape LOW = createCuboidShape(5, 0, 0, 11, 14, 8);
|
||||||
|
VoxelShape TALL = createCuboidShape(5, 0, 0, 11, 16, 8);
|
||||||
|
VoxelShape SIDE_COLLISION = createCuboidShape(5, 0, 0, 11, 24, 8);
|
||||||
|
WALL_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 14)
|
||||||
|
.add(LOW)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(TALL)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(POST_COLLISION)
|
||||||
|
.add(SIDE_COLLISION)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
public class WaterloggableReFramedDoubleBlock extends ReFramedDoubleBlock implements Waterloggable {
|
public class WaterloggableReFramedDoubleBlock extends ReFramedDoubleBlock implements Waterloggable {
|
||||||
public WaterloggableReFramedDoubleBlock(Settings settings) {
|
public WaterloggableReFramedDoubleBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(Properties.WATERLOGGED, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,35 +26,154 @@ public class ReFramedClient implements ClientModInitializer {
|
|||||||
//all frames mustn't be on the SOLID layer because they are not opaque!
|
//all frames mustn't be on the SOLID layer because they are not opaque!
|
||||||
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ReFramed.BLOCKS.toArray(new Block[0]));
|
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ReFramed.BLOCKS.toArray(new Block[0]));
|
||||||
|
|
||||||
HELPER.addReFramedModel("cube_special" , HELPER.auto(new Identifier("block/cube")));
|
// CUBE
|
||||||
HELPER.addReFramedModel("slab_special" , HELPER.auto(new Identifier("block/slab")));
|
HELPER.addReFramedModel("cube" , HELPER.auto(new Identifier("block/cube")));
|
||||||
HELPER.addReFramedModel("double_slab_special" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top")));
|
// SMALL_CUBE
|
||||||
HELPER.addReFramedModel("stairs_special" , HELPER.auto(ReFramed.id("block/stairs")));
|
HELPER.addReFramedModel("small_cube" , HELPER.auto(ReFramed.id("block/small_cube/base")));
|
||||||
HELPER.addReFramedModel("outers_stairs_special" , HELPER.auto(ReFramed.id("block/double_outer_stairs")));
|
// SMALL_CUBES_STEP
|
||||||
HELPER.addReFramedModel("inner_stairs_special" , HELPER.auto(ReFramed.id("block/inner_stairs")));
|
HELPER.addReFramedModel("small_cubes_step" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base")));
|
||||||
HELPER.addReFramedModel("outer_stairs_special" , HELPER.auto(ReFramed.id("block/outer_stairs")));
|
HELPER.addReFramedModel("small_cubes_step_reverse" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base")));
|
||||||
HELPER.addReFramedModel("outer_side_stairs_special" , HELPER.auto(ReFramed.id("block/outer_side_stairs")));
|
// SLAB
|
||||||
HELPER.addReFramedModel("double_stairs_special" , HELPER.autoDouble(ReFramed.id("block/stairs"), ReFramed.id("block/stairs_complement")));
|
HELPER.addReFramedModel("slab" , HELPER.auto(new Identifier("block/slab")));
|
||||||
HELPER.addReFramedModel("double_outers_stairs_special" , HELPER.autoDouble(ReFramed.id("block/double_outer_stairs"), ReFramed.id("block/double_outer_stairs_complement")));
|
// SLAB_CUBE
|
||||||
HELPER.addReFramedModel("double_inner_stairs_special" , HELPER.autoDouble(ReFramed.id("block/inner_stairs"), ReFramed.id("block/inner_stairs_complement")));
|
HELPER.addReFramedModel("double_slab" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top")));
|
||||||
HELPER.addReFramedModel("double_outer_stairs_special" , HELPER.autoDouble(ReFramed.id("block/outer_stairs"), ReFramed.id("block/outer_stairs_complement")));
|
// STAIR
|
||||||
HELPER.addReFramedModel("double_outer_side_stairs_special", HELPER.autoDouble(ReFramed.id("block/outer_side_stairs"), ReFramed.id("block/outer_side_stairs_complement")));
|
HELPER.addReFramedModel("stair" , HELPER.auto(ReFramed.id("block/stair/straight")));
|
||||||
HELPER.addReFramedModel("step_special" , HELPER.auto(ReFramed.id("block/step")));
|
HELPER.addReFramedModel("outers_stair" , HELPER.auto(ReFramed.id("block/stair/double_outer")));
|
||||||
HELPER.addReFramedModel("double_step_special" , HELPER.autoDouble(ReFramed.id("block/step"), ReFramed.id("block/step_complement_slab")));
|
HELPER.addReFramedModel("inner_stair" , HELPER.auto(ReFramed.id("block/stair/inner")));
|
||||||
HELPER.addReFramedModel("double_step_side_special" , HELPER.autoDouble(ReFramed.id("block/step_side"), ReFramed.id("block/step_side_complement_slab")));
|
HELPER.addReFramedModel("outer_stair" , HELPER.auto(ReFramed.id("block/stair/outer")));
|
||||||
|
HELPER.addReFramedModel("outer_side_stair" , HELPER.auto(ReFramed.id("block/stair/outer_side")));
|
||||||
|
// STAIRS_CUBE
|
||||||
|
HELPER.addReFramedModel("stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/straight"), ReFramed.id("block/stair/cube/straight")));
|
||||||
|
HELPER.addReFramedModel("outers_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/double_outer"), ReFramed.id("block/stair/cube/double_outer")));
|
||||||
|
HELPER.addReFramedModel("inner_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/inner"), ReFramed.id("block/stair/cube/inner")));
|
||||||
|
HELPER.addReFramedModel("outer_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer"), ReFramed.id("block/stair/cube/outer")));
|
||||||
|
HELPER.addReFramedModel("outer_side_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer_side"), ReFramed.id("block/stair/cube/outer_side")));
|
||||||
|
// HALF_STAIR
|
||||||
|
HELPER.addReFramedModel("half_stair_down" , HELPER.auto(ReFramed.id("block/half_stair/down")));
|
||||||
|
HELPER.addReFramedModel("half_stair_side" , HELPER.auto(ReFramed.id("block/half_stair/side")));
|
||||||
|
// HALF_STAIRS_SLAB
|
||||||
|
HELPER.addReFramedModel("half_stairs_slab_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/slab/down")));
|
||||||
|
HELPER.addReFramedModel("half_stairs_slab_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/slab/side")));
|
||||||
|
// HALF_STAIRS_STAIR
|
||||||
|
HELPER.addReFramedModel("half_stairs_stair_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/stair/down")));
|
||||||
|
HELPER.addReFramedModel("half_stairs_stair_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/stair/side")));
|
||||||
|
HELPER.addReFramedModel("half_stairs_stair_reverse" , HELPER.autoDouble(ReFramed.id("block/half_stair/stair/side"), ReFramed.id("block/half_stair/side")));
|
||||||
|
// STEP
|
||||||
|
HELPER.addReFramedModel("step" , HELPER.auto(ReFramed.id("block/step/down")));
|
||||||
|
// STEPS_SLAB
|
||||||
|
HELPER.addReFramedModel("steps_slab" , HELPER.autoDouble(ReFramed.id("block/step/down"), ReFramed.id("block/step/slab/down")));
|
||||||
|
HELPER.addReFramedModel("steps_slab_side" , HELPER.autoDouble(ReFramed.id("block/step/side"), ReFramed.id("block/step/slab/side")));
|
||||||
|
// LAYER
|
||||||
|
HELPER.addReFramedModel("layer_1" , HELPER.auto(new Identifier("block/snow_height2")));
|
||||||
|
HELPER.addReFramedModel("layer_2" , HELPER.auto(new Identifier("block/snow_height4")));
|
||||||
|
HELPER.addReFramedModel("layer_3" , HELPER.auto(new Identifier("block/snow_height6")));
|
||||||
|
HELPER.addReFramedModel("layer_4" , HELPER.auto(new Identifier("block/snow_height8")));
|
||||||
|
HELPER.addReFramedModel("layer_5" , HELPER.auto(new Identifier("block/snow_height10")));
|
||||||
|
HELPER.addReFramedModel("layer_6" , HELPER.auto(new Identifier("block/snow_height12")));
|
||||||
|
HELPER.addReFramedModel("layer_7" , HELPER.auto(new Identifier("block/snow_height14")));
|
||||||
|
HELPER.addReFramedModel("layer_8" , HELPER.auto(new Identifier("block/cube")));
|
||||||
|
// PILLAR
|
||||||
|
HELPER.addReFramedModel("pillar" , HELPER.auto(ReFramed.id("block/pillar")));
|
||||||
|
// WALL
|
||||||
|
HELPER.addReFramedModel("wall_inventory" , HELPER.auto(ReFramed.id("block/wall/inventory/default")));
|
||||||
|
// --------------------- pillar
|
||||||
|
HELPER.addReFramedModel("wall_core" , HELPER.auto(ReFramed.id("block/wall/pillar/core")));
|
||||||
|
HELPER.addReFramedModel("wall_pillar_low" , HELPER.auto(ReFramed.id("block/wall/pillar/low")));
|
||||||
|
HELPER.addReFramedModel("wall_pillar_tall" , HELPER.auto(ReFramed.id("block/wall/pillar/tall")));
|
||||||
|
HELPER.addReFramedModel("wall_pillar_none" , HELPER.auto(ReFramed.id("block/wall/pillar/none")));
|
||||||
|
// --------------------- side
|
||||||
|
HELPER.addReFramedModel("wall_side_low" , HELPER.auto(ReFramed.id("block/wall/side/low")));
|
||||||
|
HELPER.addReFramedModel("wall_side_tall" , HELPER.auto(ReFramed.id("block/wall/side/tall")));
|
||||||
|
// --------------------- junction
|
||||||
|
HELPER.addReFramedModel("wall_low_e" , HELPER.auto(ReFramed.id("block/wall/junction/low")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_e" , HELPER.auto(ReFramed.id("block/wall/junction/tall")));
|
||||||
|
// --------------------- junction_i
|
||||||
|
HELPER.addReFramedModel("wall_low_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_i")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i")));
|
||||||
|
HELPER.addReFramedModel("wall_low_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_i")));
|
||||||
|
// --------------------- junction_c
|
||||||
|
HELPER.addReFramedModel("wall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_c")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c")));
|
||||||
|
HELPER.addReFramedModel("wall_low_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c")));
|
||||||
|
// --------------------- junction_t
|
||||||
|
HELPER.addReFramedModel("wall_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_t")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_low_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c_t")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_i_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_t")));
|
||||||
|
HELPER.addReFramedModel("wall_low_i_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_i_tall_t")));
|
||||||
|
HELPER.addReFramedModel("wall_low_tall_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c_t")));
|
||||||
|
HELPER.addReFramedModel("wall_low_c_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_c_tall_t")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_c_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_t")));
|
||||||
|
// --------------------- junction_x
|
||||||
|
HELPER.addReFramedModel("wall_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/low_x")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_x")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_i_low_i_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_i_x")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_low_t_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_t_x")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_c_low_c_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_c_x")));
|
||||||
|
HELPER.addReFramedModel("wall_tall_t_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t_low_x")));
|
||||||
|
// PILLAR WALL
|
||||||
|
HELPER.addReFramedModel("pillars_wall_inventory" , HELPER.autoDouble(ReFramed.id("block/pillar"), ReFramed.id("block/wall/full/inventory/sides")));
|
||||||
|
HELPER.addReFramedModel("pillars_wall_low" , HELPER.autoDouble(ReFramed.id("block/wall/full/pillar/low"), ReFramed.id("block/wall/full/side/low")));
|
||||||
|
HELPER.addReFramedModel("pillars_wall_tall" , HELPER.autoDouble(ReFramed.id("block/wall/full/pillar/tall"), ReFramed.id("block/wall/full/side/tall")));
|
||||||
|
// PANE
|
||||||
|
HELPER.addReFramedModel("pane_inventory" , HELPER.auto(ReFramed.id("block/pane")));
|
||||||
|
HELPER.addReFramedModel("pane_post" , HELPER.auto(new Identifier("block/glass_pane_post")));
|
||||||
|
HELPER.addReFramedModel("pane_side" , HELPER.auto(new Identifier("block/glass_pane_side")));
|
||||||
|
HELPER.addReFramedModel("pane_side_alt" , HELPER.auto(new Identifier("block/glass_pane_side_alt")));
|
||||||
|
HELPER.addReFramedModel("pane_noside" , HELPER.auto(new Identifier("block/glass_pane_noside")));
|
||||||
|
HELPER.addReFramedModel("pane_noside_alt" , HELPER.auto(new Identifier("block/glass_pane_noside_alt")));
|
||||||
|
// TRAPDOOR
|
||||||
|
HELPER.addReFramedModel("trapdoor_open" , HELPER.auto(new Identifier("block/oak_trapdoor_open")));
|
||||||
|
HELPER.addReFramedModel("trapdoor_bottom" , HELPER.auto(new Identifier("block/oak_trapdoor_bottom")));
|
||||||
|
HELPER.addReFramedModel("trapdoor_top" , HELPER.auto(new Identifier("block/oak_trapdoor_top")));
|
||||||
|
// DOOR
|
||||||
|
HELPER.addReFramedModel("door_inventory" , HELPER.auto(ReFramed.id("block/door")));
|
||||||
|
// BUTTON
|
||||||
|
HELPER.addReFramedModel("button_inventory" , HELPER.auto(new Identifier("block/button_inventory")));
|
||||||
|
HELPER.addReFramedModel("button" , HELPER.auto(new Identifier("block/button")));
|
||||||
|
HELPER.addReFramedModel("button_pressed" , HELPER.auto(new Identifier("block/button_pressed")));
|
||||||
|
// POST
|
||||||
|
HELPER.addReFramedModel("post" , HELPER.auto(ReFramed.id("block/post")));
|
||||||
|
// FENCE
|
||||||
|
HELPER.addReFramedModel("fence_inventory" , HELPER.auto(ReFramed.id("block/fence/inventory")));
|
||||||
|
HELPER.addReFramedModel("fence_core" , HELPER.auto(ReFramed.id("block/fence/core")));
|
||||||
|
HELPER.addReFramedModel("fence_side_off" , HELPER.auto(ReFramed.id("block/fence/side_off")));
|
||||||
|
HELPER.addReFramedModel("fence_side_on" , HELPER.auto(ReFramed.id("block/fence/side_on")));
|
||||||
|
// POST FENCE
|
||||||
|
HELPER.addReFramedModel("post_fence_inventory" , HELPER.autoDouble(ReFramed.id("block/post"), ReFramed.id("block/fence/full/inventory")));
|
||||||
|
HELPER.addReFramedModel("post_fence_side" , HELPER.autoDouble(ReFramed.id("block/fence/full/side_core"), ReFramed.id("block/fence/full/side_bars")));
|
||||||
|
|
||||||
|
|
||||||
//item model assignments (in lieu of models/item/___.json)
|
//item model assignments (in lieu of models/item/___.json)
|
||||||
HELPER.assignItemModel("cube_special" , ReFramed.CUBE);
|
HELPER.assignItemModel("cube" , ReFramed.CUBE);
|
||||||
HELPER.assignItemModel("slab_special" , ReFramed.SLAB);
|
HELPER.assignItemModel("small_cube" , ReFramed.SMALL_CUBE);
|
||||||
HELPER.assignItemModel("double_slab_special" , ReFramed.DOUBLE_SLAB);
|
HELPER.assignItemModel("small_cubes_step" , ReFramed.SMALL_CUBES_STEP);
|
||||||
HELPER.assignItemModel("stairs_special" , ReFramed.STAIRS);
|
HELPER.assignItemModel("slab" , ReFramed.SLAB);
|
||||||
HELPER.assignItemModel("double_stairs_special" , ReFramed.DOUBLE_STAIRS);
|
HELPER.assignItemModel("double_slab" , ReFramed.SLABS_CUBE);
|
||||||
HELPER.assignItemModel("step_special" , ReFramed.STEP);
|
HELPER.assignItemModel("stair" , ReFramed.STAIR);
|
||||||
HELPER.assignItemModel("double_step_special" , ReFramed.DOUBLE_STEP);
|
HELPER.assignItemModel("stairs_cube" , ReFramed.STAIRS_CUBE);
|
||||||
|
HELPER.assignItemModel("half_stair_down" , ReFramed.HALF_STAIR);
|
||||||
|
HELPER.assignItemModel("half_stairs_slab_down" , ReFramed.HALF_STAIRS_SLAB);
|
||||||
|
HELPER.assignItemModel("half_stairs_stair_down", ReFramed.HALF_STAIRS_STAIR);
|
||||||
|
HELPER.assignItemModel("step" , ReFramed.STEP);
|
||||||
|
HELPER.assignItemModel("steps_slab" , ReFramed.STEPS_SLAB);
|
||||||
|
HELPER.assignItemModel("layer_1" , ReFramed.LAYER);
|
||||||
|
HELPER.assignItemModel("pillar" , ReFramed.PILLAR);
|
||||||
|
HELPER.assignItemModel("pillars_wall_inventory", ReFramed.PILLARS_WALL);
|
||||||
|
HELPER.assignItemModel("wall_inventory" , ReFramed.WALL);
|
||||||
|
HELPER.assignItemModel("pane_inventory" , ReFramed.PANE);
|
||||||
|
HELPER.assignItemModel("trapdoor_bottom" , ReFramed.TRAPDOOR);
|
||||||
|
HELPER.assignItemModel("door_inventory" , ReFramed.DOOR);
|
||||||
|
HELPER.assignItemModel("button_inventory" , ReFramed.BUTTON);
|
||||||
|
HELPER.assignItemModel("post" , ReFramed.POST);
|
||||||
|
HELPER.assignItemModel("fence_inventory" , ReFramed.FENCE);
|
||||||
|
HELPER.assignItemModel("post_fence_inventory" , ReFramed.POST_FENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void privateInit() {
|
private void privateInit() {
|
||||||
//set up some magic to force chunk rerenders when you change a template (see TemplateEntity)
|
//set up some magic to force chunk re-renders when you change a template (see TemplateEntity)
|
||||||
ReFramed.chunkRerenderProxy = (world, pos) -> {
|
ReFramed.chunkRerenderProxy = (world, pos) -> {
|
||||||
if(world == MinecraftClient.getInstance().world) {
|
if(world == MinecraftClient.getInstance().world) {
|
||||||
MinecraftClient.getInstance().worldRenderer.scheduleBlockRender(
|
MinecraftClient.getInstance().worldRenderer.scheduleBlockRender(
|
||||||
@@ -68,7 +187,7 @@ public class ReFramedClient implements ClientModInitializer {
|
|||||||
//supporting code for the TemplatesModelProvider
|
//supporting code for the TemplatesModelProvider
|
||||||
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> PROVIDER); //block models
|
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> PROVIDER); //block models
|
||||||
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> PROVIDER); //item models
|
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> PROVIDER); //item models
|
||||||
|
|
||||||
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
|
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
|
||||||
@Override public Identifier getFabricId() { return ReFramed.id("dump-caches"); }
|
@Override public Identifier getFabricId() { return ReFramed.id("dump-caches"); }
|
||||||
@Override public void reload(ResourceManager blah) { PROVIDER.dumpCache(); }
|
@Override public void reload(ResourceManager blah) { PROVIDER.dumpCache(); }
|
||||||
|
|||||||
@@ -36,19 +36,22 @@ public class ReFramedClientHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public UnbakedModel autoDouble(Identifier first, Identifier second) {
|
public UnbakedModel autoDouble(Identifier first, Identifier second) {
|
||||||
return new UnbakedDoubleRetexturedModel(auto(first), auto(second));
|
return new UnbakedDoubleRetexturedModel(
|
||||||
|
auto(first),
|
||||||
|
auto(second)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addReFramedModel(String id, UnbakedModel unbaked) {
|
public void addReFramedModel(String id, UnbakedModel unbaked) {
|
||||||
prov.addReFramedModel(ReFramed.id(id), unbaked);
|
prov.addReFramedModel(ReFramed.id(id + "_special"), unbaked);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assignItemModel(String id, ItemConvertible... item_convertibles) {
|
public void assignItemModel(String id, ItemConvertible... item_convertibles) {
|
||||||
prov.assignItemModel(ReFramed.id(id), item_convertibles);
|
prov.assignItemModel(ReFramed.id(id + "_special"), item_convertibles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CamoAppearanceManager getCamoApperanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
public CamoAppearanceManager getCamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
||||||
return prov.getCamoApperanceManager(spriteLookup);
|
return prov.getCamoAppearanceManager(spriteLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull Renderer getFabricRenderer() {
|
public @NotNull Renderer getFabricRenderer() {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class ReFramedModelProvider implements ModelResourceProvider, ModelVarian
|
|||||||
|
|
||||||
/// camo appearance manager cache
|
/// camo appearance manager cache
|
||||||
|
|
||||||
public CamoAppearanceManager getCamoApperanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
public CamoAppearanceManager getCamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
||||||
//This is kind of needlessly sketchy using the "volatile double checked locking" pattern.
|
//This is kind of needlessly sketchy using the "volatile double checked locking" pattern.
|
||||||
//I'd like all frame models to use the same CamoApperanceManager, despite the model
|
//I'd like all frame models to use the same CamoApperanceManager, despite the model
|
||||||
//baking process happening concurrently on several threads, but I also don't want to
|
//baking process happening concurrently on several threads, but I also don't want to
|
||||||
@@ -70,6 +70,7 @@ public class ReFramedModelProvider implements ModelResourceProvider, ModelVarian
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dumpCache() {
|
public void dumpCache() {
|
||||||
|
CamoAppearanceManager.dumpCahe();
|
||||||
appearanceManager = null; //volatile write
|
appearanceManager = null; //volatile write
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,21 +5,23 @@ import net.fabricmc.api.Environment;
|
|||||||
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedQuad;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.random.Random;
|
import net.minecraft.util.math.random.Random;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements MultiRetexturableModel {
|
public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements MultiRetexturableModel {
|
||||||
|
|
||||||
private final ForwardingBakedModel model_1, model_2;
|
private final RetexturingBakedModel model_1, model_2;
|
||||||
public DoubleRetexturingBakedModel(ForwardingBakedModel model_1, ForwardingBakedModel model_2) {
|
public DoubleRetexturingBakedModel(RetexturingBakedModel model_1, RetexturingBakedModel model_2) {
|
||||||
this.wrapped = model_1.getWrappedModel();
|
this.wrapped = model_1.getWrappedModel();
|
||||||
this.model_1 = model_1;
|
this.model_1 = model_1;
|
||||||
this.model_2 = model_2;
|
this.model_2 = model_2;
|
||||||
@@ -36,7 +38,17 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {}
|
public List<BakedQuad> getQuads(BlockState blockState, Direction face, Random rand) {
|
||||||
|
List<BakedQuad> quads = new ArrayList<>(model_1.getQuads(blockState, face, rand));
|
||||||
|
quads.addAll(model_2.getQuads(blockState, face, rand));
|
||||||
|
return quads;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
|
model_1.emitBlockQuads(world, state, pos, randomSupplier, context);
|
||||||
|
model_2.emitBlockQuads(world, state, pos, randomSupplier, context);
|
||||||
|
}
|
||||||
|
|
||||||
@Override // models are emitted here because no checks are done on items
|
@Override // models are emitted here because no checks are done on items
|
||||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
@@ -45,7 +57,7 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BakedModel> models() {
|
public List<RetexturingBakedModel> models() {
|
||||||
return List.of(model_1, model_2);
|
return List.of(model_1, model_2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import net.minecraft.block.BlockState;
|
|||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public interface DynamicBakedModel {
|
public interface DynamicBakedModel {
|
||||||
BakedModel computeQuads(BlockRenderView level, BlockState state, BlockPos pos, int theme_index);
|
BakedModel computeQuads(@Nullable BlockRenderView level, BlockState origin_state, @Nullable BlockPos pos, int theme_index);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface MultiRetexturableModel {
|
public interface MultiRetexturableModel {
|
||||||
|
|
||||||
List<BakedModel> models();
|
List<RetexturingBakedModel> models();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y, float min_z, float max_z) {
|
public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y, float min_z, float max_z) {
|
||||||
|
|
||||||
public static QuadPosBounds read(QuadView quad) {
|
public static QuadPosBounds read(QuadView quad) {
|
||||||
@@ -76,4 +79,15 @@ public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y,
|
|||||||
quad.pos(i, pos);
|
quad.pos(i, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof QuadPosBounds other)) return false;
|
||||||
|
return MathHelper.approximatelyEquals(min_x, other.min_x)
|
||||||
|
&& MathHelper.approximatelyEquals(min_y, other.min_y)
|
||||||
|
&& MathHelper.approximatelyEquals(min_z, other.min_z)
|
||||||
|
&& MathHelper.approximatelyEquals(max_x, other.max_x)
|
||||||
|
&& MathHelper.approximatelyEquals(max_y, other.max_y)
|
||||||
|
&& MathHelper.approximatelyEquals(max_z, other.max_z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
public record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
public record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
||||||
public static QuadUvBounds read(QuadView quad) {
|
public static QuadUvBounds read(QuadView quad) {
|
||||||
float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3);
|
float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3);
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.SpriteProperties;
|
|
||||||
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
|
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.*;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.render.model.BakedQuad;
|
||||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -27,33 +28,35 @@ import net.minecraft.util.math.random.Random;
|
|||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||||
public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state, boolean ao) {
|
public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state) {
|
||||||
this.wrapped = base_model; //field from the superclass; vanilla getQuads etc. will delegate through to this
|
this.wrapped = base_model; //field from the superclass; vanilla getQuads etc. will delegate through to this
|
||||||
|
|
||||||
this.tam = tam;
|
this.appearance_manager = tam;
|
||||||
this.theme_index = theme_index;
|
this.theme_index = theme_index;
|
||||||
this.uv_lock = settings.isUvLocked();
|
this.uv_lock = settings.isUvLocked();
|
||||||
this.item_state = item_state;
|
this.item_state = item_state;
|
||||||
this.ao = ao;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final CamoAppearanceManager tam;
|
protected final CamoAppearanceManager appearance_manager;
|
||||||
protected final int theme_index;
|
protected final int theme_index;
|
||||||
protected final boolean uv_lock;
|
protected final boolean uv_lock;
|
||||||
protected final BlockState item_state;
|
protected final BlockState item_state;
|
||||||
protected final boolean ao;
|
|
||||||
|
|
||||||
/* ----------------------------------------------- CACHE ELEMENT ------------------------------------------------ */
|
protected record MeshCacheKey(Object state_key, CamoAppearance appearance, int model_id) {}
|
||||||
// TODO make static ? for connected textures ?
|
/** cache that store retextured models */
|
||||||
protected record MeshCacheKey(BlockState state, TransformCacheKey transform) {}
|
// self culling cache of the models not made thread local so that it is only computed once
|
||||||
protected record TransformCacheKey(CamoAppearance appearance, int model_id) {}
|
protected final Cache<MeshCacheKey, Mesh> RETEXTURED_MESH_CACHE = CacheBuilder.newBuilder().maximumSize(256).build();
|
||||||
protected final ConcurrentMap<TransformCacheKey, RetexturingTransformer> retextured_transforms = new ConcurrentHashMap<>();
|
|
||||||
protected final ConcurrentMap<MeshCacheKey, Mesh> retextured_meshes = new ConcurrentHashMap<>(); //mutable, append-only cache
|
/** cache that stores the base meshes which has the size of the amount of models */
|
||||||
|
protected final Object2ObjectLinkedOpenHashMap<Object, Mesh> BASE_MESH_CACHE =
|
||||||
|
new Object2ObjectLinkedOpenHashMap<>(2, 0.25f) {
|
||||||
|
@Override
|
||||||
|
protected void rehash(int v) {}
|
||||||
|
};
|
||||||
|
|
||||||
protected static final Direction[] DIRECTIONS_AND_NULL;
|
protected static final Direction[] DIRECTIONS_AND_NULL;
|
||||||
static {
|
static {
|
||||||
@@ -62,14 +65,48 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length);
|
System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final ConcurrentMap<BlockState, Mesh> jsonToMesh = new ConcurrentHashMap<>();
|
protected Mesh getBaseMesh(Object key, BlockState state) {
|
||||||
|
|
||||||
protected Mesh getBaseMesh(BlockState state) {
|
|
||||||
//Convert models to re-texturable Meshes lazily, the first time we encounter each blockstate
|
//Convert models to re-texturable Meshes lazily, the first time we encounter each blockstate
|
||||||
return jsonToMesh.computeIfAbsent(state, this::convertModel);
|
if (BASE_MESH_CACHE.containsKey(key)) return BASE_MESH_CACHE.getAndMoveToFirst(key);
|
||||||
|
Mesh mesh = convertModel(state);
|
||||||
|
BASE_MESH_CACHE.putAndMoveToFirst(key, mesh);
|
||||||
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Mesh convertModel(BlockState state);
|
private List<BakedQuad>[] quads = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BakedQuad> getQuads(BlockState state, Direction face, Random rand) {
|
||||||
|
if (quads == null) {
|
||||||
|
quads = ModelHelper.toQuadLists(
|
||||||
|
getRetexturedMesh(
|
||||||
|
new MeshCacheKey(
|
||||||
|
hashCode(),
|
||||||
|
appearance_manager.getDefaultAppearance(theme_index),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
state
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return quads[ModelHelper.toFaceIndex(face)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCamo(BlockRenderView world, BlockState state, BlockPos pos) {
|
||||||
|
if (state == null || state.isAir()) {
|
||||||
|
quads = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CamoAppearance camo = appearance_manager.getCamoAppearance(world, state, pos, theme_index, false);
|
||||||
|
MeshCacheKey key = new MeshCacheKey(
|
||||||
|
hashCode(),
|
||||||
|
camo,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
quads = ModelHelper.toQuadLists(camo.hashCode() == -1 ? transformMesh(key, state) : getRetexturedMesh(key, state));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Mesh convertModel(BlockState state);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVanillaAdapter() {
|
public boolean isVanillaAdapter() {
|
||||||
@@ -78,39 +115,47 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Sprite getParticleSprite() {
|
public Sprite getParticleSprite() {
|
||||||
return tam.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite();
|
return appearance_manager.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getThemeIndex() {
|
||||||
|
return theme_index;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null;
|
BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null;
|
||||||
|
|
||||||
QuadEmitter quad_emitter = context.getEmitter();
|
QuadEmitter quad_emitter = context.getEmitter();
|
||||||
if(theme == null || theme.isAir()) {
|
if(theme == null || theme.isAir()) {
|
||||||
getUntintedRetexturedMesh(new MeshCacheKey(state, new TransformCacheKey(tam.getDefaultAppearance(theme_index), 0)), 0).outputTo(quad_emitter);
|
getRetexturedMesh(
|
||||||
|
new MeshCacheKey(
|
||||||
|
hashCode(),
|
||||||
|
appearance_manager.getDefaultAppearance(theme_index),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
state
|
||||||
|
).outputTo(quad_emitter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(theme.getBlock() == Blocks.BARRIER) return;
|
if(theme.getBlock() == Blocks.BARRIER) return;
|
||||||
|
|
||||||
CamoAppearance camo = tam.getCamoAppearance(world, theme, pos, theme_index);
|
CamoAppearance camo = appearance_manager.getCamoAppearance(world, theme, pos, theme_index, false);
|
||||||
long seed = theme.getRenderingSeed(pos);
|
long seed = theme.getRenderingSeed(pos);
|
||||||
int model_id = 0;
|
int model_id = 0;
|
||||||
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
||||||
|
|
||||||
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
||||||
Mesh untintedMesh = getUntintedRetexturedMesh(
|
MeshCacheKey key = new MeshCacheKey(hashCode(), camo, model_id);
|
||||||
new MeshCacheKey(
|
// do not clutter the cache with single-use meshes
|
||||||
state,
|
Mesh untintedMesh = camo.hashCode() == -1 ? transformMesh(key, state) : getRetexturedMesh(key, state);
|
||||||
new TransformCacheKey(camo, model_id)
|
|
||||||
),
|
|
||||||
seed
|
|
||||||
);
|
|
||||||
|
|
||||||
//The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into
|
//The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into
|
||||||
//the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors.
|
//the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors.
|
||||||
if(tint == 0xFFFFFFFF) {
|
if(tint == 0xFFFFFFFF) {
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
} else {
|
} else {
|
||||||
context.pushTransform(new TintingTransformer(camo, tint, seed));
|
context.pushTransform(new TintingTransformer(camo, model_id, tint));
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
context.popTransform();
|
context.popTransform();
|
||||||
}
|
}
|
||||||
@@ -120,121 +165,79 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
//cheeky: if the item has NBT data, pluck out the blockstate from it & look up the item color provider
|
//cheeky: if the item has NBT data, pluck out the blockstate from it & look up the item color provider
|
||||||
//none of this is accessible unless you're in creative mode doing ctrl-pick btw
|
//none of this is accessible unless you're in creative mode doing ctrl-pick btw
|
||||||
CamoAppearance nbtAppearance;
|
CamoAppearance appearance;
|
||||||
int tint;
|
int tint;
|
||||||
BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index);
|
BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index);
|
||||||
if(!theme.isAir()) {
|
if(!theme.isAir()) {
|
||||||
nbtAppearance = tam.getCamoAppearance(null, theme, null, theme_index);
|
appearance = appearance_manager.getCamoAppearance(null, theme, null, theme_index, true);
|
||||||
tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0);
|
tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0);
|
||||||
} else {
|
} else {
|
||||||
nbtAppearance = tam.getDefaultAppearance(theme_index);
|
appearance = appearance_manager.getDefaultAppearance(theme_index);
|
||||||
tint = 0xFFFFFFFF;
|
tint = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh untintedMesh = getUntintedRetexturedMesh(new MeshCacheKey(item_state, new TransformCacheKey(nbtAppearance, 0)), 0);
|
Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey("I", appearance, 0), item_state);
|
||||||
|
|
||||||
QuadEmitter quad_emitter = context.getEmitter();
|
QuadEmitter quad_emitter = context.getEmitter();
|
||||||
if(tint == 0xFFFFFFFF) {
|
if(tint == 0xFFFFFFFF) {
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
} else {
|
} else {
|
||||||
context.pushTransform(new TintingTransformer(nbtAppearance, tint, 0));
|
context.pushTransform(new TintingTransformer(appearance, 0, tint));
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
context.popTransform();
|
context.popTransform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Mesh getUntintedRetexturedMesh(MeshCacheKey key, long seed) {
|
public boolean useAmbientOcclusion(BlockRenderView view, BlockPos pos) {
|
||||||
return retextured_meshes.computeIfAbsent(key, (k) -> createUntintedRetexturedMesh(k, seed));
|
if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return false;
|
||||||
}
|
CamoAppearance appearance = appearance_manager
|
||||||
|
.getCamoAppearance(view, frame_entity.getTheme(theme_index), pos, theme_index, false);
|
||||||
protected Mesh createUntintedRetexturedMesh(MeshCacheKey key, long seed) {
|
return appearance.getAO(theme_index);
|
||||||
RetexturingTransformer transformer = retextured_transforms.computeIfAbsent(key.transform, (k) -> new RetexturingTransformer(k.appearance, seed));
|
|
||||||
return pretransformMesh(getBaseMesh(key.state), transformer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mesh pretransformMesh(Mesh mesh, RetexturingTransformer transform) {
|
protected Mesh getRetexturedMesh(MeshCacheKey key, BlockState state) {
|
||||||
|
if (RETEXTURED_MESH_CACHE.asMap().containsKey(key)) return RETEXTURED_MESH_CACHE.getIfPresent(key);
|
||||||
|
Mesh mesh = transformMesh(key, state);
|
||||||
|
RETEXTURED_MESH_CACHE.put(key, mesh);
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Mesh transformMesh(MeshCacheKey key, BlockState state) {
|
||||||
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
|
|
||||||
mesh.forEach(quad -> {
|
AtomicInteger quad_index = new AtomicInteger();
|
||||||
|
getBaseMesh(key.state_key, state).forEach(quad -> {
|
||||||
int i = -1;
|
int i = -1;
|
||||||
do {
|
do {
|
||||||
emitter.copyFrom(quad);
|
emitter.copyFrom(quad);
|
||||||
i = transform.transform(emitter, i);
|
i = key.appearance.transformQuad(emitter, i, quad_index.get(), key.model_id, uv_lock);
|
||||||
} while (i > 0);
|
} while (i > 0);
|
||||||
|
// kinda weird to do it like that but other directions don't use the quad_index, so it doesn't matter
|
||||||
|
if (quad.cullFace() == null) quad_index.getAndIncrement();
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RetexturingTransformer {
|
|
||||||
private final long seed;
|
|
||||||
protected RetexturingTransformer(CamoAppearance ta, long seed) {
|
|
||||||
this.ta = ta;
|
|
||||||
this.seed = seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final CamoAppearance ta;
|
|
||||||
|
|
||||||
public int transform(QuadEmitter quad, int i) {
|
|
||||||
if(quad.tag() == 0) return 0; //Pass the quad through unmodified.
|
|
||||||
|
|
||||||
Direction direction = quad.nominalFace();
|
|
||||||
List<SpriteProperties> sprites = ta.getSprites(direction, seed);
|
|
||||||
if (i == -1) i = sprites.size();
|
|
||||||
|
|
||||||
SpriteProperties properties = sprites.get(sprites.size() - i);
|
|
||||||
i--;
|
|
||||||
QuadPosBounds bounds = properties.bounds();
|
|
||||||
|
|
||||||
if (bounds == null) { // sprite applies anywhere e.g. default behaviour
|
|
||||||
quad.material(ta.getRenderMaterial(ao));
|
|
||||||
quad.spriteBake(
|
|
||||||
properties.sprite(),
|
|
||||||
MutableQuadView.BAKE_NORMALIZED
|
|
||||||
| properties.flags()
|
|
||||||
| (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0)
|
|
||||||
);
|
|
||||||
quad.tag(i+1);
|
|
||||||
quad.emit();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify if sprite covers the current quad and apply the new size
|
|
||||||
QuadPosBounds origin_bounds = QuadPosBounds.read(quad, false);
|
|
||||||
if (!bounds.matches(origin_bounds)) return i;
|
|
||||||
|
|
||||||
// apply new quad shape
|
|
||||||
quad.material(ta.getRenderMaterial(ao));
|
|
||||||
bounds.intersection(origin_bounds, direction.getAxis()).apply(quad, origin_bounds);
|
|
||||||
quad.spriteBake( // seems to work without the flags and break with it
|
|
||||||
properties.sprite(),
|
|
||||||
MutableQuadView.BAKE_NORMALIZED
|
|
||||||
| MutableQuadView.BAKE_LOCK_UV
|
|
||||||
);
|
|
||||||
quad.tag(i+1);
|
|
||||||
quad.emit();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class TintingTransformer implements RenderContext.QuadTransform {
|
protected static class TintingTransformer implements RenderContext.QuadTransform {
|
||||||
private final long seed;
|
private final CamoAppearance appearance;
|
||||||
protected TintingTransformer(CamoAppearance ta, int tint, long seed) {
|
private final int model_id;
|
||||||
this.ta = ta;
|
private final int tint;
|
||||||
|
|
||||||
|
protected TintingTransformer(CamoAppearance appearance, int model_id, int tint) {
|
||||||
|
this.appearance = appearance;
|
||||||
|
this.model_id = model_id;
|
||||||
this.tint = tint;
|
this.tint = tint;
|
||||||
this.seed = seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final CamoAppearance ta;
|
|
||||||
protected final int tint;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean transform(MutableQuadView quad) {
|
public boolean transform(MutableQuadView quad) {
|
||||||
if(quad.tag() == 0) return true;
|
int camo_quad_index = quad.tag() - ((quad.tag() >>> 8) << 8);
|
||||||
|
if(camo_quad_index == 0) return true;
|
||||||
|
|
||||||
|
if(appearance.hasColor(quad.nominalFace(), model_id, camo_quad_index)) quad.color(tint, tint, tint, tint);
|
||||||
|
|
||||||
if(ta.hasColor(quad.nominalFace(), seed, quad.tag())) quad.color(tint, tint, tint, tint);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,17 +33,16 @@ public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel {
|
|||||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> texture_getter, ModelBakeSettings bake_settings, Identifier identifier) {
|
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> texture_getter, ModelBakeSettings bake_settings, Identifier identifier) {
|
||||||
return new RetexturingBakedModel(
|
return new RetexturingBakedModel(
|
||||||
baker.bake(parent, bake_settings),
|
baker.bake(parent, bake_settings),
|
||||||
ReFramedClient.HELPER.getCamoApperanceManager(texture_getter),
|
ReFramedClient.HELPER.getCamoAppearanceManager(texture_getter),
|
||||||
theme_index,
|
theme_index,
|
||||||
bake_settings,
|
bake_settings,
|
||||||
item_state,
|
item_state
|
||||||
ao
|
|
||||||
) {
|
) {
|
||||||
protected Mesh convertModel(BlockState state) {
|
protected Mesh convertModel(BlockState state) {
|
||||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
MeshBuilder builder = r.meshBuilder();
|
MeshBuilder builder = r.meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
RenderMaterial mat = tam.getCachedMaterial(state, false);
|
RenderMaterial mat = appearance_manager.getCachedMaterial(state, false);
|
||||||
|
|
||||||
Random rand = Random.create(42);
|
Random rand = Random.create(42);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
import net.minecraft.client.render.model.Baker;
|
import net.minecraft.client.render.model.Baker;
|
||||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||||
@@ -41,8 +40,8 @@ public class UnbakedDoubleRetexturedModel implements UnbakedModel {
|
|||||||
@Override
|
@Override
|
||||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> texture_getter, ModelBakeSettings model_bake_settings, Identifier identifier) {
|
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> texture_getter, ModelBakeSettings model_bake_settings, Identifier identifier) {
|
||||||
return new DoubleRetexturingBakedModel(
|
return new DoubleRetexturingBakedModel(
|
||||||
(ForwardingBakedModel) model_1.bake(baker, texture_getter, model_bake_settings, identifier),
|
(RetexturingBakedModel) model_1.bake(baker, texture_getter, model_bake_settings, identifier),
|
||||||
(ForwardingBakedModel) model_2.bake(baker, texture_getter, model_bake_settings, identifier)
|
(RetexturingBakedModel) model_2.bake(baker, texture_getter, model_bake_settings, identifier)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,17 +41,16 @@ public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel {
|
|||||||
|
|
||||||
return new RetexturingBakedModel(
|
return new RetexturingBakedModel(
|
||||||
baker.bake(parent, bake_settings),
|
baker.bake(parent, bake_settings),
|
||||||
ReFramedClient.HELPER.getCamoApperanceManager(spriteLookup),
|
ReFramedClient.HELPER.getCamoAppearanceManager(spriteLookup),
|
||||||
theme_index,
|
theme_index,
|
||||||
bake_settings,
|
bake_settings,
|
||||||
item_state,
|
item_state
|
||||||
ao
|
|
||||||
) {
|
) {
|
||||||
protected Mesh convertModel(BlockState state) {
|
protected Mesh convertModel(BlockState state) {
|
||||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
MeshBuilder builder = r.meshBuilder();
|
MeshBuilder builder = r.meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
RenderMaterial mat = tam.getCachedMaterial(state, false);
|
RenderMaterial mat = appearance_manager.getCachedMaterial(state, false);
|
||||||
|
|
||||||
Random rand = Random.create(42);
|
Random rand = Random.create(42);
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ public abstract class UnbakedRetexturedModel implements UnbakedModel {
|
|||||||
|
|
||||||
protected int theme_index = 1;
|
protected int theme_index = 1;
|
||||||
protected BlockState item_state;
|
protected BlockState item_state;
|
||||||
protected boolean ao = true;
|
|
||||||
|
|
||||||
public UnbakedRetexturedModel(Identifier parent) {
|
public UnbakedRetexturedModel(Identifier parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThemeIndex(int theme_index) {
|
public UnbakedRetexturedModel setThemeIndex(int theme_index) {
|
||||||
this.theme_index = theme_index;
|
this.theme_index = theme_index;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ import net.minecraft.util.math.Direction;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public record Appearance(Map<Direction, List<SpriteProperties>> sprites) {}
|
public record Appearance(Map<Direction, List<SpriteProperties>> sprites, boolean use_ao) {}
|
||||||
|
|||||||
@@ -1,13 +1,81 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
package fr.adrien1106.reframed.client.model.apperance;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
@NotNull RenderMaterial getRenderMaterial(boolean ao);
|
public abstract class CamoAppearance {
|
||||||
@NotNull List<SpriteProperties> getSprites(Direction dir, long seed);
|
protected final int id;
|
||||||
boolean hasColor(Direction dir, long seed, int index);
|
protected final RenderMaterial ao_material;
|
||||||
|
protected final RenderMaterial material;
|
||||||
|
|
||||||
|
protected CamoAppearance(RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.ao_material = ao_material;
|
||||||
|
this.material = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id);
|
||||||
|
public abstract boolean hasColor(Direction dir, int model_id, int index);
|
||||||
|
public abstract boolean getAO(int model_id);
|
||||||
|
|
||||||
|
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
||||||
|
return ao && ao_material != null? ao_material : material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int transformQuad(QuadEmitter quad, int i, int quad_index, int model_id, boolean uv_lock) {
|
||||||
|
if(quad.tag() == 0) return 0; // Pass the quad through unmodified.
|
||||||
|
|
||||||
|
Direction direction = quad.nominalFace();
|
||||||
|
List<SpriteProperties> sprites = getSprites(direction, model_id);
|
||||||
|
if (i == -1) i = sprites.size();
|
||||||
|
|
||||||
|
SpriteProperties properties = sprites.get(sprites.size() - i);
|
||||||
|
int tag = i + (quad_index << 8);
|
||||||
|
i--;
|
||||||
|
QuadPosBounds bounds = properties.bounds();
|
||||||
|
|
||||||
|
if (bounds == null) { // sprite applies anywhere e.g. default behaviour
|
||||||
|
quad.material(getRenderMaterial(getAO(model_id)));
|
||||||
|
quad.spriteBake(
|
||||||
|
properties.sprite(),
|
||||||
|
MutableQuadView.BAKE_NORMALIZED
|
||||||
|
| properties.flags()
|
||||||
|
| (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0)
|
||||||
|
);
|
||||||
|
quad.tag(tag);
|
||||||
|
quad.emit();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify if sprite covers the current quad and apply the new size
|
||||||
|
QuadPosBounds origin_bounds = QuadPosBounds.read(quad, false);
|
||||||
|
if (!bounds.matches(origin_bounds)) return i;
|
||||||
|
|
||||||
|
// apply new quad shape
|
||||||
|
quad.material(getRenderMaterial(getAO(model_id)));
|
||||||
|
bounds.intersection(origin_bounds, direction.getAxis()).apply(quad, origin_bounds);
|
||||||
|
quad.spriteBake( // seems to work without the flags and break with it
|
||||||
|
properties.sprite(),
|
||||||
|
MutableQuadView.BAKE_NORMALIZED
|
||||||
|
| MutableQuadView.BAKE_LOCK_UV
|
||||||
|
);
|
||||||
|
quad.tag(tag);
|
||||||
|
quad.emit();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
package fr.adrien1106.reframed.client.model.apperance;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||||
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||||
|
import fr.adrien1106.reframed.compat.RebakedModel;
|
||||||
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
|
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
||||||
@@ -29,63 +34,83 @@ import net.minecraft.util.math.random.Random;
|
|||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
public class CamoAppearanceManager {
|
public class CamoAppearanceManager {
|
||||||
|
|
||||||
|
|
||||||
|
protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block"));
|
||||||
|
protected static final SpriteIdentifier DEFAULT_SPRITE_SECONDARY = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_accent_block"));
|
||||||
|
private static final SpriteIdentifier BARRIER_SPRITE_ID = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier("minecraft:item/barrier"));
|
||||||
|
private static final Cache<BlockState, CamoAppearance> APPEARANCE_CACHE = CacheBuilder.newBuilder().maximumSize(2048).build();
|
||||||
|
|
||||||
public CamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
public CamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
||||||
MaterialFinder finder = ReFramedClient.HELPER.getFabricRenderer().materialFinder();
|
MaterialFinder finder = ReFramedClient.HELPER.getFabricRenderer().materialFinder();
|
||||||
for(BlendMode blend : BlendMode.values()) {
|
for(BlendMode blend : BlendMode.values()) {
|
||||||
finder.clear().disableDiffuse(false).blendMode(blend);
|
finder.clear().disableDiffuse(false).blendMode(blend);
|
||||||
|
|
||||||
materialsWithoutAo.put(blend, finder.ambientOcclusion(TriState.FALSE).find());
|
materials.put(blend, finder.ambientOcclusion(TriState.FALSE).find());
|
||||||
materialsWithAo.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO
|
ao_materials.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite sprite = spriteLookup.apply(DEFAULT_SPRITE_MAIN);
|
Sprite sprite = spriteLookup.apply(DEFAULT_SPRITE_MAIN);
|
||||||
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
||||||
this.default_appearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
this.default_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
||||||
|
|
||||||
sprite = spriteLookup.apply(DEFAULT_SPRITE_SECONDARY);
|
sprite = spriteLookup.apply(DEFAULT_SPRITE_SECONDARY);
|
||||||
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
||||||
this.accent_appearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
this.accent_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
||||||
|
|
||||||
sprite = spriteLookup.apply(BARRIER_SPRITE_ID);
|
sprite = spriteLookup.apply(BARRIER_SPRITE_ID);
|
||||||
this.barrierItemAppearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
this.barrier_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block"));
|
|
||||||
protected static final SpriteIdentifier DEFAULT_SPRITE_SECONDARY = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_accent_block"));
|
|
||||||
private static final SpriteIdentifier BARRIER_SPRITE_ID = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier("minecraft:item/barrier"));
|
|
||||||
|
|
||||||
private final CamoAppearance default_appearance;
|
private final CamoAppearance default_appearance;
|
||||||
private final CamoAppearance accent_appearance;
|
private final CamoAppearance accent_appearance;
|
||||||
private final CamoAppearance barrierItemAppearance;
|
private final CamoAppearance barrier_appearance;
|
||||||
|
|
||||||
private final ConcurrentHashMap<BlockState, CamoAppearance> appearanceCache = new ConcurrentHashMap<>(); //Mutable, append-only cache
|
|
||||||
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
|
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
|
||||||
|
|
||||||
private final EnumMap<BlendMode, RenderMaterial> materialsWithAo = new EnumMap<>(BlendMode.class);
|
private final EnumMap<BlendMode, RenderMaterial> ao_materials = new EnumMap<>(BlendMode.class);
|
||||||
private final EnumMap<BlendMode, RenderMaterial> materialsWithoutAo = new EnumMap<>(BlendMode.class); //Immutable contents
|
private final EnumMap<BlendMode, RenderMaterial> materials = new EnumMap<>(BlendMode.class); //Immutable contents
|
||||||
|
|
||||||
|
public static void dumpCahe() {
|
||||||
|
APPEARANCE_CACHE.invalidateAll();
|
||||||
|
}
|
||||||
|
|
||||||
public CamoAppearance getDefaultAppearance(int appearance) {
|
public CamoAppearance getDefaultAppearance(int appearance) {
|
||||||
return appearance == 2 ? accent_appearance: default_appearance;
|
return appearance == 2 ? accent_appearance: default_appearance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CamoAppearance getCamoAppearance(BlockRenderView world, BlockState state, BlockPos pos, int theme_index) {
|
public CamoAppearance getCamoAppearance(BlockRenderView world, BlockState state, BlockPos pos, int theme_index, boolean item) {
|
||||||
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state);
|
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state);
|
||||||
|
|
||||||
// add support for connected textures and more generally any compatible models injected so that they return baked quads
|
// add support for connected textures that uses dynamic baking
|
||||||
if (model instanceof DynamicBakedModel dynamic_model) {
|
if (model instanceof DynamicBakedModel dynamic_model) {
|
||||||
return computeAppearance(dynamic_model.computeQuads(world, state, pos, theme_index), state);
|
// cache items as they get rendered more often
|
||||||
|
if (item && APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state);
|
||||||
|
|
||||||
|
model = dynamic_model.computeQuads(world, state, pos, theme_index);
|
||||||
|
// if model isn't rebaked its just wrapped (i.e. not dynamic and may be cached)
|
||||||
|
if (model instanceof RebakedModel) {
|
||||||
|
CamoAppearance appearance = computeAppearance(model, state, !item);
|
||||||
|
if (item) APPEARANCE_CACHE.put(state, appearance);
|
||||||
|
return appearance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return appearanceCache.computeIfAbsent(state, block_state -> computeAppearance(model, block_state));
|
|
||||||
|
// refresh cache
|
||||||
|
if (APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state);
|
||||||
|
|
||||||
|
CamoAppearance appearance = computeAppearance(model, state, false);
|
||||||
|
APPEARANCE_CACHE.put(state, appearance);
|
||||||
|
return appearance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderMaterial getCachedMaterial(BlockState state, boolean ao) {
|
public RenderMaterial getCachedMaterial(BlockState state, boolean ao) {
|
||||||
Map<BlendMode, RenderMaterial> m = ao ? materialsWithAo : materialsWithoutAo;
|
Map<BlendMode, RenderMaterial> m = ao ? ao_materials : materials;
|
||||||
return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)));
|
return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,15 +118,15 @@ public class CamoAppearanceManager {
|
|||||||
// The computeIfAbsent map update will work without corrupting the map, but there will be some "wasted effort" computing the value twice.
|
// The computeIfAbsent map update will work without corrupting the map, but there will be some "wasted effort" computing the value twice.
|
||||||
// The results are going to be the same, apart from their serialNumbers differing (= their equals & hashCode differing).
|
// The results are going to be the same, apart from their serialNumbers differing (= their equals & hashCode differing).
|
||||||
// Tiny amount of wasted space in some caches if CamoAppearances are used as a map key, then. IMO it's not a critical issue.
|
// Tiny amount of wasted space in some caches if CamoAppearances are used as a map key, then. IMO it's not a critical issue.
|
||||||
private CamoAppearance computeAppearance(BakedModel model, BlockState state) {
|
private CamoAppearance computeAppearance(BakedModel model, BlockState state, boolean is_dynamic) {
|
||||||
if(state.getBlock() == Blocks.BARRIER) return barrierItemAppearance;
|
if(state.getBlock() == Blocks.BARRIER) return barrier_appearance;
|
||||||
|
|
||||||
if (!(model instanceof WeightedBakedModelAccessor weighted_model)) {
|
if (!(model instanceof WeightedBakedModelAccessor weighted_model)) {
|
||||||
return new ComputedAppearance(
|
return new ComputedAppearance(
|
||||||
getAppearance(model),
|
getAppearance(model),
|
||||||
getCachedMaterial(state, true),
|
getCachedMaterial(state, true),
|
||||||
getCachedMaterial(state, false),
|
getCachedMaterial(state, false),
|
||||||
serial_number.getAndIncrement()
|
is_dynamic ? -1 : serial_number.getAndIncrement()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
List<Weighted.Present<Appearance>> appearances = weighted_model.getModels().stream()
|
List<Weighted.Present<Appearance>> appearances = weighted_model.getModels().stream()
|
||||||
@@ -112,7 +137,7 @@ public class CamoAppearanceManager {
|
|||||||
appearances,
|
appearances,
|
||||||
getCachedMaterial(state, true),
|
getCachedMaterial(state, true),
|
||||||
getCachedMaterial(state, false),
|
getCachedMaterial(state, false),
|
||||||
serial_number.getAndIncrement()
|
is_dynamic ? -1 : serial_number.getAndIncrement()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +175,7 @@ public class CamoAppearanceManager {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Appearance(sprites);
|
return new Appearance(sprites, model.useAmbientOcclusion());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getBakeFlags(QuadEmitter emitter, Sprite sprite) {
|
private static int getBakeFlags(QuadEmitter emitter, Sprite sprite) {
|
||||||
|
|||||||
@@ -1,52 +1,43 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
package fr.adrien1106.reframed.client.model.apperance;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ComputedAppearance implements CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class ComputedAppearance extends CamoAppearance {
|
||||||
private final Appearance appearance;
|
private final Appearance appearance;
|
||||||
private final int id;
|
|
||||||
private final RenderMaterial matWithAo;
|
|
||||||
private final RenderMaterial matWithoutAo;
|
|
||||||
|
|
||||||
public ComputedAppearance(@NotNull Appearance appearance, RenderMaterial withAo, RenderMaterial withoutAo, int id) {
|
public ComputedAppearance(@NotNull Appearance appearance, RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
super(ao_material, material, id);
|
||||||
this.appearance = appearance;
|
this.appearance = appearance;
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
this.matWithAo = withAo;
|
|
||||||
this.matWithoutAo = withoutAo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return ao ? matWithAo : matWithoutAo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
|
||||||
return appearance.sprites().get(dir);
|
return appearance.sprites().get(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
List<SpriteProperties> properties = getSprites(dir, model_id);
|
||||||
if (index != 0) index = properties.size() - index;
|
if (index != 0) index = properties.size() - index;
|
||||||
return properties.get(index).has_colors();
|
return properties.get(index).has_colors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean getAO(int model_id) {
|
||||||
if(this == o) return true;
|
return appearance.use_ao();
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
|
||||||
ComputedAppearance that = (ComputedAppearance) o;
|
|
||||||
return id == that.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public boolean equals(Object o) {
|
||||||
return id;
|
if(this == o) return true;
|
||||||
|
if(!(o instanceof ComputedAppearance that)) return false;
|
||||||
|
return id == that.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
package fr.adrien1106.reframed.client.model.apperance;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
@@ -7,47 +9,40 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SingleSpriteAppearance implements CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class SingleSpriteAppearance extends CamoAppearance {
|
||||||
private final @NotNull Sprite defaultSprite;
|
private final @NotNull Sprite defaultSprite;
|
||||||
private final RenderMaterial mat;
|
|
||||||
private final int id;
|
|
||||||
|
|
||||||
public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) {
|
public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) {
|
||||||
|
super(null, mat, id);
|
||||||
this.defaultSprite = defaultSprite;
|
this.defaultSprite = defaultSprite;
|
||||||
this.mat = mat;
|
|
||||||
this.id = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
|
||||||
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof SingleSpriteAppearance that)) return false;
|
||||||
SingleSpriteAppearance that = (SingleSpriteAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public boolean getAO(int model_id) {
|
||||||
return id;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SingleSpriteAppearance[defaultSprite=%s, mat=%s, id=%d]".formatted(defaultSprite, mat, id);
|
return "SingleSpriteAppearance[defaultSprite=%s, mat=%s, id=%d]".formatted(defaultSprite, material, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
package fr.adrien1106.reframed.client.model.apperance;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
import net.minecraft.util.collection.Weighted;
|
import net.minecraft.util.collection.Weighted;
|
||||||
import net.minecraft.util.collection.Weighting;
|
import net.minecraft.util.collection.Weighting;
|
||||||
@@ -9,25 +11,15 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WeightedComputedAppearance implements CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class WeightedComputedAppearance extends CamoAppearance {
|
||||||
private final List<Weighted.Present<Appearance>> appearances;
|
private final List<Weighted.Present<Appearance>> appearances;
|
||||||
private final int total_weight;
|
private final int total_weight;
|
||||||
private final int id;
|
|
||||||
private final RenderMaterial matWithAo;
|
|
||||||
private final RenderMaterial matWithoutAo;
|
|
||||||
|
|
||||||
public WeightedComputedAppearance(@NotNull List<Weighted.Present<Appearance>> appearances, RenderMaterial withAo, RenderMaterial withoutAo, int id) {
|
public WeightedComputedAppearance(@NotNull List<Weighted.Present<Appearance>> appearances, RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
super(ao_material, material, id);
|
||||||
this.appearances = appearances;
|
this.appearances = appearances;
|
||||||
this.total_weight = Weighting.getWeightSum(appearances);
|
this.total_weight = Weighting.getWeightSum(appearances);
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
this.matWithAo = withAo;
|
|
||||||
this.matWithoutAo = withoutAo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
|
||||||
return ao ? matWithAo : matWithoutAo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -37,35 +29,33 @@ public class WeightedComputedAppearance implements CamoAppearance {
|
|||||||
.map(appearances::indexOf).orElse(0);
|
.map(appearances::indexOf).orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Appearance getAppearance(long seed) {
|
private Appearance getAppearance(int model_id) {
|
||||||
Random random = Random.create(seed);
|
return appearances.get(model_id).getData();
|
||||||
return Weighting.getAt(appearances, Math.abs((int)random.nextLong()) % total_weight)
|
|
||||||
.map(Weighted.Present::getData).get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return getAppearance(seed).sprites().get(dir);
|
return getAppearance(model_id).sprites().get(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
List<SpriteProperties> properties = getSprites(dir, model_id);
|
||||||
if (index != 0) index = properties.size() - index;
|
if (index != 0) index = properties.size() - index;
|
||||||
return properties.get(index).has_colors();
|
return properties.get(index).has_colors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean getAO(int model_id) {
|
||||||
if(this == o) return true;
|
return getAppearance(model_id).use_ao();
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
|
||||||
WeightedComputedAppearance that = (WeightedComputedAppearance) o;
|
|
||||||
return id == that.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public boolean equals(Object o) {
|
||||||
return id;
|
if(this == o) return true;
|
||||||
|
if(!(o instanceof WeightedComputedAppearance that)) return false;
|
||||||
|
return id == that.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
package fr.adrien1106.reframed.client.util;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
|
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||||
|
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static net.minecraft.util.shape.VoxelShapes.combine;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class RenderHelper {
|
||||||
|
|
||||||
|
// self culling cache of the models not made thread local so that it is only computed once
|
||||||
|
private static final Cache<CullElement, Integer[]> INNER_CULL_MAP = CacheBuilder.newBuilder().build();
|
||||||
|
private record CullElement(Block block, Object state_key, int model) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compute which quad might cull with another model quad
|
||||||
|
* @param state - the state of the model
|
||||||
|
* @param models - list of models on the same block
|
||||||
|
* @param hash - the hash of main model
|
||||||
|
*/
|
||||||
|
public static void computeInnerCull(BlockState state, List<RetexturingBakedModel> models, int hash) {
|
||||||
|
if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return;
|
||||||
|
if (INNER_CULL_MAP.asMap().containsKey(new CullElement(frame_block, hash, 1))) return;
|
||||||
|
|
||||||
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
|
QuadEmitter quad_emitter = r.meshBuilder().getEmitter();
|
||||||
|
RenderMaterial material = r.materialFinder().clear().find();
|
||||||
|
Random random = Random.create();
|
||||||
|
|
||||||
|
List<List<QuadPosBounds>> model_bounds = models.stream()
|
||||||
|
.map(wrapped -> wrapped.getQuads(state, null, random))
|
||||||
|
.map(quads -> quads.stream().map(quad -> {
|
||||||
|
quad_emitter.fromVanilla(quad, material, null);
|
||||||
|
return QuadPosBounds.read(quad_emitter, false);
|
||||||
|
}).toList()).toList();
|
||||||
|
|
||||||
|
Integer[] cull_array;
|
||||||
|
for (int self_id = 1; self_id <= model_bounds.size(); self_id++) {
|
||||||
|
List<QuadPosBounds> self_bounds = model_bounds.get(self_id - 1);
|
||||||
|
cull_array = new Integer[self_bounds.size()];
|
||||||
|
for (int self_quad = 0; self_quad < cull_array.length; self_quad++) {
|
||||||
|
QuadPosBounds self_bound = self_bounds.get(self_quad);
|
||||||
|
for (int other_id = 1; other_id <= model_bounds.size(); other_id++) {
|
||||||
|
if (other_id == self_id) continue;
|
||||||
|
if (model_bounds.get(other_id - 1).stream().anyMatch(other_bound -> other_bound.equals(self_bound))) {
|
||||||
|
cull_array[self_quad] = other_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
INNER_CULL_MAP.put(new CullElement(frame_block, hash, self_id), cull_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index, int hash) {
|
||||||
|
if (!(state.getBlock() instanceof ReFramedBlock frame_block)
|
||||||
|
|| !(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)
|
||||||
|
) return true;
|
||||||
|
CullElement key = new CullElement(frame_block, hash, theme_index);
|
||||||
|
if (!INNER_CULL_MAP.asMap().containsKey(key)) return true;
|
||||||
|
|
||||||
|
// needs to be Integer object because array is initialized with null not 0
|
||||||
|
Integer cull_theme = Objects.requireNonNull(INNER_CULL_MAP.getIfPresent(key))[quad_index];
|
||||||
|
if (cull_theme == null) return true; // no culling possible
|
||||||
|
|
||||||
|
BlockState self_theme = frame_entity.getTheme(theme_index);
|
||||||
|
BlockState other_theme = frame_entity.getTheme(cull_theme);
|
||||||
|
|
||||||
|
if (self_theme.isSideInvisible(other_theme, null)) return false;
|
||||||
|
return !self_theme.isOpaque() || !other_theme.isOpaque();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doing this method from scratch as it is simpler to do than injecting everywhere
|
||||||
|
public static boolean shouldDrawSide(BlockState self_state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, int theme_index) {
|
||||||
|
BlockState other_state = world.getBlockState(other_pos);
|
||||||
|
ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e
|
||||||
|
&& self_state.getBlock() instanceof ReFramedBlock
|
||||||
|
? e : null;
|
||||||
|
ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e
|
||||||
|
&& other_state.getBlock() instanceof ReFramedBlock
|
||||||
|
? e : null;
|
||||||
|
|
||||||
|
// normal behaviour
|
||||||
|
if (theme_index == 0 || (self == null && other == null))
|
||||||
|
return Block.shouldDrawSide(self_state, world, pos, side, other_pos);
|
||||||
|
|
||||||
|
// self is a normal Block
|
||||||
|
if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) {
|
||||||
|
VoxelShape self_shape = self_state.getCullingShape(world, pos);
|
||||||
|
if (self_shape.isEmpty()) return true;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
VoxelShape other_shape = VoxelShapes.empty();
|
||||||
|
for (BlockState s: other.getThemes()) {
|
||||||
|
i++;
|
||||||
|
if (self_state.isSideInvisible(s, side) || s.isOpaque())
|
||||||
|
other_shape = combine(
|
||||||
|
other_shape,
|
||||||
|
other_block
|
||||||
|
.getShape(other_state, i)
|
||||||
|
.getFace(side.getOpposite()),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if side needs to be rendered
|
||||||
|
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState self_theme = self.getTheme(theme_index);
|
||||||
|
// other is normal Block
|
||||||
|
if (other == null && self_state.getBlock() instanceof ReFramedBlock self_block) {
|
||||||
|
// Transparent is simple if self and the neighbor are invisible don't render side (like default)
|
||||||
|
if (self_theme.isSideInvisible(other_state, side)) return false;
|
||||||
|
|
||||||
|
// Opaque is also simple as each model are rendered one by one
|
||||||
|
if (other_state.isOpaque()) {
|
||||||
|
// no cache section :( because it differs between each instance of the frame
|
||||||
|
VoxelShape self_shape = self_block.getShape(self_state, theme_index).getFace(side);
|
||||||
|
if (self_shape.isEmpty()) return true;
|
||||||
|
VoxelShape other_shape = other_state.getCullingFace(world, other_pos, side.getOpposite());
|
||||||
|
|
||||||
|
// determine if side needs to be rendered
|
||||||
|
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both are frames
|
||||||
|
// here both are computed in the same zone as there will necessarily a shape comparison
|
||||||
|
if (self_state.getBlock() instanceof ReFramedBlock self_block && other_state.getBlock() instanceof ReFramedBlock other_block) {
|
||||||
|
VoxelShape self_shape = self_block.getShape(self_state, theme_index).getFace(side);
|
||||||
|
if (self_shape.isEmpty()) return true;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
VoxelShape other_shape = VoxelShapes.empty();
|
||||||
|
for (BlockState s: other.getThemes()) {
|
||||||
|
i++;
|
||||||
|
if (self_theme.isSideInvisible(s, side) || s.isOpaque())
|
||||||
|
other_shape = combine(
|
||||||
|
other_shape,
|
||||||
|
other_block
|
||||||
|
.getShape(other_state, i)
|
||||||
|
.getFace(side.getOpposite()),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if side needs to be rendered
|
||||||
|
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package fr.adrien1106.reframed.compat;
|
||||||
|
|
||||||
|
import me.pepperbell.continuity.client.model.QuadProcessors;
|
||||||
|
import me.pepperbell.continuity.impl.client.ProcessingContextImpl;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public interface ICTMQuadTransform extends RenderContext.QuadTransform {
|
||||||
|
|
||||||
|
void invokePrepare(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> random, boolean manual_culling, Function<Sprite, QuadProcessors.Slice> slice);
|
||||||
|
|
||||||
|
ProcessingContextImpl getProcessingContext();
|
||||||
|
|
||||||
|
void invokeReset();
|
||||||
|
}
|
||||||
@@ -12,11 +12,13 @@ import net.minecraft.util.math.random.Random;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class RebakedAthenaModel implements BakedModel {
|
public class RebakedModel implements BakedModel {
|
||||||
protected final Map<Direction, List<BakedQuad>> face_quads;
|
protected final Map<Direction, List<BakedQuad>> face_quads;
|
||||||
|
protected boolean ambient_occlusion;
|
||||||
|
|
||||||
public RebakedAthenaModel(Map<Direction, List<BakedQuad>> face_quads) {
|
public RebakedModel(Map<Direction, List<BakedQuad>> face_quads, boolean ambient_occlusion) {
|
||||||
this.face_quads = face_quads;
|
this.face_quads = face_quads;
|
||||||
|
this.ambient_occlusion = ambient_occlusion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -26,7 +28,7 @@ public class RebakedAthenaModel implements BakedModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useAmbientOcclusion() {
|
public boolean useAmbientOcclusion() {
|
||||||
return false;
|
return ambient_occlusion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,11 +53,11 @@ public class RebakedAthenaModel implements BakedModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelTransformation getTransformation() {
|
public ModelTransformation getTransformation() {
|
||||||
return null;
|
return ModelTransformation.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelOverrideList getOverrides() {
|
public ModelOverrideList getOverrides() {
|
||||||
return null;
|
return ModelOverrideList.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.generator;
|
package fr.adrien1106.reframed.generator;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.data.client.BlockStateSupplier;
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
|
||||||
public interface BlockStateProvider {
|
public interface BlockStateProvider {
|
||||||
BlockStateSupplier getMultipart();
|
BlockStateSupplier getMultipart(Block block);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
package fr.adrien1106.reframed.generator;
|
package fr.adrien1106.reframed.generator;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.*;
|
||||||
|
import fr.adrien1106.reframed.generator.block.*;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider.BlockTagProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider.BlockTagProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
|
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
|
||||||
import net.minecraft.registry.tag.BlockTags;
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class GBlockTag extends BlockTagProvider {
|
public class GBlockTag extends BlockTagProvider {
|
||||||
|
private static final Map<Class<? extends Block>, TagGetter> providers = new HashMap<>();
|
||||||
|
static {
|
||||||
|
providers.put(ReFramedPillarsWallBlock.class, new PillarsWall());
|
||||||
|
providers.put(ReFramedWallBlock.class, new Wall());
|
||||||
|
providers.put(ReFramedPaneBlock.class, new Pane());
|
||||||
|
providers.put(ReFramedFenceBlock.class, new Fence());
|
||||||
|
providers.put(ReFramedPostFenceBlock.class, new PostFence());
|
||||||
|
}
|
||||||
|
|
||||||
public GBlockTag(FabricDataOutput output, CompletableFuture<WrapperLookup> registries) {
|
public GBlockTag(FabricDataOutput output, CompletableFuture<WrapperLookup> registries) {
|
||||||
super(output, registries);
|
super(output, registries);
|
||||||
@@ -17,6 +30,10 @@ public class GBlockTag extends BlockTagProvider {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure(WrapperLookup arg) {
|
protected void configure(WrapperLookup arg) {
|
||||||
FabricTagBuilder builder = getOrCreateTagBuilder(BlockTags.AXE_MINEABLE);
|
FabricTagBuilder builder = getOrCreateTagBuilder(BlockTags.AXE_MINEABLE);
|
||||||
ReFramed.BLOCKS.forEach(builder::add);
|
ReFramed.BLOCKS.forEach((block) -> {
|
||||||
|
if (providers.containsKey(block.getClass()))
|
||||||
|
providers.get(block.getClass()).getTags().forEach((tag) -> getOrCreateTagBuilder(tag).add(block));
|
||||||
|
builder.add(block);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,47 @@
|
|||||||
package fr.adrien1106.reframed.generator;
|
package fr.adrien1106.reframed.generator;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.*;
|
||||||
|
import fr.adrien1106.reframed.generator.block.*;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.data.client.*;
|
import net.minecraft.data.client.*;
|
||||||
import net.minecraft.state.property.Property;
|
import net.minecraft.state.property.Property;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
|
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
|
||||||
|
|
||||||
public class GBlockstate extends FabricModelProvider {
|
public class GBlockstate extends FabricModelProvider {
|
||||||
|
private static final Map<Class<? extends Block>, BlockStateProvider> providers = new HashMap<>();
|
||||||
|
static {
|
||||||
|
providers.put(ReFramedHalfStairBlock.class, new HalfStair());
|
||||||
|
providers.put(ReFramedHalfStairsSlabBlock.class, new HalfStairsSlab());
|
||||||
|
providers.put(ReFramedHalfStairsStairBlock.class, new HalfStairsStair());
|
||||||
|
providers.put(ReFramedLayerBlock.class, new Layer());
|
||||||
|
providers.put(ReFramedPillarBlock.class, new Pillar());
|
||||||
|
providers.put(ReFramedSlabBlock.class, new Slab());
|
||||||
|
providers.put(ReFramedSlabsCubeBlock.class, new SlabsCube());
|
||||||
|
providers.put(ReFramedSmallCubeBlock.class, new SmallCube());
|
||||||
|
providers.put(ReFramedSmallCubesStepBlock.class, new SmallCubesStep());
|
||||||
|
providers.put(ReFramedStairBlock.class, new Stair());
|
||||||
|
providers.put(ReFramedStairsCubeBlock.class, new StairsCube());
|
||||||
|
providers.put(ReFramedStepBlock.class, new Step());
|
||||||
|
providers.put(ReFramedStepsSlabBlock.class, new StepsSlab());
|
||||||
|
providers.put(ReFramedPillarsWallBlock.class, new PillarsWall());
|
||||||
|
providers.put(ReFramedWallBlock.class, new Wall());
|
||||||
|
providers.put(ReFramedPaneBlock.class, new Pane());
|
||||||
|
providers.put(ReFramedTrapdoorBlock.class, new Trapdoor());
|
||||||
|
providers.put(ReFramedDoorBlock.class, new Door());
|
||||||
|
providers.put(ReFramedButtonBlock.class, new Button());
|
||||||
|
providers.put(ReFramedPostBlock.class, new Post());
|
||||||
|
providers.put(ReFramedFenceBlock.class, new Fence());
|
||||||
|
providers.put(ReFramedPostFenceBlock.class, new PostFence());
|
||||||
|
}
|
||||||
|
|
||||||
public GBlockstate(FabricDataOutput output) {
|
public GBlockstate(FabricDataOutput output) {
|
||||||
super(output);
|
super(output);
|
||||||
@@ -23,7 +53,7 @@ public class GBlockstate extends FabricModelProvider {
|
|||||||
.forEach(model_generator::excludeFromSimpleItemModelGeneration);
|
.forEach(model_generator::excludeFromSimpleItemModelGeneration);
|
||||||
ReFramed.BLOCKS.stream()
|
ReFramed.BLOCKS.stream()
|
||||||
.map(block -> {
|
.map(block -> {
|
||||||
if (block instanceof BlockStateProvider multipart_block) return multipart_block.getMultipart();
|
if (providers.containsKey(block.getClass())) return providers.get(block.getClass()).getMultipart(block);
|
||||||
return VariantsBlockStateSupplier.create(
|
return VariantsBlockStateSupplier.create(
|
||||||
block,
|
block,
|
||||||
GBlockstate.variant(
|
GBlockstate.variant(
|
||||||
@@ -38,7 +68,9 @@ public class GBlockstate extends FabricModelProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateItemModels(ItemModelGenerator itemModelGenerator) {}
|
public void generateItemModels(ItemModelGenerator model_generator) {
|
||||||
|
ReFramed.ITEMS.forEach(item -> model_generator.register(item, Models.GENERATED));
|
||||||
|
}
|
||||||
|
|
||||||
public static BlockStateVariant variant(Identifier model, boolean uv_lock, VariantSettings.Rotation x, VariantSettings.Rotation y) {
|
public static BlockStateVariant variant(Identifier model, boolean uv_lock, VariantSettings.Rotation x, VariantSettings.Rotation y) {
|
||||||
BlockStateVariant variant = BlockStateVariant.create().put(VariantSettings.MODEL, model);
|
BlockStateVariant variant = BlockStateVariant.create().put(VariantSettings.MODEL, model);
|
||||||
@@ -52,11 +84,57 @@ public class GBlockstate extends FabricModelProvider {
|
|||||||
return When.create().set(property_1, value_1);
|
return When.create().set(property_1, value_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Comparable<T>, U extends Comparable<U>> When when(Property<T> property_1, T value_1, Property<U> property_2, U value_2) {
|
public static <T extends Comparable<T>,
|
||||||
return When.allOf(when(property_1, value_1), when(property_2, value_2));
|
U extends Comparable<U>> When when(Property<T> property_1, T value_1,
|
||||||
|
Property<U> property_2, U value_2) {
|
||||||
|
return When.allOf(
|
||||||
|
when(property_1, value_1),
|
||||||
|
when(property_2, value_2)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Comparable<T>, U extends Comparable<U>, V extends Comparable<V>> When when(Property<T> property_1, T value_1, Property<U> property_2, U value_2, Property<V> property_3, V value_3) {
|
public static <T extends Comparable<T>,
|
||||||
return When.allOf(when(property_1, value_1), when(property_2, value_2), when(property_3, value_3));
|
U extends Comparable<U>,
|
||||||
|
V extends Comparable<V>> When when(Property<T> property_1, T value_1,
|
||||||
|
Property<U> property_2, U value_2,
|
||||||
|
Property<V> property_3, V value_3) {
|
||||||
|
return When.allOf(
|
||||||
|
when(property_1, value_1),
|
||||||
|
when(property_2, value_2),
|
||||||
|
when(property_3, value_3)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Comparable<T>,
|
||||||
|
U extends Comparable<U>,
|
||||||
|
V extends Comparable<V>,
|
||||||
|
W extends Comparable<W>> When when(Property<T> property_1, T value_1,
|
||||||
|
Property<U> property_2, U value_2,
|
||||||
|
Property<V> property_3, V value_3,
|
||||||
|
Property<W> property_4, W value_4) {
|
||||||
|
return When.allOf(
|
||||||
|
when(property_1, value_1),
|
||||||
|
when(property_2, value_2),
|
||||||
|
when(property_3, value_3),
|
||||||
|
when(property_4, value_4)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Comparable<T>,
|
||||||
|
U extends Comparable<U>,
|
||||||
|
V extends Comparable<V>,
|
||||||
|
W extends Comparable<W>,
|
||||||
|
X extends Comparable<X>> When when(Property<T> property_1, T value_1,
|
||||||
|
Property<U> property_2, U value_2,
|
||||||
|
Property<V> property_3, V value_3,
|
||||||
|
Property<W> property_4, W value_4,
|
||||||
|
Property<X> property_5, X value_5) {
|
||||||
|
return When.allOf(
|
||||||
|
when(property_1, value_1),
|
||||||
|
when(property_2, value_2),
|
||||||
|
when(property_3, value_3),
|
||||||
|
when(property_4, value_4),
|
||||||
|
when(property_5, value_5)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,9 +17,8 @@ public class GLanguage extends FabricLanguageProvider {
|
|||||||
public void generateTranslations(TranslationBuilder builder) {
|
public void generateTranslations(TranslationBuilder builder) {
|
||||||
builder.add(Registries.ITEM_GROUP.getKey(ReFramed.ITEM_GROUP).get(), "Frames");
|
builder.add(Registries.ITEM_GROUP.getKey(ReFramed.ITEM_GROUP).get(), "Frames");
|
||||||
builder.add("advancements.reframed.description", "Get all the frame types.");
|
builder.add("advancements.reframed.description", "Get all the frame types.");
|
||||||
ReFramed.BLOCKS.forEach(block -> {
|
ReFramed.BLOCKS.forEach(block -> builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame"));
|
||||||
builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame");
|
ReFramed.ITEMS.forEach(block -> builder.add(block, beautify(Registries.ITEM.getId(block).getPath())));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String beautify(String name) {
|
private static String beautify(String name) {
|
||||||
|
|||||||
@@ -1,11 +1,53 @@
|
|||||||
package fr.adrien1106.reframed.generator;
|
package fr.adrien1106.reframed.generator;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.*;
|
||||||
|
import fr.adrien1106.reframed.generator.block.*;
|
||||||
|
import fr.adrien1106.reframed.generator.item.Blueprint;
|
||||||
|
import fr.adrien1106.reframed.generator.item.Hammer;
|
||||||
|
import fr.adrien1106.reframed.generator.item.Screwdriver;
|
||||||
|
import fr.adrien1106.reframed.item.ReFramedBlueprintItem;
|
||||||
|
import fr.adrien1106.reframed.item.ReFramedHammerItem;
|
||||||
|
import fr.adrien1106.reframed.item.ReFramedScrewdriverItem;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class GRecipe extends FabricRecipeProvider {
|
public class GRecipe extends FabricRecipeProvider {
|
||||||
|
private static final Map<Class<? extends ItemConvertible>, RecipeSetter> providers = new HashMap<>();
|
||||||
|
static {
|
||||||
|
providers.put(ReFramedBlock.class, new Cube());
|
||||||
|
providers.put(ReFramedHalfStairBlock.class, new HalfStair());
|
||||||
|
providers.put(ReFramedHalfStairsSlabBlock.class, new HalfStairsSlab());
|
||||||
|
providers.put(ReFramedHalfStairsStairBlock.class, new HalfStairsStair());
|
||||||
|
providers.put(ReFramedLayerBlock.class, new Layer());
|
||||||
|
providers.put(ReFramedPillarBlock.class, new Pillar());
|
||||||
|
providers.put(ReFramedSlabBlock.class, new Slab());
|
||||||
|
providers.put(ReFramedSlabsCubeBlock.class, new SlabsCube());
|
||||||
|
providers.put(ReFramedSmallCubeBlock.class, new SmallCube());
|
||||||
|
providers.put(ReFramedSmallCubesStepBlock.class, new SmallCubesStep());
|
||||||
|
providers.put(ReFramedStairBlock.class, new Stair());
|
||||||
|
providers.put(ReFramedStairsCubeBlock.class, new StairsCube());
|
||||||
|
providers.put(ReFramedStepBlock.class, new Step());
|
||||||
|
providers.put(ReFramedStepsSlabBlock.class, new StepsSlab());
|
||||||
|
providers.put(ReFramedPillarsWallBlock.class, new PillarsWall());
|
||||||
|
providers.put(ReFramedWallBlock.class, new Wall());
|
||||||
|
providers.put(ReFramedPaneBlock.class, new Pane());
|
||||||
|
providers.put(ReFramedTrapdoorBlock.class, new Trapdoor());
|
||||||
|
providers.put(ReFramedDoorBlock.class, new Door());
|
||||||
|
providers.put(ReFramedButtonBlock.class, new Button());
|
||||||
|
providers.put(ReFramedPostBlock.class, new Post());
|
||||||
|
providers.put(ReFramedFenceBlock.class, new Fence());
|
||||||
|
providers.put(ReFramedPostFenceBlock.class, new PostFence());
|
||||||
|
providers.put(ReFramedBlueprintItem.class, new Blueprint());
|
||||||
|
providers.put(ReFramedHammerItem.class, new Hammer());
|
||||||
|
providers.put(ReFramedScrewdriverItem.class, new Screwdriver());
|
||||||
|
}
|
||||||
|
|
||||||
public GRecipe(FabricDataOutput output) {
|
public GRecipe(FabricDataOutput output) {
|
||||||
super(output);
|
super(output);
|
||||||
}
|
}
|
||||||
@@ -13,7 +55,10 @@ public class GRecipe extends FabricRecipeProvider {
|
|||||||
@Override
|
@Override
|
||||||
public void generate(RecipeExporter exporter) {
|
public void generate(RecipeExporter exporter) {
|
||||||
ReFramed.BLOCKS.forEach(block -> {
|
ReFramed.BLOCKS.forEach(block -> {
|
||||||
if (block instanceof RecipeSetter provider) provider.setRecipe(exporter);
|
if (providers.containsKey(block.getClass())) providers.get(block.getClass()).setRecipe(exporter, block);
|
||||||
|
});
|
||||||
|
ReFramed.ITEMS.forEach(item -> {
|
||||||
|
if (providers.containsKey(item.getClass())) providers.get(item.getClass()).setRecipe(exporter, item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package fr.adrien1106.reframed.generator;
|
package fr.adrien1106.reframed.generator;
|
||||||
|
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
|
||||||
public interface RecipeSetter {
|
public interface RecipeSetter {
|
||||||
|
|
||||||
void setRecipe(RecipeExporter exporter);
|
void setRecipe(RecipeExporter exporter, ItemConvertible convertible);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package fr.adrien1106.reframed.generator;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface TagGetter {
|
||||||
|
|
||||||
|
List<TagKey<Block>> getTags();
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.enums.BlockFace;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Button implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 8);
|
||||||
|
ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, convertible, 1)
|
||||||
|
.input(ReFramed.CUBE, 1)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier button = ReFramed.id("button_special");
|
||||||
|
Identifier button_pressed = ReFramed.id("button_pressed_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
// FLOOR OFF
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R270))
|
||||||
|
// CEILING OFF
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R270))
|
||||||
|
// WALL OFF
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R270))
|
||||||
|
// FLOOR ON
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R270))
|
||||||
|
// CEILING ON
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R270))
|
||||||
|
// WALL ON
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
|
||||||
|
public class Cube implements RecipeSetter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.pattern("III")
|
||||||
|
.pattern("I~I")
|
||||||
|
.pattern("III")
|
||||||
|
.input('I', Items.BAMBOO)
|
||||||
|
.input('~', Items.STRING)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(Items.BAMBOO), FabricRecipeProvider.conditionsFromItem(Items.BAMBOO))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.When;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.block.enums.DoorHinge.*;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Door implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 1);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 3)
|
||||||
|
.pattern("II")
|
||||||
|
.pattern("II")
|
||||||
|
.pattern("II")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier door = ReFramed.id("trapdoor_open_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
// SOUTH
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.SOUTH),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.EAST, DOOR_HINGE, LEFT),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.WEST, DOOR_HINGE, RIGHT)
|
||||||
|
),
|
||||||
|
GBlockstate.variant(door, true, R0, R0))
|
||||||
|
// WEST
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.WEST),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.SOUTH, DOOR_HINGE, LEFT),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.NORTH, DOOR_HINGE, RIGHT)
|
||||||
|
),
|
||||||
|
GBlockstate.variant(door, true, R0, R90))
|
||||||
|
// NORTH
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.NORTH),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.WEST, DOOR_HINGE, LEFT),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.EAST, DOOR_HINGE, RIGHT)
|
||||||
|
),
|
||||||
|
GBlockstate.variant(door, true, R0, R180))
|
||||||
|
// EAST
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.EAST),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.NORTH, DOOR_HINGE, LEFT),
|
||||||
|
GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.SOUTH, DOOR_HINGE, RIGHT)
|
||||||
|
),
|
||||||
|
GBlockstate.variant(door, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Fence implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
|
||||||
|
.pattern("I-I")
|
||||||
|
.pattern("I-I")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.input('-', Blocks.BAMBOO)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.FENCES, BlockTags.WOODEN_FENCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier side_on = ReFramed.id("fence_side_on_special");
|
||||||
|
Identifier side_off = ReFramed.id("fence_side_off_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.variant(ReFramed.id("fence_core_special"), true, R0, R0))
|
||||||
|
// SIDE ON
|
||||||
|
.with(GBlockstate.when(NORTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R270))
|
||||||
|
// SIDE OFF
|
||||||
|
.with(GBlockstate.when(NORTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER_FACE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.NORTH_EAST_UP;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
|
public class HalfStair implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
|
||||||
|
.pattern("I ")
|
||||||
|
.pattern("II")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
return getMultipart(
|
||||||
|
block,
|
||||||
|
ReFramed.id("half_stair_down_special"),
|
||||||
|
ReFramed.id("half_stair_side_special")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockStateSupplier getMultipart(Block block, Identifier model_down, Identifier model_side) {
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R90, R270))
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R0, R0))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R0, R90))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R0, R180))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R0, R270))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R270, R90))
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R180, R0))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R270, R180))
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R180, R90))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R270, R270))
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R180, R180))
|
||||||
|
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 0),
|
||||||
|
GBlockstate.variant(model_side, true, R180, R270))
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 1),
|
||||||
|
GBlockstate.variant(model_side, true, R270, R0))
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 2),
|
||||||
|
GBlockstate.variant(model_down, true, R180, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
|
||||||
|
public class HalfStairsSlab implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.input(ReFramed.HALF_STAIR)
|
||||||
|
.input(ReFramed.SMALL_CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
return HalfStair.getMultipart(
|
||||||
|
block,
|
||||||
|
ReFramed.id("half_stairs_slab_down_special"),
|
||||||
|
ReFramed.id("half_stairs_slab_side_special")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.WEST_DOWN;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
|
public class HalfStairsStair implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.input(ReFramed.HALF_STAIR, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("half_stairs_stair_down_special");
|
||||||
|
Identifier side_model_id = ReFramed.id("half_stairs_stair_side_special");
|
||||||
|
Identifier reverse_model_id = ReFramed.id("half_stairs_stair_reverse_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
/* X AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_DOWN),
|
||||||
|
GBlockstate.variant(side_model_id, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
|
||||||
|
GBlockstate.variant(side_model_id, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_UP),
|
||||||
|
GBlockstate.variant(side_model_id, true, R270, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_NORTH),
|
||||||
|
GBlockstate.variant(side_model_id, true, R180, R180))
|
||||||
|
/* Y AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_EAST),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_SOUTH),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_WEST),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_NORTH),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R270))
|
||||||
|
/* Z AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_EAST),
|
||||||
|
GBlockstate.variant(reverse_model_id, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_UP),
|
||||||
|
GBlockstate.variant(side_model_id, true, R180, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_WEST),
|
||||||
|
GBlockstate.variant(reverse_model_id, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_DOWN),
|
||||||
|
GBlockstate.variant(side_model_id, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
|
import static net.minecraft.state.property.Properties.LAYERS;
|
||||||
|
|
||||||
|
public class Layer implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 8);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 16)
|
||||||
|
.pattern("II")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartBlockStateSupplier getMultipart(Block block) {
|
||||||
|
String model_pattern = "layer_x_special";
|
||||||
|
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(block);
|
||||||
|
for (int i = 1; i <= 8; i++) {
|
||||||
|
Identifier model = ReFramed.id(model_pattern.replace("x", i + ""));
|
||||||
|
supplier
|
||||||
|
.with(GBlockstate.when(FACING, Direction.DOWN, LAYERS, i),
|
||||||
|
GBlockstate.variant(model, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.SOUTH, LAYERS, i),
|
||||||
|
GBlockstate.variant(model, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.UP, LAYERS, i),
|
||||||
|
GBlockstate.variant(model, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.NORTH, LAYERS, i),
|
||||||
|
GBlockstate.variant(model, true, R270, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.WEST, LAYERS, i),
|
||||||
|
GBlockstate.variant(model, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.EAST, LAYERS, i),
|
||||||
|
GBlockstate.variant(model, true, R90, R270));
|
||||||
|
}
|
||||||
|
return supplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Pane implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 32)
|
||||||
|
.pattern("III")
|
||||||
|
.pattern("I I")
|
||||||
|
.pattern("III")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.WALLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier
|
||||||
|
pane_side = ReFramed.id("pane_side_special"),
|
||||||
|
pane_side_alt = ReFramed.id("pane_side_alt_special"),
|
||||||
|
pane_noside = ReFramed.id("pane_noside_special"),
|
||||||
|
pane_noside_alt = ReFramed.id("pane_noside_alt_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
// PILLAR CORE
|
||||||
|
.with(GBlockstate.variant(ReFramed.id("pane_post_special"), true, R0, R0))
|
||||||
|
// SIDE
|
||||||
|
.with(GBlockstate.when(NORTH, true),
|
||||||
|
GBlockstate.variant(pane_side, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, true),
|
||||||
|
GBlockstate.variant(pane_side, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, true),
|
||||||
|
GBlockstate.variant(pane_side_alt, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(WEST, true),
|
||||||
|
GBlockstate.variant(pane_side_alt, true, R0, R90))
|
||||||
|
// NOSIDE
|
||||||
|
.with(GBlockstate.when(NORTH, false),
|
||||||
|
GBlockstate.variant(pane_noside, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, false),
|
||||||
|
GBlockstate.variant(pane_noside_alt, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(SOUTH, false),
|
||||||
|
GBlockstate.variant(pane_noside_alt, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(WEST, false),
|
||||||
|
GBlockstate.variant(pane_noside, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class Pillar implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 8)
|
||||||
|
.pattern("I")
|
||||||
|
.pattern("I")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("pillar_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R0));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.block.enums.WallShape.*;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class PillarsWall implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 1);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 2)
|
||||||
|
.input(ReFramed.WALL, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.WALLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier
|
||||||
|
low = ReFramed.id("pillars_wall_low_special"),
|
||||||
|
tall = ReFramed.id("pillars_wall_tall_special"),
|
||||||
|
none = ReFramed.id("wall_pillar_none_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
// PILLAR CORE
|
||||||
|
.with(GBlockstate.variant(ReFramed.id("wall_core_special"), true, R0, R0))
|
||||||
|
// LOW
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(low, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(low, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(low, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(low, true, R0, R270))
|
||||||
|
// TALL
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(tall, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(tall, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(tall, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(tall, true, R0, R270))
|
||||||
|
// PILLAR NONE
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, NONE),
|
||||||
|
GBlockstate.variant(none, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, NONE),
|
||||||
|
GBlockstate.variant(none, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, NONE),
|
||||||
|
GBlockstate.variant(none, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, NONE),
|
||||||
|
GBlockstate.variant(none, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class Post implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 6);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 12)
|
||||||
|
.pattern("I")
|
||||||
|
.pattern("I")
|
||||||
|
.pattern("I")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("post_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R0));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class PostFence implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.FENCE, 1);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 2)
|
||||||
|
.input(ReFramed.FENCE, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.FENCES, BlockTags.WOODEN_FENCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier side_on = ReFramed.id("post_fence_side_special");
|
||||||
|
Identifier side_off = ReFramed.id("fence_side_off_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.variant(ReFramed.id("fence_core_special"), true, R0, R0))
|
||||||
|
// SIDE ON
|
||||||
|
.with(GBlockstate.when(NORTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R270))
|
||||||
|
// SIDE OFF
|
||||||
|
.with(GBlockstate.when(NORTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
|
|
||||||
|
public class Slab implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 6)
|
||||||
|
.pattern("III")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartBlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("slab_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(FACING, Direction.DOWN),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.SOUTH),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.UP),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.NORTH),
|
||||||
|
GBlockstate.variant(model_id, true, R270, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.WEST),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.EAST),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class SlabsCube implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.input(ReFramed.SLAB, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartBlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("double_slab_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(model_id, true, R270, R0))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Corner.NORTH_EAST_UP;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
|
public class SmallCube implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 8);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 8)
|
||||||
|
.input(ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier small_cube_id = ReFramed.id("small_cube_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(CORNER, WEST_NORTH_UP),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(CORNER, NORTH_EAST_UP),
|
||||||
|
GBlockstate.variant(small_cube_id, true, R180, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.SOUTH_UP;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
|
public class SmallCubesStep implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.input(ReFramed.SMALL_CUBE, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("small_cubes_step_special");
|
||||||
|
Identifier reverse_model_id = ReFramed.id("small_cubes_step_reverse_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
/* X AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_EAST),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_UP),
|
||||||
|
GBlockstate.variant(reverse_model_id, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_WEST),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_DOWN),
|
||||||
|
GBlockstate.variant(reverse_model_id, true, R0, R180))
|
||||||
|
/* Y AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_SOUTH),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_WEST),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_NORTH),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_EAST),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R270))
|
||||||
|
/* Z AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
|
||||||
|
GBlockstate.variant(reverse_model_id, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_DOWN),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_NORTH),
|
||||||
|
GBlockstate.variant(reverse_model_id, true, R180, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_UP),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R90));
|
||||||
|
}
|
||||||
|
}
|
||||||
267
src/main/java/fr/adrien1106/reframed/generator/block/Stair.java
Normal file
267
src/main/java/fr/adrien1106/reframed/generator/block/Stair.java
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.When;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
|
public class Stair implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
|
||||||
|
.pattern("I ")
|
||||||
|
.pattern("II ")
|
||||||
|
.pattern("III")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartBlockStateSupplier getMultipart(Block block) {
|
||||||
|
return getMultipart(block, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MultipartBlockStateSupplier getMultipart(Block block, boolean is_double) {
|
||||||
|
String infix = is_double ? "s_cube" : "";
|
||||||
|
Identifier straight_id = ReFramed.id("stair" + infix + "_special");
|
||||||
|
Identifier double_outer_id = ReFramed.id("outers_stair" + infix + "_special");
|
||||||
|
Identifier inner_id = ReFramed.id("inner_stair" + infix + "_special");
|
||||||
|
Identifier outer_id = ReFramed.id("outer_stair" + infix + "_special");
|
||||||
|
Identifier outer_side_id = ReFramed.id("outer_side_stair" + infix + "_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
/* STRAIGHT X AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R0, R180))
|
||||||
|
/* STRAIGHT Y AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R90, R270))
|
||||||
|
/* STRAIGHT Z AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R180, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, STRAIGHT),
|
||||||
|
GBlockstate.variant(straight_id, true, R180, R90))
|
||||||
|
/* INNER BOTTOM */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R0, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R0, R270))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R0, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R0, R90))
|
||||||
|
/* INNER TOP */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_LEFT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R180, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_LEFT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R180, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_LEFT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R180, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_RIGHT)),
|
||||||
|
GBlockstate.variant(inner_id, true, R180, R270))
|
||||||
|
/* OUTER BOTTOM */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R0, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R0, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R0, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R0, R270))
|
||||||
|
/* OUTER TOP */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R180, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R180, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R180, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_id, true, R180, R270))
|
||||||
|
/* OUTER EAST */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R0, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R90, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R180, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R270, R0))
|
||||||
|
/* OUTER SOUTH */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R0, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R90, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R180, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R270, R90))
|
||||||
|
/* OUTER WEST */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R0, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R90, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R180, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R270, R180))
|
||||||
|
/* OUTER NORTH */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R0, R270))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R90, R270))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R180, R270))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(outer_side_id, true, R270, R270))
|
||||||
|
/* OUTER BOTTOM */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R0, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R0, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R0, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_RIGHT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R0, R270))
|
||||||
|
/* OUTER TOP */
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R180, R0))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R180, R90))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_LEFT),
|
||||||
|
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R180, R180))
|
||||||
|
.with(When.anyOf(
|
||||||
|
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_RIGHT),
|
||||||
|
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)),
|
||||||
|
GBlockstate.variant(double_outer_id, true, R180, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
|
||||||
|
public class StairsCube implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.input(ReFramed.STAIR)
|
||||||
|
.input(ReFramed.STEP)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartBlockStateSupplier getMultipart(Block block) {
|
||||||
|
return Stair.getMultipart(block, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.*;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.SOUTH_UP;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
|
public class Step implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 8)
|
||||||
|
.pattern("II")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("step_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
/* X AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_EAST),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_UP),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_WEST),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_DOWN),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R180))
|
||||||
|
/* Y AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, EAST_SOUTH),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_WEST),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, WEST_NORTH),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_EAST),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R270))
|
||||||
|
/* Z AXIS */
|
||||||
|
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(EDGE, NORTH_DOWN),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, UP_NORTH),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R270))
|
||||||
|
.with(GBlockstate.when(EDGE, SOUTH_UP),
|
||||||
|
GBlockstate.variant(model_id, true, R180, R90));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R270;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
|
|
||||||
|
public class StepsSlab implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
|
||||||
|
.input(ReFramed.STEP, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartBlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier step_id = ReFramed.id("steps_slab_special");
|
||||||
|
Identifier step_side_id = ReFramed.id("steps_slab_side_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(step_id, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(step_id, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(step_id, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(step_id, true, R180, R270))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(step_side_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(step_side_id, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(step_side_id, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(step_side_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(step_side_id, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(step_side_id, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(step_side_id, true, R0, R270))
|
||||||
|
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(step_side_id, true, R90, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.enums.BlockHalf;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Trapdoor implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 2)
|
||||||
|
.pattern(" I")
|
||||||
|
.pattern("III")
|
||||||
|
.pattern("II ")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier open = ReFramed.id("trapdoor_open_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(OPEN, false, BLOCK_HALF, BlockHalf.BOTTOM),
|
||||||
|
GBlockstate.variant(ReFramed.id("trapdoor_bottom_special"), true, R0, R0))
|
||||||
|
.with(GBlockstate.when(OPEN, false, BLOCK_HALF, BlockHalf.TOP),
|
||||||
|
GBlockstate.variant(ReFramed.id("trapdoor_top_special"), true, R0, R0))
|
||||||
|
.with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.NORTH),
|
||||||
|
GBlockstate.variant(open, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.EAST),
|
||||||
|
GBlockstate.variant(open, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.SOUTH),
|
||||||
|
GBlockstate.variant(open, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.WEST),
|
||||||
|
GBlockstate.variant(open, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
788
src/main/java/fr/adrien1106/reframed/generator/block/Wall.java
Normal file
788
src/main/java/fr/adrien1106/reframed/generator/block/Wall.java
Normal file
@@ -0,0 +1,788 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.block.enums.WallShape.*;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Wall implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 1);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
|
||||||
|
.pattern("III")
|
||||||
|
.pattern("III")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.WALLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier
|
||||||
|
side_low = ReFramed.id("wall_side_low_special"),
|
||||||
|
side_tall = ReFramed.id("wall_side_tall_special"),
|
||||||
|
pillar_low = ReFramed.id("wall_pillar_low_special"),
|
||||||
|
pillar_tall = ReFramed.id("wall_pillar_tall_special"),
|
||||||
|
pillar_none = ReFramed.id("wall_pillar_none_special"),
|
||||||
|
low_e = ReFramed.id("wall_low_e_special"),
|
||||||
|
tall_e = ReFramed.id("wall_tall_e_special"),
|
||||||
|
low_i = ReFramed.id("wall_low_i_special"),
|
||||||
|
tall_i = ReFramed.id("wall_tall_i_special"),
|
||||||
|
low_tall_i = ReFramed.id("wall_low_tall_i_special"),
|
||||||
|
low_c = ReFramed.id("wall_low_c_special"),
|
||||||
|
tall_c = ReFramed.id("wall_tall_c_special"),
|
||||||
|
low_tall_c = ReFramed.id("wall_low_tall_c_special"),
|
||||||
|
tall_low_c = ReFramed.id("wall_tall_low_c_special"),
|
||||||
|
low_t = ReFramed.id("wall_low_t_special"),
|
||||||
|
tall_t = ReFramed.id("wall_tall_t_special"),
|
||||||
|
tall_low_c_t = ReFramed.id("wall_tall_low_c_t_special"),
|
||||||
|
tall_i_low_t = ReFramed.id("wall_tall_i_low_t_special"),
|
||||||
|
low_i_tall_t = ReFramed.id("wall_low_i_tall_t_special"),
|
||||||
|
low_tall_c_t = ReFramed.id("wall_low_tall_c_t_special"),
|
||||||
|
low_c_tall_t = ReFramed.id("wall_low_c_tall_t_special"),
|
||||||
|
tall_c_low_t = ReFramed.id("wall_tall_c_low_t_special"),
|
||||||
|
tall_i_low_i_x = ReFramed.id("wall_tall_i_low_i_x_special"),
|
||||||
|
tall_low_t_x = ReFramed.id("wall_tall_low_t_x_special"),
|
||||||
|
tall_c_low_c_x = ReFramed.id("wall_tall_c_low_c_x_special"),
|
||||||
|
tall_t_low_x = ReFramed.id("wall_tall_t_low_x_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
// PILLAR CORE
|
||||||
|
.with(GBlockstate.when(UP, true),
|
||||||
|
GBlockstate.variant(ReFramed.id("wall_core_special"), true, R0, R0))
|
||||||
|
// LOW
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(side_low, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(side_low, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(side_low, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, LOW),
|
||||||
|
GBlockstate.variant(side_low, true, R0, R270))
|
||||||
|
// TALL
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(side_tall, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(side_tall, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(side_tall, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, TALL),
|
||||||
|
GBlockstate.variant(side_tall, true, R0, R270))
|
||||||
|
// PILLAR LOW
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, LOW, UP, true),
|
||||||
|
GBlockstate.variant(pillar_low, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, LOW, UP, true),
|
||||||
|
GBlockstate.variant(pillar_low, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, LOW, UP, true),
|
||||||
|
GBlockstate.variant(pillar_low, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, LOW, UP, true),
|
||||||
|
GBlockstate.variant(pillar_low, true, R0, R270))
|
||||||
|
// PILLAR TALL
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, TALL, UP, true),
|
||||||
|
GBlockstate.variant(pillar_tall, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, TALL, UP, true),
|
||||||
|
GBlockstate.variant(pillar_tall, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, TALL, UP, true),
|
||||||
|
GBlockstate.variant(pillar_tall, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, TALL, UP, true),
|
||||||
|
GBlockstate.variant(pillar_tall, true, R0, R270))
|
||||||
|
// PILLAR NONE
|
||||||
|
.with(GBlockstate.when(NORTH_WALL_SHAPE, NONE, UP, true),
|
||||||
|
GBlockstate.variant(pillar_none, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST_WALL_SHAPE, NONE, UP, true),
|
||||||
|
GBlockstate.variant(pillar_none, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH_WALL_SHAPE, NONE, UP, true),
|
||||||
|
GBlockstate.variant(pillar_none, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST_WALL_SHAPE, NONE, UP, true),
|
||||||
|
GBlockstate.variant(pillar_none, true, R0, R270))
|
||||||
|
// JUNCTION LOW
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_e, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_e, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_e, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_e, true, R0, R270))
|
||||||
|
// JUNCTION TALL
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_e, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_e, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_e, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_e, true, R0, R270))
|
||||||
|
// JUNCTION LOW I
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_i, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_i, true, R0, R90))
|
||||||
|
// JUNCTION TALL I
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i, true, R0, R90))
|
||||||
|
// JUNCTION LOW TALL I
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_i, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_i, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_i, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_i, true, R0, R270))
|
||||||
|
// JUNCTION LOW C
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c, true, R0, R270))
|
||||||
|
// JUNCTION TALL C
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c, true, R0, R270))
|
||||||
|
// JUNCTION LOW TALL C
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c, true, R0, R270))
|
||||||
|
// JUNCTION TALL LOW C
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c, true, R0, R270))
|
||||||
|
// JUNCTION LOW T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_t, true, R0, R270))
|
||||||
|
// JUNCTION TALL T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t, true, R0, R270))
|
||||||
|
// JUNCTION TALL LOW C T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_c_t, true, R0, R270))
|
||||||
|
// JUNCTION TALL I LOW T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i_low_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i_low_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i_low_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i_low_t, true, R0, R270))
|
||||||
|
// JUNCTION LOW I TALL T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_i_tall_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_i_tall_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_i_tall_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_i_tall_t, true, R0, R270))
|
||||||
|
// JUNCTION LOW TALL C T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_tall_c_t, true, R0, R270))
|
||||||
|
// JUNCTION LOW C TALL T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c_tall_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c_tall_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c_tall_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(low_c_tall_t, true, R0, R270))
|
||||||
|
// JUNCTION TALL C LOW T
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, NONE,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_t, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, NONE,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_t, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, NONE,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_t, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, NONE,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_t, true, R0, R270))
|
||||||
|
// JUNCTION X
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(ReFramed.id("wall_low_x_special"), true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(ReFramed.id("wall_tall_x_special"), true, R0, R0))
|
||||||
|
// JUNCTION I X
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i_low_i_x, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_i_low_i_x, true, R0, R90))
|
||||||
|
// JUNCTION TALL LOW T X
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_t_x, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_t_x, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_t_x, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_low_t_x, true, R0, R270))
|
||||||
|
// JUNCTION TALL C LOW C X
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_c_x, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_c_x, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_c_x, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_c_low_c_x, true, R0, R270))
|
||||||
|
// JUNCTION TALL C LOW C X
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, LOW,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t_low_x, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, LOW,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t_low_x, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, LOW,
|
||||||
|
EAST_WALL_SHAPE, TALL,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t_low_x, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(
|
||||||
|
NORTH_WALL_SHAPE, TALL,
|
||||||
|
EAST_WALL_SHAPE, LOW,
|
||||||
|
SOUTH_WALL_SHAPE, TALL,
|
||||||
|
WEST_WALL_SHAPE, TALL,
|
||||||
|
UP, false
|
||||||
|
),
|
||||||
|
GBlockstate.variant(tall_t_low_x, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
|
||||||
|
public class Blueprint implements RecipeSetter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.TOOLS, convertible, 3)
|
||||||
|
.pattern("PI")
|
||||||
|
.pattern("PP")
|
||||||
|
.input('P', Items.PAPER)
|
||||||
|
.input('I', Items.INK_SAC)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(Items.PAPER), FabricRecipeProvider.conditionsFromItem(Items.PAPER))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
|
||||||
|
public class Hammer implements RecipeSetter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.TOOLS, convertible)
|
||||||
|
.pattern(" CI")
|
||||||
|
.pattern(" ~C")
|
||||||
|
.pattern("~ ")
|
||||||
|
.input('I', Items.IRON_INGOT)
|
||||||
|
.input('C', ReFramed.CUBE)
|
||||||
|
.input('~', Items.STICK)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
|
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.ItemConvertible;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
|
||||||
|
public class Screwdriver implements RecipeSetter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.TOOLS, convertible)
|
||||||
|
.pattern(" I")
|
||||||
|
.pattern(" I ")
|
||||||
|
.pattern("C ")
|
||||||
|
.input('I', Items.IRON_INGOT)
|
||||||
|
.input('C', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package fr.adrien1106.reframed.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.ItemUsageContext;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class ReFramedBlueprintItem extends Item {
|
||||||
|
public ReFramedBlueprintItem(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult useOnBlock(ItemUsageContext context) {
|
||||||
|
BlockPos pos = context.getBlockPos();
|
||||||
|
World world = context.getWorld();
|
||||||
|
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)
|
||||||
|
|| frame_entity.getThemes().stream().noneMatch(state -> state.getBlock() != Blocks.AIR)
|
||||||
|
) return ActionResult.PASS;
|
||||||
|
|
||||||
|
context.getStack().decrement(1);
|
||||||
|
ItemStack stack = ReFramed.BLUEPRINT_WRITTEN.getDefaultStack();
|
||||||
|
frame_entity.setStackNbt(stack);
|
||||||
|
context.getPlayer().giveItemStack(stack);
|
||||||
|
world.playSound(context.getPlayer(), context.getPlayer().getBlockPos(), SoundEvents.ITEM_BOOK_PUT, SoundCategory.PLAYERS);
|
||||||
|
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package fr.adrien1106.reframed.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
|
import net.minecraft.block.AbstractBlock;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.client.item.TooltipContext;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.ItemUsageContext;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.nbt.NbtHelper;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Formatting;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.TypedActionResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
|
||||||
|
|
||||||
|
public class ReFramedBlueprintWrittenItem extends Item {
|
||||||
|
public ReFramedBlueprintWrittenItem(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||||
|
ItemStack stack = player.getStackInHand(hand);
|
||||||
|
if (!player.isSneaking() || !stack.hasNbt()) return super.use(world, player, hand);
|
||||||
|
stack.decrement(1);
|
||||||
|
player.giveItemStack(ReFramed.BLUEPRINT.getDefaultStack());
|
||||||
|
world.playSound(player, player.getBlockPos(), SoundEvents.ITEM_BOOK_PUT, SoundCategory.PLAYERS);
|
||||||
|
|
||||||
|
return TypedActionResult.success(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult useOnBlock(ItemUsageContext context) {
|
||||||
|
BlockPos pos = context.getBlockPos();
|
||||||
|
World world = context.getWorld();
|
||||||
|
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)
|
||||||
|
|| frame_entity.getThemes().stream().anyMatch(state -> state.getBlock() != Blocks.AIR)
|
||||||
|
|| !context.getStack().hasNbt()
|
||||||
|
) return ActionResult.PASS;
|
||||||
|
|
||||||
|
NbtCompound tag = BlockItem.getBlockEntityNbt(context.getStack());
|
||||||
|
if(tag == null) return ActionResult.FAIL;
|
||||||
|
|
||||||
|
PlayerEntity player = context.getPlayer();
|
||||||
|
if (!player.isCreative()) { // verify player has blocks and remove them
|
||||||
|
PlayerInventory inventory = player.getInventory();
|
||||||
|
List<ItemStack> stacks = getBlockStates(tag).values().stream()
|
||||||
|
.map(AbstractBlock.AbstractBlockState::getBlock)
|
||||||
|
.map(Block::asItem)
|
||||||
|
.map(Item::getDefaultStack)
|
||||||
|
.toList();
|
||||||
|
if (stacks.stream().anyMatch(stack -> !inventory.contains(stack)))
|
||||||
|
return ActionResult.FAIL;
|
||||||
|
stacks.stream().map(inventory::getSlotWithStack).forEach(index -> inventory.removeStack(index, 1));
|
||||||
|
player.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 0.5f, 0.5f);
|
||||||
|
}
|
||||||
|
frame_entity.readNbt(tag);
|
||||||
|
world.playSound(player, player.getBlockPos(), SoundEvents.ITEM_BOOK_PAGE_TURN, SoundCategory.PLAYERS);
|
||||||
|
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context) {
|
||||||
|
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
|
||||||
|
if(tag == null) return;
|
||||||
|
|
||||||
|
Map<Integer, BlockState> states = getBlockStates(tag);
|
||||||
|
states.forEach((index, state) -> tooltip.add(
|
||||||
|
Text.literal("Theme " + index + ": ")
|
||||||
|
.append(
|
||||||
|
Text.translatable(state.getBlock().getTranslationKey())
|
||||||
|
.formatted(Formatting.GRAY)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
super.appendTooltip(stack, world, tooltip, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Integer, BlockState> getBlockStates(NbtCompound tag) {
|
||||||
|
return tag.getKeys().stream()
|
||||||
|
.filter(key ->
|
||||||
|
key.startsWith(BLOCKSTATE_KEY)
|
||||||
|
&& key.replace(BLOCKSTATE_KEY,"").chars().allMatch(Character::isDigit)
|
||||||
|
)
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
key -> Integer.parseInt(key.substring(BLOCKSTATE_KEY.length())),
|
||||||
|
key -> NbtHelper.toBlockState(
|
||||||
|
Registries.BLOCK.getReadOnlyWrapper(),
|
||||||
|
tag.getCompound(key)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package fr.adrien1106.reframed.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedDoubleBlock;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.ItemUsageContext;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class ReFramedHammerItem extends Item {
|
||||||
|
public ReFramedHammerItem(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult useOnBlock(ItemUsageContext context) {
|
||||||
|
World world = context.getWorld();
|
||||||
|
BlockPos pos = context.getBlockPos();
|
||||||
|
if (!(world.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return ActionResult.PASS;
|
||||||
|
BlockState state = world.getBlockState(pos);
|
||||||
|
PlayerEntity player = context.getPlayer();
|
||||||
|
int theme_index = state.getBlock() instanceof ReFramedDoubleBlock b
|
||||||
|
? b.getHitShape(
|
||||||
|
state,
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
context.getSide()
|
||||||
|
)
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
if (frame_entity.getTheme(theme_index).getBlock() == Blocks.AIR) return ActionResult.PASS;
|
||||||
|
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
player.giveItemStack(new ItemStack(frame_entity.getTheme(theme_index).getBlock()));
|
||||||
|
world.playSound(player, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 1f, 1.1f);
|
||||||
|
}
|
||||||
|
frame_entity.setTheme(Blocks.AIR.getDefaultState(), theme_index);
|
||||||
|
ReFramed.chunkRerenderProxy.accept(world, pos);
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package fr.adrien1106.reframed.item;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedDoubleBlock;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemUsageContext;
|
||||||
|
import net.minecraft.sound.BlockSoundGroup;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.state.property.Properties;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class ReFramedScrewdriverItem extends Item {
|
||||||
|
|
||||||
|
public ReFramedScrewdriverItem(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult useOnBlock(ItemUsageContext context) {
|
||||||
|
World world = context.getWorld();
|
||||||
|
BlockPos pos = context.getBlockPos();
|
||||||
|
if (!(world.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return ActionResult.PASS;
|
||||||
|
BlockState state = world.getBlockState(pos);
|
||||||
|
PlayerEntity player = context.getPlayer();
|
||||||
|
int theme_index = state.getBlock() instanceof ReFramedDoubleBlock b
|
||||||
|
? b.getHitShape(
|
||||||
|
state,
|
||||||
|
context.getHitPos(),
|
||||||
|
context.getBlockPos(),
|
||||||
|
context.getSide()
|
||||||
|
)
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
|
||||||
|
BlockState theme = frame_entity.getTheme(theme_index);
|
||||||
|
if (!theme.contains(Properties.AXIS)) return ActionResult.PASS;
|
||||||
|
|
||||||
|
Direction.Axis axis = theme.get(Properties.AXIS);
|
||||||
|
BlockSoundGroup group = theme.getSoundGroup();
|
||||||
|
world.playSound(player, pos, group.getPlaceSound(), SoundCategory.BLOCKS, group.getVolume(), group.getPitch());
|
||||||
|
frame_entity.setTheme(theme.with(
|
||||||
|
Properties.AXIS,
|
||||||
|
switch (axis) {
|
||||||
|
case X -> Direction.Axis.Y;
|
||||||
|
case Y -> Direction.Axis.Z;
|
||||||
|
case Z -> Direction.Axis.X;
|
||||||
|
}
|
||||||
|
), theme_index);
|
||||||
|
ReFramed.chunkRerenderProxy.accept(world, pos);
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user