Compare commits

...

4 Commits

Author SHA1 Message Date
Shadowfacts 47ff975449
Fix cable shape cache not working
There are different BlockState objects for each color of cable :S
2021-03-15 21:44:54 -04:00
Shadowfacts 369dcebe1b
Add glowing-screen Terminal model 2021-03-15 19:58:53 -04:00
Shadowfacts ee6fb1e725
Fix cable recipes, advancements, loot tables, and face device drops 2021-03-15 19:55:54 -04:00
Shadowfacts bc50017b4a
Add cable colors to face device blocks 2021-03-15 18:30:35 -04:00
150 changed files with 1076 additions and 177 deletions

View File

@ -4,10 +4,13 @@ import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
import net.fabricmc.fabric.api.renderer.v1.RendererAccess
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial
import net.shadowfacts.phycon.block.inserter.InserterScreen
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
import net.shadowfacts.phycon.init.PhyScreens
import net.shadowfacts.phycon.block.terminal.TerminalScreen
import net.shadowfacts.phycon.client.PhyExtendedModelProvider
import net.shadowfacts.phycon.client.PhyModelProvider
import net.shadowfacts.phycon.networking.ClientReceiver
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
@ -17,9 +20,22 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
*/
object PhysicalConnectivityClient: ClientModInitializer {
var screenMaterial: RenderMaterial? = null
private set
override fun onInitializeClient() {
ModelLoadingRegistry.INSTANCE.registerResourceProvider(::PhyModelProvider)
RendererAccess.INSTANCE.renderer?.also { renderer ->
screenMaterial = renderer.materialFinder()
.emissive(0, true)
.disableAo(0, true)
.disableDiffuse(0, true)
.find()
ModelLoadingRegistry.INSTANCE.registerResourceProvider(::PhyExtendedModelProvider)
}
ScreenRegistry.register(PhyScreens.TERMINAL, ::TerminalScreen)
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)

View File

@ -4,20 +4,23 @@ import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.ShapeContext
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.server.world.ServerWorld
import net.minecraft.state.StateManager
import net.minecraft.state.property.EnumProperty
import net.minecraft.state.property.Properties
import net.minecraft.util.DyeColor
import net.minecraft.util.StringIdentifiable
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.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.init.PhyItems
import java.util.*
@ -28,6 +31,7 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
companion object {
val FACING = Properties.FACING
val CABLE_CONNECTION = EnumProperty.of("cable_connection", FaceCableConnection::class.java)
val COLOR = EnumProperty.of("color", DyeColor::class.java)
}
enum class FaceCableConnection : StringIdentifiable {
@ -100,44 +104,56 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
super.appendProperties(builder)
builder.add(FACING)
builder.add(CABLE_CONNECTION)
builder.add(COLOR)
}
override fun getPlacementState(context: ItemPlacementContext): BlockState {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
val cableConnection = FaceCableConnection.from(getCableConnectedSide(context.world, context.blockPos, facing))
// todo: this should never be called
val cableConnection = FaceCableConnection.from(getCableConnectedSide(context.world, context.blockPos, facing, DyeColor.BLUE))
return defaultState
.with(FACING, facing)
.with(CABLE_CONNECTION, cableConnection)
}
private fun getCableConnectedSide(world: WorldAccess, pos: BlockPos, facing: Direction): Direction? {
private fun getCableConnectedSide(world: WorldAccess, pos: BlockPos, facing: Direction, color: DyeColor): Direction? {
for (side in Direction.values()) {
if (side == facing) {
continue
}
val offsetPos = pos.offset(side)
val state = world.getBlockState(offsetPos)
val block = state.block
if (block is NetworkComponentBlock && block.getNetworkConnectedSides(state, world, offsetPos).contains(side.opposite)) {
if (canConnectTo(world, side, state, offsetPos, color)) {
return side
}
}
return null
}
private fun canConnectTo(world: WorldAccess, side: Direction, candidateState: BlockState, candidatePos: BlockPos, myColor: DyeColor): Boolean {
val block = candidateState.block
return if (block is FaceDeviceBlock<*> && candidateState[COLOR] == myColor) {
true
} else if (block is CableBlock && block.color == myColor) {
true
} else {
block is NetworkComponentBlock && block.getNetworkConnectedSides(candidateState, world, candidatePos).contains(side.opposite)
}
}
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
val current = state[CABLE_CONNECTION]
var newConnection = current
if (current == FaceCableConnection.NONE) {
if (neighborState.block is NetworkComponentBlock) {
if (canConnectTo(world, side, neighborState, neighborPos, state[COLOR])) {
newConnection = FaceCableConnection.from(side)
}
} else {
val currentConnectedPos = pos.offset(current.direction)
if (neighborPos == currentConnectedPos && neighborState.block !is NetworkComponentBlock) {
// the old cable connection is no longer correct, try to find another
newConnection = FaceCableConnection.from(getCableConnectedSide(world, pos, state[FACING]))
newConnection = FaceCableConnection.from(getCableConnectedSide(world, pos, state[FACING], state[COLOR]))
}
}
return state.with(CABLE_CONNECTION, newConnection)
@ -146,4 +162,11 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
return getShape(state[FACING], state[CABLE_CONNECTION])
}
override fun onStacksDropped(state: BlockState, world: ServerWorld, pos: BlockPos, stack: ItemStack) {
super.onStacksDropped(state, world, pos, stack)
val cableStack = ItemStack(PhyItems.CABLES[state[COLOR]])
dropStack(world, pos, cableStack)
}
}

View File

@ -2,7 +2,6 @@ package net.shadowfacts.phycon.block.cable
import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings
import net.minecraft.block.*
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemPlacementContext
import net.minecraft.state.StateManager
@ -53,19 +52,25 @@ class CableBlock(
Direction.WEST to createCuboidShape(0.0, 6.0, 6.0, 6.0, 10.0, 10.0),
Direction.EAST to createCuboidShape(10.0, 6.0, 6.0, 16.0, 10.0, 10.0)
)
private val SHAPE_CACHE = mutableMapOf<BlockState, VoxelShape>()
private val SHAPE_CACHE = Array<VoxelShape>(64) { key ->
val connectedSides = Direction.values().filterIndexed { index, _ ->
((key shr index) and 1) == 1
}
connectedSides.fold(CENTER_SHAPE) { acc, side ->
VoxelShapes.union(acc, SIDE_SHAPES[side])
}
}
val CONNECTIONS: Map<Direction, EnumProperty<CableConnection>> = Direction.values().associate { it to EnumProperty.of(it.name.toLowerCase(), CableConnection::class.java) }
fun getShape(state: BlockState): VoxelShape {
return SHAPE_CACHE.getOrPut(state) {
var shape = CENTER_SHAPE
for ((side, prop) in CONNECTIONS) {
if (state[prop] == CableConnection.ON) {
shape = VoxelShapes.union(shape, SIDE_SHAPES[side])
}
val key = Direction.values().foldIndexed(0) { i, acc, dir ->
if (state[CONNECTIONS[dir]] == CableConnection.ON) {
acc or (1 shl i)
} else {
acc
}
return shape
}
return SHAPE_CACHE[key]
}
}

View File

@ -0,0 +1,27 @@
package net.shadowfacts.phycon.client
import net.fabricmc.fabric.api.client.model.ModelProviderContext
import net.fabricmc.fabric.api.client.model.ModelResourceProvider
import net.minecraft.client.render.model.UnbakedModel
import net.minecraft.resource.ResourceManager
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.client.model.TerminalModel
/**
* @author shadowfacts
*/
class PhyExtendedModelProvider(resourceManager: ResourceManager): ModelResourceProvider {
companion object {
val TERMINAL = Identifier(PhysicalConnectivity.MODID, "block/terminal")
}
override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? {
return when (resourceId) {
TERMINAL -> TerminalModel
else -> null
}
}
}

View File

@ -3,8 +3,6 @@ package net.shadowfacts.phycon.client.model
import com.mojang.datafixers.util.Pair
import net.minecraft.block.BlockState
import net.minecraft.client.render.model.*
import net.minecraft.client.render.model.json.ModelOverrideList
import net.minecraft.client.render.model.json.ModelTransformation
import net.minecraft.client.texture.Sprite
import net.minecraft.client.texture.SpriteAtlasTexture
import net.minecraft.client.util.SpriteIdentifier
@ -13,6 +11,7 @@ import net.minecraft.util.Identifier
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.client.util.bakeRecoloredCable
import net.shadowfacts.phycon.util.CableConnection
import java.util.Random
import java.util.function.Function
@ -89,8 +88,8 @@ class ColoredCableModel(
centerSprite = textureGetter.apply(SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/cable/${color.getName()}/straight")))
sideRotations.forEach { (side, rot) ->
this.side[side.ordinal] = loader.bakeRetextured(SIDE, textureGetter, rot)
this.center[side.ordinal] = loader.bakeRetextured(CENTER, textureGetter, rot)
this.side[side.ordinal] = loader.bakeRecoloredCable(SIDE, rot, textureGetter, color)
this.center[side.ordinal] = loader.bakeRecoloredCable(CENTER, rot, textureGetter, color)
}
diagCorner.clear()
@ -105,8 +104,8 @@ class ColoredCableModel(
ModelRotation.X180_Y90,
ModelRotation.X180_Y270,
).forEach { rot ->
diagCorner[rot] = loader.bakeRetextured(DIAG_CORNER, textureGetter, rot)
diagCornerCont[rot] = loader.bakeRetextured(DIAG_CORNER_CONT, textureGetter, rot)
diagCorner[rot] = loader.bakeRecoloredCable(DIAG_CORNER, rot, textureGetter, color)
diagCornerCont[rot] = loader.bakeRecoloredCable(DIAG_CORNER_CONT, rot, textureGetter, color)
}
diagCornerXZ.clear()
@ -117,26 +116,13 @@ class ColoredCableModel(
ModelRotation.X0_Y180,
ModelRotation.X0_Y270,
).forEach { rot ->
diagCornerXZ[rot] = loader.bakeRetextured(DIAG_CORNER_XZ, textureGetter, rot)
diagCornerXZCont[rot] = loader.bakeRetextured(DIAG_CORNER_XZ_CONT, textureGetter, rot)
diagCornerXZ[rot] = loader.bakeRecoloredCable(DIAG_CORNER_XZ, rot, textureGetter, color)
diagCornerXZCont[rot] = loader.bakeRecoloredCable(DIAG_CORNER_XZ_CONT, rot, textureGetter, color)
}
return this
}
private fun ModelLoader.bakeRetextured(id: Identifier, textureGetter: Function<SpriteIdentifier, Sprite>, rot: ModelRotation): BakedModel {
val unbaked = getOrLoadModel(id)
val wrappedTextureGetter: (SpriteIdentifier) -> Sprite = {
var newId = it
if (it.textureId.namespace == PhysicalConnectivity.MODID && it.textureId.path.startsWith("block/cable/color/")) {
val newPath = it.textureId.path.replace("block/cable/color/", "block/cable/${color.getName()}/")
newId = SpriteIdentifier(it.atlasId, Identifier(PhysicalConnectivity.MODID, newPath))
}
textureGetter.apply(newId)
}
return unbaked.bake(this, wrappedTextureGetter, rot, id)!!
}
override fun getQuads(state: BlockState?, face: Direction?, random: Random): List<BakedQuad> {
if (state == null) {
return center.flatMap {

View File

@ -4,11 +4,13 @@ import net.minecraft.block.BlockState
import net.minecraft.client.render.model.*
import net.minecraft.client.texture.Sprite
import net.minecraft.client.util.SpriteIdentifier
import net.minecraft.util.DyeColor
import net.minecraft.util.Identifier
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.block.FaceDeviceBlock.FaceCableConnection
import net.shadowfacts.phycon.client.util.bakeRecoloredCable
import java.util.Random
import java.util.function.Function
@ -21,10 +23,14 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
private val interfaceCableCornerID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner")
private val interfaceCableCorner2ID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner_2")
private val interfaceCableCapID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_cap")
private var interfaceCableStraight = Array<BakedModel?>(6) { null }
private var interfaceCableCap = Array<BakedModel?>(6) { null }
private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>()
private var interfaceCableCorner2 = mutableMapOf<ModelRotation, BakedModel>()
// private var interfaceCableStraight = Array<BakedModel?>(6) { null }
// private var interfaceCableCap = Array<BakedModel?>(6) { null }
// private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>()
// private var interfaceCableCorner2 = mutableMapOf<ModelRotation, BakedModel>()
private var interfaceCableStraight = mutableMapOf<DyeColor, Array<BakedModel>>()
private var interfaceCableCap = mutableMapOf<DyeColor, Array<BakedModel>>()
private var interfaceCableCorner = mutableMapOf<DyeColor, MutableMap<ModelRotation, BakedModel>>()
private var interfaceCableCorner2 = mutableMapOf<DyeColor, MutableMap<ModelRotation, BakedModel>>()
protected val defaultRotations = listOf(
ModelRotation.X0_Y0,
@ -36,7 +42,7 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
)
abstract fun getSideModelIDs(): Collection<Identifier>
abstract fun bakeSideModels(loader: ModelLoader)
abstract fun bakeSideModels(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>)
abstract fun getSideModel(state: BlockState): BakedModel?
override fun getModelDependencies(): Collection<Identifier> {
@ -52,36 +58,54 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
unbakedModelGetter: Function<Identifier, UnbakedModel>,
unresolvedTextureReferences: MutableSet<com.mojang.datafixers.util.Pair<String, String>>
): Collection<SpriteIdentifier> {
return modelDependencies.map(unbakedModelGetter::apply).flatMap { it.getTextureDependencies(unbakedModelGetter, unresolvedTextureReferences) }
val textures = mutableListOf<SpriteIdentifier>()
for (dep in modelDependencies) {
val unbakedDep = unbakedModelGetter.apply(dep)
val depTextures = unbakedDep.getTextureDependencies(unbakedModelGetter, unresolvedTextureReferences)
for (tex in depTextures) {
if (tex.textureId.namespace == PhysicalConnectivity.MODID && tex.textureId.path.startsWith("block/cable/color/")) {
for (color in DyeColor.values()) {
val newPath = tex.textureId.path.replace("block/cable/color/", "block/cable/${color.getName()}/")
val substituted = SpriteIdentifier(tex.atlasId, Identifier(PhysicalConnectivity.MODID, newPath))
textures.add(substituted)
}
} else {
textures.add(tex)
}
}
}
return textures
}
override fun bake(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>, rotationContainer: ModelBakeSettings, modelId: Identifier): BakedModel {
bakeSideModels(loader)
bakeSideModels(loader, textureGetter)
defaultRotations.forEachIndexed { i, rot ->
interfaceCableStraight[i] = loader.bake(interfaceCableStraightID, rot)
interfaceCableCap[i] = loader.bake(interfaceCableCapID, rot)
}
DyeColor.values().forEach { color ->
interfaceCableStraight[color] = Array(6) { i ->
loader.bakeRecoloredCable(interfaceCableStraightID, defaultRotations[i], textureGetter, color)
}
interfaceCableCap[color] = Array(6) { i ->
loader.bakeRecoloredCable(interfaceCableCapID, defaultRotations[i], textureGetter, color)
}
mapOf(
interfaceCableCorner to interfaceCableCornerID to ModelRotation.values().toList(),
interfaceCableCorner2 to interfaceCableCorner2ID to listOf(
ModelRotation.X0_Y0,
ModelRotation.X0_Y90,
ModelRotation.X0_Y180,
ModelRotation.X0_Y270,
ModelRotation.X180_Y0,
ModelRotation.X180_Y90,
ModelRotation.X180_Y180,
ModelRotation.X180_Y270,
),
).forEach { (k, rotations) ->
val (map, id) = k
map.clear()
rotations.forEach { rot ->
val model = loader.bake(id, rot)
if (model == null) map.remove(rot)
else map[rot] = model
mapOf(
interfaceCableCorner to interfaceCableCornerID to ModelRotation.values().toList(),
interfaceCableCorner2 to interfaceCableCorner2ID to listOf(
ModelRotation.X0_Y0,
ModelRotation.X0_Y90,
ModelRotation.X0_Y180,
ModelRotation.X0_Y270,
ModelRotation.X180_Y0,
ModelRotation.X180_Y90,
ModelRotation.X180_Y180,
ModelRotation.X180_Y270,
),
).forEach { (k, rotations) ->
val (map, id) = k
map[color] = mutableMapOf()
rotations.forEach { rot ->
map[color]!![rot] = loader.bakeRecoloredCable(id, rot, textureGetter, color)
}
}
}
@ -92,54 +116,55 @@ abstract class FaceDeviceModel: UnbakedModel, BakedModel {
if (state == null) return listOf()
val facing = state[FaceDeviceBlock.FACING]
val connection = state[FaceDeviceBlock.CABLE_CONNECTION]
val color = state[FaceDeviceBlock.COLOR]
val sideQuads = getSideModel(state)?.getQuads(state, face, random) ?: listOf()
val cableQuads = if (connection.direction == facing.opposite) {
interfaceCableStraight[facing.ordinal]?.getQuads(state, face, random) ?: listOf()
interfaceCableStraight[color]!![facing.ordinal]?.getQuads(state, face, random) ?: listOf()
} else if (connection == FaceCableConnection.NONE) {
interfaceCableCap[facing.ordinal]?.getQuads(state, face, random) ?: listOf()
interfaceCableCap[color]!![facing.ordinal]?.getQuads(state, face, random) ?: listOf()
} else {
val model = when (facing) {
Direction.DOWN -> when (connection) {
FaceCableConnection.NORTH -> interfaceCableCorner[ModelRotation.X0_Y0]
FaceCableConnection.EAST -> interfaceCableCorner[ModelRotation.X0_Y90]
FaceCableConnection.SOUTH -> interfaceCableCorner[ModelRotation.X0_Y180]
FaceCableConnection.WEST -> interfaceCableCorner[ModelRotation.X0_Y270]
FaceCableConnection.NORTH -> interfaceCableCorner[color]!![ModelRotation.X0_Y0]
FaceCableConnection.EAST -> interfaceCableCorner[color]!![ModelRotation.X0_Y90]
FaceCableConnection.SOUTH -> interfaceCableCorner[color]!![ModelRotation.X0_Y180]
FaceCableConnection.WEST -> interfaceCableCorner[color]!![ModelRotation.X0_Y270]
else -> null
}
Direction.UP -> when (connection) {
FaceCableConnection.NORTH -> interfaceCableCorner[ModelRotation.X180_Y180]
FaceCableConnection.EAST -> interfaceCableCorner[ModelRotation.X180_Y270]
FaceCableConnection.SOUTH -> interfaceCableCorner[ModelRotation.X180_Y0]
FaceCableConnection.WEST -> interfaceCableCorner[ModelRotation.X180_Y90]
FaceCableConnection.NORTH -> interfaceCableCorner[color]!![ModelRotation.X180_Y180]
FaceCableConnection.EAST -> interfaceCableCorner[color]!![ModelRotation.X180_Y270]
FaceCableConnection.SOUTH -> interfaceCableCorner[color]!![ModelRotation.X180_Y0]
FaceCableConnection.WEST -> interfaceCableCorner[color]!![ModelRotation.X180_Y90]
else -> null
}
Direction.NORTH -> when (connection) {
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y0]
FaceCableConnection.EAST -> interfaceCableCorner2[ModelRotation.X180_Y180]
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y180]
FaceCableConnection.WEST -> interfaceCableCorner2[ModelRotation.X0_Y0]
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y0]
FaceCableConnection.EAST -> interfaceCableCorner2[color]!![ModelRotation.X180_Y180]
FaceCableConnection.DOWN -> interfaceCableCorner[color]!![ModelRotation.X90_Y180]
FaceCableConnection.WEST -> interfaceCableCorner2[color]!![ModelRotation.X0_Y0]
else -> null
}
Direction.SOUTH -> when (connection) {
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y180]
FaceCableConnection.WEST -> interfaceCableCorner2[ModelRotation.X180_Y0]
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y0]
FaceCableConnection.EAST -> interfaceCableCorner2[ModelRotation.X0_Y180]
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y180]
FaceCableConnection.WEST -> interfaceCableCorner2[color]!![ModelRotation.X180_Y0]
FaceCableConnection.DOWN -> interfaceCableCorner[color]!![ModelRotation.X90_Y0]
FaceCableConnection.EAST -> interfaceCableCorner2[color]!![ModelRotation.X0_Y180]
else -> null
}
Direction.WEST -> when (connection) {
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y270]
FaceCableConnection.NORTH -> interfaceCableCorner2[ModelRotation.X180_Y90]
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y90]
FaceCableConnection.SOUTH -> interfaceCableCorner2[ModelRotation.X0_Y270]
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y270]
FaceCableConnection.NORTH -> interfaceCableCorner2[color]!![ModelRotation.X180_Y90]
FaceCableConnection.DOWN -> interfaceCableCorner[color]!![ModelRotation.X90_Y90]
FaceCableConnection.SOUTH -> interfaceCableCorner2[color]!![ModelRotation.X0_Y270]
else -> null
}
Direction.EAST -> when (connection) {
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y90]
FaceCableConnection.SOUTH -> interfaceCableCorner2[ModelRotation.X180_Y270]
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y270]
FaceCableConnection.NORTH -> interfaceCableCorner2[ModelRotation.X0_Y90]
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y90]
FaceCableConnection.SOUTH -> interfaceCableCorner2[color]!![ModelRotation.X180_Y270]
FaceCableConnection.DOWN -> interfaceCableCorner[color]!![ModelRotation.X90_Y270]
FaceCableConnection.NORTH -> interfaceCableCorner2[color]!![ModelRotation.X0_Y90]
else -> null
}
else -> null

View File

@ -4,10 +4,12 @@ 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.client.util.SpriteIdentifier
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
import java.util.function.Function
/**
* @author shadowfacts
@ -23,7 +25,7 @@ object RedstoneControllerModel: FaceDeviceModel() {
return listOf(ON, OFF)
}
override fun bakeSideModels(loader: ModelLoader) {
override fun bakeSideModels(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>) {
defaultRotations.forEachIndexed { i, rot ->
onModels[i] = loader.bake(ON, rot)
offModels[i] = loader.bake(OFF, rot)

View File

@ -4,8 +4,12 @@ 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.client.util.SpriteIdentifier
import net.minecraft.util.DyeColor
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.client.util.bakeRecoloredCable
import java.util.function.Function
/**
* @author shadowfacts
@ -13,23 +17,25 @@ import net.shadowfacts.phycon.block.FaceDeviceBlock
class SimpleFaceDeviceModel(
private val sideModelID: Identifier,
): FaceDeviceModel() {
private val sideModels = Array<BakedModel?>(6) { null }
private val sideModels = mutableMapOf<DyeColor, Array<BakedModel>>()
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 bakeSideModels(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>) {
DyeColor.values().forEach { color ->
sideModels[color] = Array(6) { i ->
loader.bakeRecoloredCable(sideModelID, defaultRotations[i], textureGetter, color)
}
}
}
override fun getSideModel(state: BlockState): BakedModel? {
return sideModels[state[FaceDeviceBlock.FACING].ordinal]
override fun getSideModel(state: BlockState): BakedModel {
return sideModels[state[FaceDeviceBlock.COLOR]]!![state[FaceDeviceBlock.FACING].ordinal]
}
override fun getSprite(): Sprite {
return sideModels.first()!!.sprite
return sideModels[DyeColor.BLACK]!!.first().sprite
}
}

View File

@ -0,0 +1,137 @@
package net.shadowfacts.phycon.client.model
import com.mojang.datafixers.util.Pair
import net.fabricmc.fabric.api.renderer.v1.RendererAccess
import net.fabricmc.fabric.api.renderer.v1.mesh.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.FabricBakedModel
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext
import net.minecraft.block.BlockState
import net.minecraft.client.render.model.*
import net.minecraft.client.texture.Sprite
import net.minecraft.client.texture.SpriteAtlasTexture
import net.minecraft.client.util.SpriteIdentifier
import net.minecraft.item.ItemStack
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.BlockRenderView
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.TerminalBlock
import java.util.Random
import java.util.function.Function
import java.util.function.Supplier
/**
* @author shadowfacts
*/
object TerminalModel: UnbakedModel, BakedModel, FabricBakedModel {
private val TERMINAL = SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/terminal"))
private val CASING = SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/casing"))
private lateinit var meshes: Array<Mesh>
private lateinit var terminalSprite: Sprite
override fun getModelDependencies(): Collection<Identifier> {
return listOf()
}
override fun getTextureDependencies(
unbakedModelGetter: Function<Identifier, UnbakedModel>,
unresolvedTextureDependencies: MutableSet<Pair<String, String>>
): Collection<SpriteIdentifier> {
return listOf(TERMINAL, CASING)
}
override fun bake(
loader: ModelLoader,
textureGetter: Function<SpriteIdentifier, Sprite>,
rotationContainer: ModelBakeSettings,
modelId: Identifier
): BakedModel {
terminalSprite = textureGetter.apply(TERMINAL)
val casingSprite = textureGetter.apply(CASING)
val renderer = RendererAccess.INSTANCE.renderer!!
meshes = Array(6) { i ->
val facing = Direction.values()[i]
val builder = renderer.meshBuilder()
val emitter = builder.emitter
for (dir in Direction.values()) {
if (dir == facing) {
emitter.square(facing, 0f, 0f, 1f, 1f, QuadEmitter.CULL_FACE_EPSILON * 10)
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
emitter.spriteColor(0, -1, -1, -1, -1)
emitter.emit()
emitter.material(PhysicalConnectivityClient.screenMaterial)
emitter.square(facing, 3/16f, 2/16f, 13/16f, 3/16f, 0f)
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
emitter.spriteColor(0, -1, -1, -1, -1)
emitter.emit()
emitter.material(PhysicalConnectivityClient.screenMaterial)
emitter.square(facing, 2/16f, 3/16f, 14/16f, 13/16f, 0f)
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
emitter.spriteColor(0, -1, -1, -1, -1)
emitter.emit()
emitter.material(PhysicalConnectivityClient.screenMaterial)
emitter.square(facing, 3/16f, 13/16f, 13/16f, 14/16f, 0f)
emitter.spriteBake(0, terminalSprite, MutableQuadView.BAKE_LOCK_UV)
emitter.spriteColor(0, -1, -1, -1, -1)
emitter.emit()
} else {
emitter.square(dir, 0f, 0f, 1f, 1f, 0f)
emitter.spriteBake(0, casingSprite, MutableQuadView.BAKE_LOCK_UV)
emitter.spriteColor(0, -1, -1, -1, -1)
emitter.emit()
}
}
builder.build()
}
return this
}
override fun isVanillaAdapter() = false
override fun emitBlockQuads(
blockView: BlockRenderView,
state: BlockState,
pos: BlockPos,
randomSupplier: Supplier<Random>,
context: RenderContext
) {
val mesh = meshes[state[TerminalBlock.FACING].ordinal]
context.meshConsumer().accept(mesh)
}
override fun emitItemQuads(stack: ItemStack, randomSupplier: Supplier<Random>, context: RenderContext) {
}
override fun getQuads(state: BlockState?, face: Direction?, random: Random) = null
override fun useAmbientOcclusion() = true
override fun hasDepth() = false
override fun isSideLit() = false
override fun isBuiltin() = false
override fun getSprite() = terminalSprite
override fun getTransformation() = null
override fun getOverrides() = null
}

View File

@ -0,0 +1,32 @@
package net.shadowfacts.phycon.client.util
import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.render.model.ModelLoader
import net.minecraft.client.render.model.ModelRotation
import net.minecraft.client.texture.Sprite
import net.minecraft.client.util.SpriteIdentifier
import net.minecraft.util.DyeColor
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import java.util.function.Function
/**
* @author shadowfacts
*/
fun ModelLoader.bakeRecoloredCable(
id: Identifier,
rot: ModelRotation,
textureGetter: Function<SpriteIdentifier, Sprite>,
color: DyeColor
): BakedModel {
val unbaked = getOrLoadModel(id)
val wrappedTextureGetter: (SpriteIdentifier) -> Sprite = {
var newId = it
if (it.textureId.namespace == PhysicalConnectivity.MODID && it.textureId.path.startsWith("block/cable/color/")) {
val newPath = it.textureId.path.replace("block/cable/color/", "block/cable/${color.getName()}/")
newId = SpriteIdentifier(it.atlasId, Identifier(PhysicalConnectivity.MODID, newPath))
}
textureGetter.apply(newId)
}
return unbaked.bake(this, wrappedTextureGetter, rot, id)!!
}

View File

@ -15,7 +15,8 @@ class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settin
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
val hitState = context.world.getBlockState(context.blockPos)
if (hitState.block is CableBlock) {
val hitBlock = hitState.block
if (hitBlock is CableBlock) {
val hitBlockEdge = context.hitPos.getComponentAlongAxis(context.side.axis) % 1 == 0.0
val placementSide = if (hitBlockEdge) context.side.opposite else context.side
@ -32,6 +33,7 @@ class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settin
return block.defaultState
.with(FaceDeviceBlock.FACING, placementSide)
.with(FaceDeviceBlock.CABLE_CONNECTION, connection)
.with(FaceDeviceBlock.COLOR, hitBlock.color)
}
}
return null

View File

@ -82,7 +82,8 @@ class ScrewdriverItem: Item(Settings().maxCount(1)) {
val faceShape = block.faceShapes[state[FaceDeviceBlock.FACING]]!!
// if we hit the face part of block, leave the cable behind
if (faceShape.boundingBox.containsInclusive(hitInsideBlock)) {
return (state.block as CableBlock).getInitialState(context.world, context.blockPos)
val cableBlock = PhyBlocks.CABLES[state[FaceDeviceBlock.COLOR]]!!
return cableBlock.getInitialState(context.world, context.blockPos)
} else {
if (!context.world.isClient) {
val cable = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(state.block))

View File

@ -1,7 +1,7 @@
{
"textures": {
"cap": "phycon:block/cable_cap_end",
"straight": "phycon:block/cable_straight"
"cap": "phycon:block/cable/color/cap_end",
"straight": "phycon:block/cable/color/straight"
},
"elements": [
{

View File

@ -1,9 +1,9 @@
{
"textures": {
"straight": "phycon:block/cable_straight",
"cap": "phycon:block/cable_cap_end",
"corner_r": "phycon:block/interface_cable_corner_r",
"corner_l": "phycon:block/interface_cable_corner_l"
"straight": "phycon:block/cable/color/straight",
"cap": "phycon:block/cable/color/cap_end",
"corner_r": "phycon:block/cable/color/corner_r_down",
"corner_l": "phycon:block/cable/color/corner_l_down"
},
"elements": [
{
@ -19,4 +19,4 @@
}
}
]
}
}

View File

@ -1,9 +1,9 @@
{
"textures": {
"straight": "phycon:block/cable_straight_rotated",
"cap": "phycon:block/cable_cap_end",
"corner_up": "phycon:block/interface_cable_corner_l_up",
"corner_down": "phycon:block/interface_cable_corner_r"
"straight": "phycon:block/cable/color/straight_rotated",
"cap": "phycon:block/cable/color/cap_end",
"corner_up": "phycon:block/cable/color/corner_l_up",
"corner_down": "phycon:block/cable/color/corner_r_down"
},
"elements": [
{
@ -19,4 +19,4 @@
}
}
]
}
}

View File

@ -1,7 +1,7 @@
{
"textures": {
"cable": "phycon:block/cable_straight",
"cap": "phycon:block/cable_cap_end"
"cable": "phycon:block/cable/color/straight",
"cap": "phycon:block/cable/color/cap_end"
},
"elements": [
{
@ -16,4 +16,4 @@
}
}
]
}
}

View File

@ -1,7 +1,7 @@
{
"parent": "block/block",
"textures": {
"cable": "phycon:block/cable_straight",
"cable": "phycon:block/cable/color/straight",
"particle": "#front",
"back": "phycon:block/interface_back",
"front": "phycon:block/interface_front"
@ -13,10 +13,10 @@
"faces": {
"down": { "texture": "#front" },
"up": { "texture": "#back" },
"north": { "texture": "#back" },
"south": { "texture": "#back" },
"west": { "texture": "#back" },
"east": { "texture": "#back" }
"north": { "texture": "#back", "uv": [2, 2, 14, 4] },
"south": { "texture": "#back", "uv": [2, 2, 14, 4] },
"west": { "texture": "#back", "uv": [2, 2, 14, 4] },
"east": { "texture": "#back", "uv": [2, 2, 14, 4] }
}
},
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 B

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 B

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 B

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 B

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Some files were not shown because too many files have changed in this diff Show More