Convert Redstone Controller and Emitter to use FaceDeviceModel

This commit is contained in:
Shadowfacts 2021-03-06 15:32:38 -05:00
parent 72b8435834
commit 32d87fbd9d
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
10 changed files with 122 additions and 357 deletions

View File

@ -119,10 +119,11 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
open fun findDestination(): Interface? { open fun findDestination(): Interface? {
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos) val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
if (sides.size != 1) { return when (sides.size) {
throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side") 0 -> null
1 -> NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
} }
return NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
} }
override fun tick() { override fun tick() {

View File

@ -6,7 +6,8 @@ import net.minecraft.client.render.model.UnbakedModel
import net.minecraft.resource.ResourceManager import net.minecraft.resource.ResourceManager
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.client.model.InterfaceModel import net.shadowfacts.phycon.client.model.RedstoneControllerModel
import net.shadowfacts.phycon.client.model.SimpleFaceDeviceModel
/** /**
* @author shadowfacts * @author shadowfacts
@ -14,11 +15,17 @@ import net.shadowfacts.phycon.client.model.InterfaceModel
class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider { class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider {
companion object { companion object {
val INTERFACE = Identifier(PhysicalConnectivity.MODID, "block/network_interface") val INTERFACE = Identifier(PhysicalConnectivity.MODID, "block/network_interface")
val INTERFACE_SIDE = Identifier(PhysicalConnectivity.MODID, "block/interface_side")
val REDSTONE_CONTROLLER = Identifier(PhysicalConnectivity.MODID, "block/redstone_controller")
val REDSTONE_EMITTER = Identifier(PhysicalConnectivity.MODID, "block/redstone_emitter")
val REDSTONE_EMITTER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/redstone_emitter_side")
} }
override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? { override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? {
return when (resourceId) { return when (resourceId) {
INTERFACE -> InterfaceModel INTERFACE -> SimpleFaceDeviceModel(INTERFACE_SIDE)
REDSTONE_CONTROLLER -> RedstoneControllerModel
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
else -> null else -> null
} }
} }

View File

@ -15,22 +15,32 @@ import java.util.function.Function
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
object InterfaceModel: UnbakedModel, BakedModel { abstract class FaceDeviceModel: UnbakedModel, BakedModel {
private val interfaceSideID = Identifier(PhysicalConnectivity.MODID, "block/interface_side")
private val interfaceCableStraightID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_straight") private val interfaceCableStraightID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_straight")
private val interfaceCableCornerID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner") private val interfaceCableCornerID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner")
private val interfaceCableCorner2ID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner_2") private val interfaceCableCorner2ID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner_2")
private val interfaceCableCapID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_cap") private val interfaceCableCapID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_cap")
private var interfaceSides = Array<BakedModel?>(6) { null }
private var interfaceCableStraight = Array<BakedModel?>(6) { null } private var interfaceCableStraight = Array<BakedModel?>(6) { null }
private var interfaceCableCap = Array<BakedModel?>(6) { null } private var interfaceCableCap = Array<BakedModel?>(6) { null }
private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>() private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>()
private var interfaceCableCorner2 = mutableMapOf<ModelRotation, BakedModel>() private var interfaceCableCorner2 = mutableMapOf<ModelRotation, BakedModel>()
protected val defaultRotations = listOf(
ModelRotation.X0_Y0,
ModelRotation.X180_Y0,
ModelRotation.X270_Y0,
ModelRotation.X90_Y0,
ModelRotation.X90_Y90,
ModelRotation.X90_Y270,
)
abstract fun getSideModelIDs(): Collection<Identifier>
abstract fun bakeSideModels(loader: ModelLoader)
abstract fun getSideModel(state: BlockState): BakedModel?
override fun getModelDependencies(): Collection<Identifier> { override fun getModelDependencies(): Collection<Identifier> {
return listOf( return getSideModelIDs() + listOf(
interfaceSideID,
interfaceCableStraightID, interfaceCableStraightID,
interfaceCableCornerID, interfaceCableCornerID,
interfaceCableCorner2ID, interfaceCableCorner2ID,
@ -42,19 +52,13 @@ object InterfaceModel: UnbakedModel, BakedModel {
unbakedModelGetter: Function<Identifier, UnbakedModel>, unbakedModelGetter: Function<Identifier, UnbakedModel>,
unresolvedTextureReferences: MutableSet<com.mojang.datafixers.util.Pair<String, String>> unresolvedTextureReferences: MutableSet<com.mojang.datafixers.util.Pair<String, String>>
): Collection<SpriteIdentifier> { ): Collection<SpriteIdentifier> {
return listOf() return modelDependencies.map(unbakedModelGetter::apply).flatMap { it.getTextureDependencies(unbakedModelGetter, unresolvedTextureReferences) }
} }
override fun bake(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>, rotationContainer: ModelBakeSettings, modelId: Identifier): BakedModel { override fun bake(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>, rotationContainer: ModelBakeSettings, modelId: Identifier): BakedModel {
listOf( bakeSideModels(loader)
ModelRotation.X0_Y0,
ModelRotation.X180_Y0, defaultRotations.forEachIndexed { i, rot ->
ModelRotation.X270_Y0,
ModelRotation.X90_Y0,
ModelRotation.X90_Y90,
ModelRotation.X90_Y270,
).forEachIndexed { i, rot ->
interfaceSides[i] = loader.bake(interfaceSideID, rot)
interfaceCableStraight[i] = loader.bake(interfaceCableStraightID, rot) interfaceCableStraight[i] = loader.bake(interfaceCableStraightID, rot)
interfaceCableCap[i] = loader.bake(interfaceCableCapID, rot) interfaceCableCap[i] = loader.bake(interfaceCableCapID, rot)
} }
@ -89,7 +93,7 @@ object InterfaceModel: UnbakedModel, BakedModel {
val facing = state[FaceDeviceBlock.FACING] val facing = state[FaceDeviceBlock.FACING]
val connection = state[FaceDeviceBlock.CABLE_CONNECTION] val connection = state[FaceDeviceBlock.CABLE_CONNECTION]
val sideQuads = interfaceSides[facing.ordinal]?.getQuads(state, face, random) ?: listOf() val sideQuads = getSideModel(state)?.getQuads(state, face, random) ?: listOf()
val cableQuads = if (connection.direction == facing.opposite) { val cableQuads = if (connection.direction == facing.opposite) {
interfaceCableStraight[facing.ordinal]?.getQuads(state, face, random) ?: listOf() interfaceCableStraight[facing.ordinal]?.getQuads(state, face, random) ?: listOf()
} else if (connection == FaceCableConnection.NONE) { } else if (connection == FaceCableConnection.NONE) {
@ -154,9 +158,7 @@ object InterfaceModel: UnbakedModel, BakedModel {
override fun isBuiltin() = false override fun isBuiltin() = false
override fun getSprite(): Sprite { abstract override fun getSprite(): Sprite
return interfaceSides.first()!!.sprite
}
override fun getTransformation() = null override fun getTransformation() = null

View File

@ -0,0 +1,45 @@
package net.shadowfacts.phycon.client.model
import net.minecraft.block.BlockState
import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.render.model.ModelLoader
import net.minecraft.client.texture.Sprite
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
/**
* @author shadowfacts
*/
object RedstoneControllerModel: FaceDeviceModel() {
private val ON = Identifier(PhysicalConnectivity.MODID, "block/redstone_controller_side_on")
private val OFF = Identifier(PhysicalConnectivity.MODID, "block/redstone_controller_side_off")
private val onModels = Array<BakedModel?>(6) { null }
private val offModels = Array<BakedModel?>(6) { null }
override fun getSideModelIDs(): Collection<Identifier> {
return listOf(ON, OFF)
}
override fun bakeSideModels(loader: ModelLoader) {
defaultRotations.forEachIndexed { i, rot ->
onModels[i] = loader.bake(ON, rot)
offModels[i] = loader.bake(OFF, rot)
}
}
override fun getSideModel(state: BlockState): BakedModel? {
return if (state[RedstoneControllerBlock.POWERED]) {
onModels[state[FaceDeviceBlock.FACING].ordinal]
} else {
offModels[state[FaceDeviceBlock.FACING].ordinal]
}
}
override fun getSprite(): Sprite {
return offModels.first()!!.sprite
}
}

View File

@ -0,0 +1,35 @@
package net.shadowfacts.phycon.client.model
import net.minecraft.block.BlockState
import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.render.model.ModelLoader
import net.minecraft.client.texture.Sprite
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.block.FaceDeviceBlock
/**
* @author shadowfacts
*/
class SimpleFaceDeviceModel(
private val sideModelID: Identifier,
): FaceDeviceModel() {
private val sideModels = Array<BakedModel?>(6) { null }
override fun getSideModelIDs(): Collection<Identifier> {
return listOf(sideModelID)
}
override fun bakeSideModels(loader: ModelLoader) {
defaultRotations.forEachIndexed { i, rot ->
sideModels[i] = loader.bake(sideModelID, rot)
}
}
override fun getSideModel(state: BlockState): BakedModel? {
return sideModels[state[FaceDeviceBlock.FACING].ordinal]
}
override fun getSprite(): Sprite {
return sideModels.first()!!.sprite
}
}

View File

@ -1,7 +1,7 @@
{ {
"multipart": [ "multipart": [
{ {
"_comment": "see InterfaceModel", "_comment": "see SimpleFaceDeviceModel",
"apply": { "model": "phycon:block/network_interface" } "apply": { "model": "phycon:block/network_interface" }
} }
] ]

View File

@ -1,183 +1,8 @@
{ {
"multipart": [ "multipart": [
{ {
"apply": { "model": "phycon:block/cable_center" } "_comment": "see RedstoneControllerModel",
}, "apply": { "model": "phycon:block/redstone_controller" }
{
"when": { "facing": "down", "powered": "false" },
"apply": { "model": "phycon:block/redstone_controller_side_off" }
},
{
"when": { "facing": "up", "powered": "false" },
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 180 }
},
{
"when": { "facing": "north", "powered": "false" },
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 270 }
},
{
"when": { "facing": "south", "powered": "false" },
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90 }
},
{
"when": { "facing": "west", "powered": "false" },
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90, "y": 90 }
},
{
"when": { "facing": "east", "powered": "false" },
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90, "y": 270 }
},
{
"when": { "facing": "down", "powered": "true" },
"apply": { "model": "phycon:block/redstone_controller_side_on" }
},
{
"when": { "facing": "up", "powered": "true" },
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 180 }
},
{
"when": { "facing": "north", "powered": "true" },
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 270 }
},
{
"when": { "facing": "south", "powered": "true" },
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90 }
},
{
"when": { "facing": "west", "powered": "true" },
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90, "y": 90 }
},
{
"when": { "facing": "east", "powered": "true" },
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90, "y": 270 }
},
{
"when": { "cable_connection": "up", "facing": "down" },
"apply": { "model": "phycon:block/interface_cable_straight" }
},
{
"when": { "cable_connection": "down", "facing": "up" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 180 }
},
{
"when": { "cable_connection": "north", "facing": "south" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90 }
},
{
"when": { "cable_connection": "south", "facing": "north" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 270 }
},
{
"when": { "cable_connection": "west", "facing": "east" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 270 }
},
{
"when": { "cable_connection": "east", "facing": "west" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 90 }
},
{
"when": {"cable_connection": "north", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner" }
},
{
"when": {"cable_connection": "east", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner", "y": 90 }
},
{
"when": {"cable_connection": "south", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner", "y": 180 }
},
{
"when": {"cable_connection": "west", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner", "y": 270 }
},
{
"when": {"cable_connection": "north", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 180 }
},
{
"when": {"cable_connection": "east", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 270 }
},
{
"when": {"cable_connection": "south", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180 }
},
{
"when": {"cable_connection": "west", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 90 }
},
{
"when": {"cable_connection": "down", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 180 }
},
{
"when": {"cable_connection": "up", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270 }
},
{
"when": {"cable_connection": "west", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner_2" }
},
{
"when": {"cable_connection": "east", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 180 }
},
{
"when": {"cable_connection": "down", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90 }
},
{
"when": {"cable_connection": "up", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 180 }
},
{
"when": {"cable_connection": "west", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner_3" }
},
{
"when": {"cable_connection": "east", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 180 }
},
{
"when": {"cable_connection": "down", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 90 }
},
{
"when": {"cable_connection": "up", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 270 }
},
{
"when": {"cable_connection": "north", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner_3", "y": 90 }
},
{
"when": {"cable_connection": "south", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 270 }
},
{
"when": {"cable_connection": "down", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 270 }
},
{
"when": {"cable_connection": "up", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 90 }
},
{
"when": {"cable_connection": "north", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner_2", "y": 90 }
},
{
"when": {"cable_connection": "south", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 270 }
} }
] ]
} }

View File

@ -1,159 +1,7 @@
{ {
"multipart": [ "multipart": [
{ {
"apply": { "model": "phycon:block/cable_center" } "apply": { "model": "phycon:block/redstone_emitter" }
},
{
"when": { "facing": "down" },
"apply": { "model": "phycon:block/redstone_emitter_side" }
},
{
"when": { "facing": "up" },
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 180 }
},
{
"when": { "facing": "north" },
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 270 }
},
{
"when": { "facing": "south" },
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 90 }
},
{
"when": { "facing": "west" },
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 90, "y": 90 }
},
{
"when": { "facing": "east" },
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 90, "y": 270 }
},
{
"when": { "cable_connection": "up", "facing": "down" },
"apply": { "model": "phycon:block/interface_cable_straight" }
},
{
"when": { "cable_connection": "down", "facing": "up" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 180 }
},
{
"when": { "cable_connection": "north", "facing": "south" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90 }
},
{
"when": { "cable_connection": "south", "facing": "north" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 270 }
},
{
"when": { "cable_connection": "west", "facing": "east" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 270 }
},
{
"when": { "cable_connection": "east", "facing": "west" },
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 90 }
},
{
"when": {"cable_connection": "north", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner" }
},
{
"when": {"cable_connection": "east", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner", "y": 90 }
},
{
"when": {"cable_connection": "south", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner", "y": 180 }
},
{
"when": {"cable_connection": "west", "facing": "down"},
"apply": { "model": "phycon:block/interface_cable_corner", "y": 270 }
},
{
"when": {"cable_connection": "north", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 180 }
},
{
"when": {"cable_connection": "east", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 270 }
},
{
"when": {"cable_connection": "south", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180 }
},
{
"when": {"cable_connection": "west", "facing": "up"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 90 }
},
{
"when": {"cable_connection": "down", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 180 }
},
{
"when": {"cable_connection": "up", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270 }
},
{
"when": {"cable_connection": "west", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner_2" }
},
{
"when": {"cable_connection": "east", "facing": "north"},
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 180 }
},
{
"when": {"cable_connection": "down", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90 }
},
{
"when": {"cable_connection": "up", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 180 }
},
{
"when": {"cable_connection": "west", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner_3" }
},
{
"when": {"cable_connection": "east", "facing": "south"},
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 180 }
},
{
"when": {"cable_connection": "down", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 90 }
},
{
"when": {"cable_connection": "up", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 270 }
},
{
"when": {"cable_connection": "north", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner_3", "y": 90 }
},
{
"when": {"cable_connection": "south", "facing": "west"},
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 270 }
},
{
"when": {"cable_connection": "down", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 270 }
},
{
"when": {"cable_connection": "up", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 90 }
},
{
"when": {"cable_connection": "north", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner_2", "y": 90 }
},
{
"when": {"cable_connection": "south", "facing": "east"},
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 270 }
} }
] ]
} }

View File

@ -4,7 +4,8 @@
"cable": "phycon:block/cable_straight", "cable": "phycon:block/cable_straight",
"front": "phycon:block/redstone_controller_front_off", "front": "phycon:block/redstone_controller_front_off",
"back": "phycon:block/redstone_controller_back", "back": "phycon:block/redstone_controller_back",
"side": "phycon:block/redstone_controller_back" "side": "phycon:block/redstone_controller_back",
"particle": "#front"
}, },
"elements": [ "elements": [
{ {

View File

@ -4,7 +4,8 @@
"cable": "phycon:block/cable_straight", "cable": "phycon:block/cable_straight",
"front": "phycon:block/redstone_controller_front_on", "front": "phycon:block/redstone_controller_front_on",
"back": "phycon:block/redstone_controller_back", "back": "phycon:block/redstone_controller_back",
"side": "phycon:block/redstone_controller_back" "side": "phycon:block/redstone_controller_back",
"particle": "#front"
}, },
"elements": [ "elements": [
{ {