Pattern Rendering and other Rendering

This commit is contained in:
Sebastian Hartte
2020-07-20 20:13:20 +02:00
parent d053c9b1bc
commit 019f570331
69 changed files with 994 additions and 1398 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ yarn_mappings=1.16.1+build.19
loader_version=0.8.9+build.203
#Fabric api
fabric_version=0.14.1+build.372-1.16
fabric_version=0.15.0+local-indigo-flat-lighting-fix
loom_version=0.4-SNAPSHOT
@@ -20,6 +20,7 @@ package appeng.block;
import java.util.List;
import appeng.block.networking.WirelessBlock;
import net.fabricmc.api.EnvType;
import net.minecraft.block.Block;
import net.minecraft.client.item.TooltipContext;
@@ -84,7 +85,7 @@ public class AEBaseBlockItem extends BlockItem {
} else {
forward = Direction.UP;
}
} else if (/* FIXME FABRIC this.blockType instanceof WirelessBlock || */ this.blockType instanceof SkyCompassBlock) {
} else if (this.blockType instanceof WirelessBlock || this.blockType instanceof SkyCompassBlock) {
forward = side;
if (forward == Direction.UP || forward == Direction.DOWN) {
up = Direction.SOUTH;
@@ -152,7 +152,7 @@ public class SkyCompassBlock extends AEBaseTileBlock<SkyCompassBlockEntity> {
@Override
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.ENTITYBLOCK_ANIMATED;
return BlockRenderType.MODEL;
}
}
@@ -1,34 +1,38 @@
package appeng.block.qnb;
import java.util.Collections;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.core.Api;
import appeng.core.AppEng;
import com.google.common.collect.ImmutableList;
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.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
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;
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 javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.tile.qnb.QuantumBridgeBlockEntity;
class QnbFormedBakedModel implements IDynamicBakedModel {
class QnbFormedBakedModel implements BakedModel, FabricBakedModel {
private static final SpriteIdentifier TEXTURE_LINK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "block/quantum_link"));
@@ -75,23 +79,46 @@ class QnbFormedBakedModel implements IDynamicBakedModel {
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand,
IModelData modelData) {
QnbFormedState formedState = modelData.getData(QuantumBridgeBlockEntity.FORMED_STATE);
if (formedState == null) {
return this.baseModel.getQuads(state, side, rand);
}
if (side != null) {
return Collections.emptyList();
}
return this.getQuads(formedState, state);
public boolean isVanillaAdapter() {
return false;
}
private List<BakedQuad> getQuads(QnbFormedState formedState, BlockState state) {
CubeBuilder builder = new CubeBuilder();
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
QnbFormedState formedState = getState(blockView, pos);
if (formedState == null) {
context.fallbackConsumer().accept(this.baseModel);
return;
}
buildQuads(context.getEmitter(), formedState, state);
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
return baseModel.getQuads(state, face, random);
}
private static QnbFormedState getState(BlockRenderView view, BlockPos pos) {
if (!(view instanceof RenderAttachedBlockView)) {
return null;
}
Object attachment = ((RenderAttachedBlockView) view).getBlockEntityRenderAttachment(pos);
if (attachment instanceof QnbFormedState) {
return (QnbFormedState) attachment;
}
return null;
}
private void buildQuads(QuadEmitter emitter, QnbFormedState formedState, BlockState state) {
CubeBuilder builder = new CubeBuilder(emitter);
if (state.getBlock() == this.linkBlock) {
Set<Direction> sides = formedState.getAdjacentQuantumBridges();
@@ -155,8 +182,6 @@ class QnbFormedBakedModel implements IDynamicBakedModel {
}
}
}
return builder.getOutput();
}
private void renderCableAt(CubeBuilder builder, float thickness, Sprite texture, float pull,
@@ -188,6 +213,11 @@ class QnbFormedBakedModel implements IDynamicBakedModel {
}
}
@Override
public ModelTransformation getTransformation() {
return ModelTransformation.NONE;
}
@Override
public boolean useAmbientOcclusion() {
return this.baseModel.useAmbientOcclusion();
@@ -0,0 +1,40 @@
package appeng.block.qnb;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import com.google.common.collect.ImmutableSet;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
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 javax.annotation.Nullable;
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Stream;
public class QnbFormedModel implements BasicUnbakedModel {
private static final Identifier MODEL_RING = new Identifier(AppEng.MOD_ID, "block/qnb/ring");
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
BakedModel ringModel = loader.bake(MODEL_RING, rotationContainer);
return new QnbFormedBakedModel(ringModel, textureGetter);
}
@Override
public Collection<Identifier> getModelDependencies() {
return ImmutableSet.of(MODEL_RING);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return QnbFormedBakedModel.getRequiredTextures().stream();
}
}
+18 -14
View File
@@ -1,6 +1,9 @@
package appeng.client;
import appeng.api.parts.CableRenderMode;
import appeng.block.crafting.AbstractCraftingUnitBlock;
import appeng.block.paint.PaintSplotchesModel;
import appeng.block.qnb.QnbFormedModel;
import appeng.bootstrap.ModelsReloadCallback;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IItemColorRegistrationComponent;
@@ -8,9 +11,9 @@ import appeng.bootstrap.components.IModelBakeComponent;
import appeng.client.gui.implementations.*;
import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.crafting.CraftingCubeModel;
import appeng.client.render.effects.*;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.model.*;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.client.render.tesr.InscriberTESR;
import appeng.client.render.tesr.SkyChestTESR;
@@ -239,28 +242,29 @@ public final class AppEngClient extends AppEngBase {
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
// FIXME FABRIC addBuiltInModel("glass", GlassModel::new);
addBuiltInModel("block/quartz_glass", GlassModel::new);
addBuiltInModel("block/sky_compass", SkyCompassModel::new);
addBuiltInModel("item/sky_compass", SkyCompassModel::new);
// FIXME FABRIC addBuiltInModel("item/dummy_fluid_item", DummyFluidItemModel::new);
// FIXME FABRIC addBuiltInModel("memory_card", MemoryCardModel::new);
// FIXME FABRIC addBuiltInModel("biometric_card", BiometricCardModel::new);
addBuiltInModel("item/memory_card", MemoryCardModel::new);
addBuiltInModel("item/biometric_card", BiometricCardModel::new);
addBuiltInModel("block/drive", DriveModel::new);
// FIXME FABRIC addBuiltInModel("color_applicator", ColorApplicatorModel::new);
addBuiltInModel("color_applicator", ColorApplicatorModel::new); // FIXME need to wire this up
addBuiltInModel("block/spatial_pylon", SpatialPylonModel::new);
// FIXME FABRIC addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
// FIXME FABRIC addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
addBuiltInModel("block/paint", PaintSplotchesModel::new);
addBuiltInModel("block/qnb/qnb_formed", QnbFormedModel::new);
// FIXME FABRIC addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
// FIXME FABRIC addBuiltInModel("facade", FacadeItemModel::new);
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "encoded_pattern"),
// FIXME FABRIC EncodedPatternModelLoader.INSTANCE);
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "part_plane"),
// FIXME FABRIC PlaneModelLoader.INSTANCE);
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "crafting_cube"),
// FIXME FABRIC CraftingCubeModelLoader.INSTANCE);
addBuiltInModel("block/crafting/1k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_1K));
addBuiltInModel("block/crafting/4k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_4K));
addBuiltInModel("block/crafting/16k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_16K));
addBuiltInModel("block/crafting/64k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_64K));
addBuiltInModel("block/crafting/accelerator_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.ACCELERATOR));
addBuiltInModel("block/crafting/monitor_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.MONITOR));
addBuiltInModel("block/crafting/unit_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.UNIT));
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "cable_bus"),
// FIXME FABRIC new CableBusModelLoader());
}
private static <T extends UnbakedModel> void addBuiltInModel(String id, Supplier<T> modelFactory) {
@@ -18,21 +18,27 @@
package appeng.client.render.crafting;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
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.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraft.world.BlockRenderView;
import appeng.client.render.cablebus.CubeBuilder;
@@ -45,7 +51,7 @@ import appeng.util.Platform;
* the "ring" that frames the multi-block structure and delegates rendering of
* the "inner" part of each block to the subclasses of this class.
*/
abstract class CraftingCubeBakedModel implements IDynamicBakedModel {
abstract class CraftingCubeBakedModel implements BakedModel, FabricBakedModel {
private final Sprite ringCorner;
@@ -59,61 +65,75 @@ abstract class CraftingCubeBakedModel implements IDynamicBakedModel {
this.ringVer = ringVer;
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand,
@Nonnull IModelData extraData) {
if (side == null) {
return Collections.emptyList(); // No generic quads for this model
}
EnumSet<Direction> connections = getConnections(extraData);
List<BakedQuad> quads = new ArrayList<>();
CubeBuilder builder = new CubeBuilder(quads);
builder.setDrawFaces(EnumSet.of(side));
// Add the quads for the ring that frames the entire multi-block structure
this.addRing(builder, side, connections);
// Calculate the bounds of the "inner" block that is framed by the border drawn
// above
float x2 = connections.contains(Direction.EAST) ? 16 : 13.01f;
float x1 = connections.contains(Direction.WEST) ? 0 : 2.99f;
float y2 = connections.contains(Direction.UP) ? 16 : 13.01f;
float y1 = connections.contains(Direction.DOWN) ? 0 : 2.99f;
float z2 = connections.contains(Direction.SOUTH) ? 16 : 13.01f;
float z1 = connections.contains(Direction.NORTH) ? 0 : 2.99f;
// On the axis of the side that we're currently drawing, extend the dimensions
// out to the outer face of the block
switch (side) {
case DOWN:
case UP:
y1 = 0;
y2 = 16;
break;
case NORTH:
case SOUTH:
z1 = 0;
z2 = 16;
break;
case WEST:
case EAST:
x1 = 0;
x2 = 16;
break;
}
this.addInnerCube(side, state, extraData, builder, x1, y1, z1, x2, y2, z2);
return quads;
public boolean isVanillaAdapter() {
return false;
}
private void addRing(CubeBuilder builder, @Nullable Direction side, EnumSet<Direction> connections) {
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
CraftingCubeModelData modelData = getModelData(blockView, pos);
EnumSet<Direction> connections = modelData.getConnections();
CubeBuilder builder = new CubeBuilder(context.getEmitter());
for (Direction side : Direction.values()) {
builder.setDrawFaces(EnumSet.of(side));
// Add the quads for the ring that frames the entire multi-block structure
this.addRing(builder, side, connections);
// Calculate the bounds of the "inner" block that is framed by the border drawn
// above
float x2 = connections.contains(Direction.EAST) ? 16 : 13.01f;
float x1 = connections.contains(Direction.WEST) ? 0 : 2.99f;
float y2 = connections.contains(Direction.UP) ? 16 : 13.01f;
float y1 = connections.contains(Direction.DOWN) ? 0 : 2.99f;
float z2 = connections.contains(Direction.SOUTH) ? 16 : 13.01f;
float z1 = connections.contains(Direction.NORTH) ? 0 : 2.99f;
// On the axis of the side that we're currently drawing, extend the dimensions
// out to the outer face of the block
switch (side) {
case DOWN:
case UP:
y1 = 0;
y2 = 16;
break;
case NORTH:
case SOUTH:
z1 = 0;
z2 = 16;
break;
case WEST:
case EAST:
x1 = 0;
x2 = 16;
break;
}
this.addInnerCube(side, state, modelData, builder, x1, y1, z1, x2, y2, z2);
}
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
return Collections.emptyList();
}
@Override
public ModelTransformation getTransformation() {
return ModelTransformation.NONE;
}
private void addRing(CubeBuilder builder, Direction side, EnumSet<Direction> connections) {
// Fill in the corners
builder.setTexture(this.ringCorner);
this.addCornerCap(builder, connections, side, Direction.UP, Direction.EAST, Direction.NORTH);
@@ -244,15 +264,18 @@ abstract class CraftingCubeBakedModel implements IDynamicBakedModel {
// Retrieve the cube connection state from the block state
// If none is present, just assume there are no adjacent crafting cube blocks
private static EnumSet<Direction> getConnections(IModelData modelData) {
if (!(modelData instanceof CraftingCubeModelData)) {
return EnumSet.noneOf(Direction.class);
private static CraftingCubeModelData getModelData(BlockRenderView blockRenderView, BlockPos pos) {
if (!(blockRenderView instanceof RenderAttachedBlockView)) {
return null;
}
return ((CraftingCubeModelData) modelData).getConnections();
Object attached = ((RenderAttachedBlockView) blockRenderView).getBlockEntityRenderAttachment(pos);
if (attached instanceof CraftingCubeModelData) {
return (CraftingCubeModelData) attached;
}
return null;
}
protected abstract void addInnerCube(Direction facing, BlockState state, IModelData modelData, CubeBuilder builder,
protected abstract void addInnerCube(Direction facing, BlockState state, CraftingCubeModelData modelData, CubeBuilder builder,
float x1, float y1, float z1, float x2, float y2, float z2);
@Override
@@ -18,32 +18,25 @@
package appeng.client.render.crafting;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.block.crafting.AbstractCraftingUnitBlock;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* The built-in model for the connected texture crafting cube.
*/
class CraftingCubeModel implements IModelGeometry<CraftingCubeModel> {
public class CraftingCubeModel implements BasicUnbakedModel {
private final static SpriteIdentifier RING_CORNER = texture("ring_corner");
private final static SpriteIdentifier RING_SIDE_HOR = texture("ring_side_hor");
@@ -62,41 +55,39 @@ class CraftingCubeModel implements IModelGeometry<CraftingCubeModel> {
private final AbstractCraftingUnitBlock.CraftingUnitType type;
CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType type) {
public CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType type) {
this.type = type;
}
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return ImmutableList.of(RING_CORNER, RING_SIDE_HOR, RING_SIDE_VER, UNIT_BASE, LIGHT_BASE, ACCELERATOR_LIGHT,
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.of(RING_CORNER, RING_SIDE_HOR, RING_SIDE_VER, UNIT_BASE, LIGHT_BASE, ACCELERATOR_LIGHT,
STORAGE_1K_LIGHT, STORAGE_4K_LIGHT, STORAGE_16K_LIGHT, STORAGE_64K_LIGHT, MONITOR_BASE,
MONITOR_LIGHT_DARK, MONITOR_LIGHT_MEDIUM, MONITOR_LIGHT_BRIGHT);
}
@Nullable
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform modelTransform,
ModelOverrideList overrides, Identifier modelLocation) {
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
// Retrieve our textures and pass them on to the baked model
Sprite ringCorner = spriteGetter.apply(RING_CORNER);
Sprite ringSideHor = spriteGetter.apply(RING_SIDE_HOR);
Sprite ringSideVer = spriteGetter.apply(RING_SIDE_VER);
Sprite ringCorner = textureGetter.apply(RING_CORNER);
Sprite ringSideHor = textureGetter.apply(RING_SIDE_HOR);
Sprite ringSideVer = textureGetter.apply(RING_SIDE_VER);
switch (this.type) {
case UNIT:
return new UnitBakedModel(ringCorner, ringSideHor, ringSideVer, spriteGetter.apply(UNIT_BASE));
return new UnitBakedModel(ringCorner, ringSideHor, ringSideVer, textureGetter.apply(UNIT_BASE));
case ACCELERATOR:
case STORAGE_1K:
case STORAGE_4K:
case STORAGE_16K:
case STORAGE_64K:
return new LightBakedModel(ringCorner, ringSideHor, ringSideVer, spriteGetter.apply(LIGHT_BASE),
getLightTexture(spriteGetter, this.type));
return new LightBakedModel(ringCorner, ringSideHor, ringSideVer, textureGetter.apply(LIGHT_BASE),
getLightTexture(textureGetter, this.type));
case MONITOR:
return new MonitorBakedModel(ringCorner, ringSideHor, ringSideVer, spriteGetter.apply(UNIT_BASE),
spriteGetter.apply(MONITOR_BASE), spriteGetter.apply(MONITOR_LIGHT_DARK),
spriteGetter.apply(MONITOR_LIGHT_MEDIUM), spriteGetter.apply(MONITOR_LIGHT_BRIGHT));
return new MonitorBakedModel(ringCorner, ringSideHor, ringSideVer, textureGetter.apply(UNIT_BASE),
textureGetter.apply(MONITOR_BASE), textureGetter.apply(MONITOR_LIGHT_DARK),
textureGetter.apply(MONITOR_LIGHT_MEDIUM), textureGetter.apply(MONITOR_LIGHT_BRIGHT));
default:
throw new IllegalArgumentException("Unsupported crafting unit type: " + this.type);
}
@@ -18,6 +18,7 @@
package appeng.client.render.crafting;
import appeng.tile.crafting.CraftingCubeModelData;
import net.minecraft.block.BlockState;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.Direction;
@@ -45,8 +46,8 @@ class LightBakedModel extends CraftingCubeBakedModel {
}
@Override
protected void addInnerCube(Direction facing, BlockState state, IModelData modelData, CubeBuilder builder, float x1,
float y1, float z1, float x2, float y2, float z2) {
protected void addInnerCube(Direction facing, BlockState state, CraftingCubeModelData modelData, CubeBuilder builder, float x1,
float y1, float z1, float x2, float y2, float z2) {
builder.setTexture(this.baseTexture);
builder.addCube(x1, y1, z1, x2, y2, z2);
@@ -18,6 +18,7 @@
package appeng.client.render.crafting;
import appeng.tile.crafting.CraftingCubeModelData;
import net.minecraft.block.BlockState;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.Direction;
@@ -26,7 +27,6 @@ import net.minecraft.util.math.Direction;
import appeng.api.util.AEColor;
import appeng.block.crafting.CraftingMonitorBlock;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.client.render.model.AEModelData;
import appeng.tile.crafting.CraftingMonitorModelData;
/**
@@ -60,9 +60,9 @@ public class MonitorBakedModel extends CraftingCubeBakedModel {
}
@Override
protected void addInnerCube(Direction side, BlockState state, IModelData modelData, CubeBuilder builder, float x1,
float y1, float z1, float x2, float y2, float z2) {
Direction forward = getForward(modelData);
protected void addInnerCube(Direction side, BlockState state, CraftingCubeModelData modelData, CubeBuilder builder, float x1,
float y1, float z1, float x2, float y2, float z2) {
Direction forward = modelData.getForward();
// For sides other than the front, use the chassis texture
if (side != forward) {
@@ -94,17 +94,11 @@ public class MonitorBakedModel extends CraftingCubeBakedModel {
}
private static AEColor getColor(IModelData modelData) {
private static AEColor getColor(CraftingCubeModelData modelData) {
if (modelData instanceof CraftingMonitorModelData) {
return ((CraftingMonitorModelData) modelData).getColor();
}
return AEColor.TRANSPARENT;
}
private static Direction getForward(IModelData modelData) {
if (modelData instanceof AEModelData) {
return ((AEModelData) modelData).getForward();
}
return Direction.NORTH;
}
}
@@ -18,6 +18,7 @@
package appeng.client.render.crafting;
import appeng.tile.crafting.CraftingCubeModelData;
import net.minecraft.block.BlockState;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.Direction;
@@ -39,8 +40,8 @@ class UnitBakedModel extends CraftingCubeBakedModel {
}
@Override
protected void addInnerCube(Direction facing, BlockState state, IModelData modelData, CubeBuilder builder, float x1,
float y1, float z1, float x2, float y2, float z2) {
protected void addInnerCube(Direction facing, BlockState state, CraftingCubeModelData modelData, CubeBuilder builder, float x1,
float y1, float z1, float x2, float y2, float z2) {
builder.setTexture(this.unitTexture);
builder.addCube(x1, y1, z1, x2, y2, z2);
}
@@ -0,0 +1,147 @@
package appeng.client.render.model;
import appeng.api.implementations.items.IBiometricCard;
import appeng.api.util.AEColor;
import appeng.client.render.cablebus.CubeBuilder;
import com.mojang.authlib.GameProfile;
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.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
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.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
class BiometricCardBakedModel implements BakedModel, FabricBakedModel {
private final BakedModel baseModel;
private final Sprite texture;
BiometricCardBakedModel(BakedModel baseModel, Sprite texture) {
this.baseModel = baseModel;
this.texture = texture;
}
@Override
public boolean isVanillaAdapter() {
return false;
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
// Not intended as a block
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
context.fallbackConsumer().accept(this.baseModel);
// Get the player's name hash from the card
int hash = getHash(stack);
emitColorCode(context.getEmitter(), hash);
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
return this.baseModel.getQuads(state, side, rand);
}
private void emitColorCode(QuadEmitter emitter, int hash) {
CubeBuilder builder = new CubeBuilder(emitter);
builder.setTexture(this.texture);
AEColor col = AEColor.values()[Math.abs(3 + hash) % AEColor.values().length];
if (hash == 0) {
col = AEColor.BLACK;
}
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 6; y++) {
final boolean isLit;
// This makes the border always use the darker color
if (x == 0 || y == 0 || x == 7 || y == 5) {
isLit = false;
} else {
isLit = (hash & (1 << x)) != 0 || (hash & (1 << y)) != 0;
}
if (isLit) {
builder.setColorRGB(col.mediumVariant);
} else {
final float scale = 0.3f / 255.0f;
builder.setColorRGB(((col.blackVariant >> 16) & 0xff) * scale,
((col.blackVariant >> 8) & 0xff) * scale, (col.blackVariant & 0xff) * scale);
}
builder.addCube(4 + x, 6 + y, 7.5f, 4 + x + 1, 6 + y + 1, 8.5f);
}
}
}
@Override
public boolean useAmbientOcclusion() {
return this.baseModel.useAmbientOcclusion();
}
@Override
public boolean hasDepth() {
return this.baseModel.hasDepth();
}
@Override
public boolean isSideLit() {
return false; // This is an item model
}
@Override
public boolean isBuiltin() {
return this.baseModel.isBuiltin();
}
@Override
public Sprite getSprite() {
return this.baseModel.getSprite();
}
@Override
public ModelTransformation getTransformation() {
return this.baseModel.getTransformation();
}
@Override
public ModelOverrideList getOverrides() {
return ModelOverrideList.EMPTY;
}
private static int getHash(ItemStack stack) {
String username = "";
if (stack.getItem() instanceof IBiometricCard) {
final GameProfile gp = ((IBiometricCard) stack.getItem()).getProfile(stack);
if (gp != null) {
if (gp.getId() != null) {
username = gp.getId().toString();
} else {
username = gp.getName();
}
}
}
return !username.isEmpty() ? username.hashCode() : 0;
}
}
@@ -0,0 +1,49 @@
package appeng.client.render.model;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* Model wrapper for the biometric card item model, which combines a base card
* layer with a "visual hash" of the player name
*/
public class BiometricCardModel implements BasicUnbakedModel {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/biometric_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/biometric_card_hash"));
@Override
public Collection<Identifier> getModelDependencies() {
return Collections.singleton(MODEL_BASE);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.of(TEXTURE);
}
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
Sprite texture = textureGetter.apply(TEXTURE);
BakedModel baseModel = loader.bake(MODEL_BASE, rotationContainer);
return new BiometricCardBakedModel(baseModel, texture);
}
}
@@ -0,0 +1,83 @@
package appeng.client.render.model;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Random;
import javax.annotation.Nullable;
import appeng.mixins.BakedQuadAccessor;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.texture.Sprite;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.util.math.Direction;
/**
* This baked model will take the generated item model for the colored color applicator,
* and associate tint indices with the added layers that correspond to the light/medium/dark
* variants of the {@link appeng.api.util.AEColor}.
* <p>
* Using the color provider registered in {@link appeng.items.tools.powered.ColorApplicatorItemRendering},
* this results in the right color being multiplied with the corresponding layer.
*/
class ColorApplicatorBakedModel extends ForwardingBakedModel {
private final EnumMap<Direction, List<BakedQuad>> quadsBySide;
private final List<BakedQuad> generalQuads;
ColorApplicatorBakedModel(BakedModel baseModel, Sprite texDark,
Sprite texMedium, Sprite texBright) {
this.wrapped = baseModel;
// Put the tint indices in... Since this is an item model, we are ignoring rand
this.generalQuads = this.fixQuadTint(null, texDark, texMedium, texBright);
this.quadsBySide = new EnumMap<>(Direction.class);
for (Direction facing : Direction.values()) {
this.quadsBySide.put(facing, this.fixQuadTint(facing, texDark, texMedium, texBright));
}
}
private Sprite getSprite(BakedQuad quad) {
return ((BakedQuadAccessor) quad).getSprite();
}
private List<BakedQuad> fixQuadTint(Direction facing, Sprite texDark, Sprite texMedium,
Sprite texBright) {
List<BakedQuad> quads = this.wrapped.getQuads(null, facing, new Random(0));
List<BakedQuad> result = new ArrayList<>(quads.size());
for (BakedQuad quad : quads) {
int tint;
if (getSprite(quad) == texDark) {
tint = 1;
} else if (getSprite(quad) == texMedium) {
tint = 2;
} else if (getSprite(quad) == texBright) {
tint = 3;
} else {
result.add(quad);
continue;
}
BakedQuad newQuad = new BakedQuad(quad.getVertexData(), tint, quad.getFace(), getSprite(quad),
quad.hasShade());
result.add(newQuad);
}
return result;
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
if (side == null) {
return this.generalQuads;
}
return this.quadsBySide.get(side);
}
}
@@ -0,0 +1,56 @@
package appeng.client.render.model;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* A color applicator uses the base model, and extends it with additional layers
* that are colored according to the selected color of the applicator.
*/
public class ColorApplicatorModel implements BasicUnbakedModel {
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID,
"item/color_applicator_colored");
private static final SpriteIdentifier TEXTURE_DARK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_dark"));
private static final SpriteIdentifier TEXTURE_MEDIUM = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_medium"));
private static final SpriteIdentifier TEXTURE_BRIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_bright"));
@Override
public Collection<Identifier> getModelDependencies() {
return Collections.singleton(MODEL_BASE);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.of(TEXTURE_DARK, TEXTURE_MEDIUM, TEXTURE_DARK);
}
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
BakedModel baseModel = loader.bake(MODEL_BASE, rotationContainer);
Sprite texDark = textureGetter.apply(TEXTURE_DARK);
Sprite texMedium = textureGetter.apply(TEXTURE_MEDIUM);
Sprite texBright = textureGetter.apply(TEXTURE_BRIGHT);
return new ColorApplicatorBakedModel(baseModel, texDark, texMedium, texBright);
}
}
@@ -18,48 +18,43 @@
package appeng.client.render.model;
import java.util.ArrayList;
import appeng.decorative.solid.GlassState;
import appeng.decorative.solid.QuartzGlassBlock;
import com.google.common.base.Strings;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
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.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
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;
import net.minecraft.client.util.math.Vector3f;
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.util.math.MathHelper;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Strings;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormatElement;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import appeng.decorative.solid.GlassState;
import appeng.decorative.solid.QuartzGlassBlock;
class GlassBakedModel implements IDynamicBakedModel {
// This unlisted property is used to determine the actual block that should be
// rendered
public static final ModelProperty<GlassState> GLASS_STATE = new ModelProperty<>();
class GlassBakedModel implements BakedModel, FabricBakedModel {
private static final byte[][][] OFFSETS = generateOffsets();
@@ -75,6 +70,12 @@ class GlassBakedModel implements IDynamicBakedModel {
// Frame texture
static final SpriteIdentifier[] TEXTURES_FRAME = generateTexturesFrame();
private final RenderMaterial material = RendererAccess.INSTANCE.getRenderer().materialFinder()
.disableDiffuse(0, true)
.disableAo(0, true)
.disableColorIndex(0, true)
.blendMode(0, BlendMode.TRANSLUCENT)
.find();
// Generates the required textures for the frame
private static SpriteIdentifier[] generateTexturesFrame() {
@@ -101,17 +102,13 @@ class GlassBakedModel implements IDynamicBakedModel {
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand,
IModelData extraData) {
if (side == null) {
return Collections.emptyList();
}
public boolean isVanillaAdapter() {
return false;
}
final GlassState glassState = extraData.getData(GLASS_STATE);
if (glassState == null) {
return Collections.emptyList();
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
final GlassState glassState = getGlassState(blockView, pos);
// TODO: This could just use the Random instance we're given...
final int cx = Math.abs(glassState.getX() % 10);
@@ -130,36 +127,51 @@ class GlassBakedModel implements IDynamicBakedModel {
final Sprite glassTexture = this.glassTextures[texIdx];
QuadEmitter emitter = context.getEmitter();
// Render the glass side
final List<BakedQuad> quads = new ArrayList<>(5); // At most 5
for (Direction side : Direction.values()) {
final List<Vector3f> corners = RenderHelper.getFaceCorners(side);
this.emitQuad(emitter, side, corners, glassTexture, u, v);
final List<Vec3d> corners = RenderHelper.getFaceCorners(side);
quads.add(this.createQuad(side, corners, glassTexture, u, v));
/*
* This needs some explanation: The bit-field contains 4-bits, one for each
* direction that a frame may be drawn. Converted to a number, the bit-field is
* then used as an index into the list of frame textures, which have been
* created in such a way that their filenames indicate, in which directions they
* contain borders. i.e. bitmask = 0101 means a border should be drawn up and
* down (in terms of u,v space). Converted to a number, this bitmask is 5. So
* the texture at index 5 is used. That texture had "0101" in its filename to
* indicate this.
*/
final int edgeBitmask = makeBitmask(glassState, side);
final Sprite sideSprite = this.frameTextures[edgeBitmask];
/*
* This needs some explanation: The bit-field contains 4-bits, one for each
* direction that a frame may be drawn. Converted to a number, the bit-field is
* then used as an index into the list of frame textures, which have been
* created in such a way that their filenames indicate, in which directions they
* contain borders. i.e. bitmask = 0101 means a border should be drawn up and
* down (in terms of u,v space). Converted to a number, this bitmask is 5. So
* the texture at index 5 is used. That texture had "0101" in its filename to
* indicate this.
*/
final int edgeBitmask = makeBitmask(glassState, side);
final Sprite sideSprite = this.frameTextures[edgeBitmask];
if (sideSprite != null) {
quads.add(this.createQuad(side, corners, sideSprite, 0, 0));
if (sideSprite != null) {
this.emitQuad(emitter, side, corners, sideSprite, 0, 0);
}
}
return quads;
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
return Collections.emptyList();
}
@Override
public ModelTransformation getTransformation() {
return ModelTransformation.NONE;
}
@Override
public boolean isSideLit() {
// TODO: Forge: Auto-generated method stub
return false;
return false; // Irrelvant because not used as item model
}
/**
@@ -204,65 +216,31 @@ class GlassBakedModel implements IDynamicBakedModel {
return bitmask;
}
private BakedQuad createQuad(Direction side, List<Vec3d> corners, Sprite sprite, float uOffset,
private void emitQuad(QuadEmitter emitter, Direction side, List<Vector3f> corners, Sprite sprite, float uOffset,
float vOffset) {
return this.createQuad(side, corners.get(0), corners.get(1), corners.get(2), corners.get(3), sprite, uOffset,
this.emitQuad(emitter, side, corners.get(0), corners.get(1), corners.get(2), corners.get(3), sprite, uOffset,
vOffset);
}
private BakedQuad createQuad(Direction side, Vec3d c1, Vec3d c2, Vec3d c3, Vec3d c4, Sprite sprite,
private void emitQuad(QuadEmitter emitter, Direction side, Vector3f c1, Vector3f c2, Vector3f c3, Vector3f c4, Sprite sprite,
float uOffset, float vOffset) {
Vec3d normal = new Vec3d(side.getVector());
// Apply the u,v shift.
// This mirrors the logic from OffsetIcon from 1.7
float u1 = MathHelper.clamp(0 - uOffset, 0, 16);
float u2 = MathHelper.clamp(16 - uOffset, 0, 16);
float v1 = MathHelper.clamp(0 - vOffset, 0, 16);
float v2 = MathHelper.clamp(16 - vOffset, 0, 16);
float u1 = sprite.getFrameU(MathHelper.clamp(0 - uOffset, 0, 16));
float u2 = sprite.getFrameU(MathHelper.clamp(16 - uOffset, 0, 16));
float v1 = sprite.getFrameV(MathHelper.clamp(0 - vOffset, 0, 16));
float v2 = sprite.getFrameV(MathHelper.clamp(16 - vOffset, 0, 16));
BakedQuadBuilder builder = new BakedQuadBuilder(sprite);
builder.setQuadOrientation(side);
this.putVertex(builder, normal, c1.x, c1.y, c1.z, sprite, u1, v1);
this.putVertex(builder, normal, c2.x, c2.y, c2.z, sprite, u1, v2);
this.putVertex(builder, normal, c3.x, c3.y, c3.z, sprite, u2, v2);
this.putVertex(builder, normal, c4.x, c4.y, c4.z, sprite, u2, v1);
return builder.build();
}
/*
* This method is as complicated as it is, because the order in which we push
* data into the vertexbuffer actually has to be precisely the order in which
* the vertex elements had been declared in the vertex format.
*/
private void putVertex(BakedQuadBuilder builder, Vec3d normal, double x, double y, double z,
Sprite sprite, float u, float v) {
VertexFormat vertexFormat = builder.getVertexFormat();
for (int e = 0; e < vertexFormat.getElements().size(); e++) {
VertexFormatElement el = vertexFormat.getElements().get(e);
switch (el.getType()) {
case POSITION:
builder.put(e, (float) x, (float) y, (float) z, 1.0f);
break;
case COLOR:
builder.put(e, 1.0f, 1.0f, 1.0f, 1.0f);
break;
case NORMAL:
builder.put(e, (float) normal.x, (float) normal.y, (float) normal.z, 0f);
break;
case UV:
if (el.getIndex() == 0) {
u = sprite.getFrameU(u);
v = sprite.getFrameV(v);
builder.put(e, u, v, 0f, 1f);
break;
}
// Important: Fall through for getIndex() != 0
default:
builder.put(e);
break;
}
}
emitter.nominalFace(side);
emitter.cullFace(side);
emitter.material(material);
emitter.pos(0, c1).sprite(0, 0, u1, v1);
emitter.pos(1, c2).sprite(1, 0, u1, v2);
emitter.pos(2, c3).sprite(2, 0, u2, v2);
emitter.pos(3, c4).sprite(3, 0, u2, v1);
emitter.spriteColor(0, -1, -1, -1, -1);
emitter.emit();
}
@Override
@@ -304,10 +282,7 @@ class GlassBakedModel implements IDynamicBakedModel {
}
@Nonnull
@Override
public IModelData getModelData(@Nonnull BlockRenderView world, @Nonnull BlockPos pos, @Nonnull BlockState state,
@Nonnull IModelData tileData) {
private static GlassState getGlassState(BlockRenderView world, BlockPos pos) {
EnumSet<Direction> flushWith = EnumSet.noneOf(Direction.class);
// Test every direction for another glass block
for (Direction facing : Direction.values()) {
@@ -316,9 +291,7 @@ class GlassBakedModel implements IDynamicBakedModel {
}
}
GlassState glassState = new GlassState(pos.getX(), pos.getY(), pos.getZ(), flushWith);
return new ModelDataMap.Builder().withInitial(GLASS_STATE, glassState).build();
return new GlassState(pos.getX(), pos.getY(), pos.getZ(), flushWith);
}
private static boolean isGlassBlock(BlockView world, BlockPos pos, Direction facing) {
@@ -18,43 +18,36 @@
package appeng.client.render.model;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import appeng.client.render.BasicUnbakedModel;
import com.google.common.collect.ImmutableSet;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelBakeSettings;
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.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nullable;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* Model class for the connected texture glass model.
*/
public class GlassModel implements IModelGeometry<GlassModel> {
public class GlassModel implements BasicUnbakedModel {
@Nullable
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform modelTransform,
ModelOverrideList overrides, Identifier modelLocation) {
return new GlassBakedModel(spriteGetter);
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
return new GlassBakedModel(textureGetter);
}
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
public Stream<SpriteIdentifier> getAdditionalTextures() {
return ImmutableSet
.<SpriteIdentifier>builder().add(GlassBakedModel.TEXTURE_A, GlassBakedModel.TEXTURE_B,
GlassBakedModel.TEXTURE_C, GlassBakedModel.TEXTURE_D)
.add(GlassBakedModel.TEXTURES_FRAME).build();
.add(GlassBakedModel.TEXTURES_FRAME).build().stream();
}
}
@@ -0,0 +1,63 @@
package appeng.client.render.model;
import appeng.api.implementations.items.IMemoryCard;
import appeng.api.util.AEColor;
import appeng.client.render.cablebus.CubeBuilder;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.texture.Sprite;
import net.minecraft.item.ItemStack;
import java.util.Random;
import java.util.function.Supplier;
class MemoryCardBakedModel extends ForwardingBakedModel implements FabricBakedModel {
private static final AEColor[] DEFAULT_COLOR_CODE = new AEColor[] { AEColor.TRANSPARENT, AEColor.TRANSPARENT,
AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT,
AEColor.TRANSPARENT, };
private final Sprite texture;
public MemoryCardBakedModel(BakedModel baseModel, Sprite texture) {
this.wrapped = baseModel;
this.texture = texture;
}
@Override
public boolean isVanillaAdapter() {
return false;
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
context.fallbackConsumer().accept(wrapped);
AEColor[] colorCode = getColorCode(stack);
CubeBuilder builder = new CubeBuilder(context.getEmitter());
builder.setTexture(this.texture);
for (int x = 0; x < 4; x++) {
for (int y = 0; y < 2; y++) {
final AEColor color = colorCode[x + y * 4];
builder.setColorRGB(color.mediumVariant);
builder.addCube(7 + x, 8 + (1 - y), 7.5f, 7 + x + 1, 8 + (1 - y) + 1, 8.5f);
}
}
}
private static AEColor[] getColorCode(ItemStack stack) {
if (stack.getItem() instanceof IMemoryCard) {
final IMemoryCard memoryCard = (IMemoryCard) stack.getItem();
return memoryCard.getColorCode(stack);
}
return DEFAULT_COLOR_CODE;
}
}
@@ -0,0 +1,48 @@
package appeng.client.render.model;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* Model wrapper for the memory card item model, which combines a base card
* layer with a "visual hash" of the part/tile.
*/
public class MemoryCardModel implements BasicUnbakedModel {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/memory_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/memory_card_hash"));
@Override
public Collection<Identifier> getModelDependencies() {
return Collections.singleton(MODEL_BASE);
}
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
Sprite texture = textureGetter.apply(TEXTURE);
BakedModel baseModel = loader.bake(MODEL_BASE, rotationContainer);
return new MemoryCardBakedModel(baseModel, texture);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.of(TEXTURE);
}
}
@@ -24,47 +24,48 @@ import java.util.List;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
// TODO: Investigate use of CubeBuilder instead
final class RenderHelper {
private static EnumMap<Direction, List<Vec3d>> cornersForFacing = generateCornersForFacings();
private static EnumMap<Direction, List<Vector3f>> cornersForFacing = generateCornersForFacings();
private RenderHelper() {
}
static List<Vec3d> getFaceCorners(Direction side) {
static List<Vector3f> getFaceCorners(Direction side) {
return cornersForFacing.get(side);
}
private static EnumMap<Direction, List<Vec3d>> generateCornersForFacings() {
EnumMap<Direction, List<Vec3d>> result = new EnumMap<>(Direction.class);
private static EnumMap<Direction, List<Vector3f>> generateCornersForFacings() {
EnumMap<Direction, List<Vector3f>> result = new EnumMap<>(Direction.class);
for (Direction facing : Direction.values()) {
List<Vec3d> corners;
List<Vector3f> corners;
float offset = (facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ? 0 : 1;
float offset = (facing.getDirection() == Direction.AxisDirection.NEGATIVE) ? 0 : 1;
switch (facing.getAxis()) {
default:
case X:
corners = Lists.newArrayList(new Vec3d(offset, 1, 1), new Vec3d(offset, 0, 1),
new Vec3d(offset, 0, 0), new Vec3d(offset, 1, 0));
corners = Lists.newArrayList(new Vector3f(offset, 1, 1), new Vector3f(offset, 0, 1),
new Vector3f(offset, 0, 0), new Vector3f(offset, 1, 0));
break;
case Y:
corners = Lists.newArrayList(new Vec3d(1, offset, 1), new Vec3d(1, offset, 0),
new Vec3d(0, offset, 0), new Vec3d(0, offset, 1));
corners = Lists.newArrayList(new Vector3f(1, offset, 1), new Vector3f(1, offset, 0),
new Vector3f(0, offset, 0), new Vector3f(0, offset, 1));
break;
case Z:
corners = Lists.newArrayList(new Vec3d(0, 1, offset), new Vec3d(0, 0, offset),
new Vec3d(1, 0, offset), new Vec3d(1, 1, offset));
corners = Lists.newArrayList(new Vector3f(0, 1, offset), new Vector3f(0, 0, offset),
new Vector3f(1, 0, offset), new Vector3f(1, 1, offset));
break;
}
if (facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) {
if (facing.getDirection() == Direction.AxisDirection.NEGATIVE) {
corners = Lists.reverse(corners);
}
@@ -20,10 +20,6 @@ package appeng.client.render.model;
import appeng.hooks.CompassManager;
import appeng.hooks.CompassResult;
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.MeshBuilder;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.block.BlockState;
@@ -47,7 +43,6 @@ import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -85,30 +80,18 @@ public class SkyCompassBakedModel implements BakedModel, FabricBakedModel {
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
MeshBuilder mb = RendererAccess.INSTANCE.getRenderer().meshBuilder();
mb.getEmitter().square(Direction.UP, 0, 0, 1, 1, 0).emit();
Mesh build = mb.build();
context.meshConsumer().accept(build);
float rotation = getAnimatedRotation(pos, false);
emitQuads(context, rotation);
// Pre-compute the quad count to avoid list resizes
context.fallbackConsumer().accept(this.base);
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
// This is used to render a compass pointing in a specific direction when being
// held in hand
emitQuads(context, this.fallbackRotation);
}
private void emitQuads(RenderContext context, float rotation) {
// Pre-compute the quad count to avoid list resizes
context.fallbackConsumer().accept(this.base);
context.fallbackConsumer().accept(base);
// This is used to render a compass pointing in a specific direction when being held in hand
// Set up the rotation around the Y-axis for the pointer
context.pushTransform(quad -> {
Quaternion quaternion = new Quaternion(0, rotation, 0, false);
Quaternion quaternion = new Quaternion(0, this.fallbackRotation, 0, false);
Vector3f pos = new Vector3f();
for (int i = 0; i < 4; i++) {
quad.copyPos(i, pos);
@@ -43,7 +43,7 @@ public class ItemRenderable<T extends BlockEntity> implements Renderable<T> {
if (pair != null && pair.getLeft() != null) {
matrixStack.push();
if (pair.getRight() != null) {
pair.getRight().apply(true, matrixStack); // FIXME: check left handed
pair.getRight().apply(false, matrixStack); // FIXME: check left handed
}
MinecraftClient.getInstance().getItemRenderer().renderItem(pair.getLeft(),
ModelTransformation.Mode.GROUND, combinedLight, combinedOverlay, matrixStack, buffers);
@@ -67,7 +67,6 @@ public class SkyCompassTESR extends BlockEntityRenderer<SkyCompassBlockEntity> {
return;
}
BakedModel baseModel = skyCompassModel.getBase();
BakedModel pointerModel = skyCompassModel.getPointer();
Direction forward = te.getForward();
@@ -78,17 +77,14 @@ public class SkyCompassTESR extends BlockEntityRenderer<SkyCompassBlockEntity> {
if (forward == Direction.UP || forward == Direction.DOWN) {
up = Direction.NORTH;
}
// Flip forward/up for rendering, the base model is facing up without any
// rotation
ms.push();
VertexConsumer buffer = buffers.getBuffer(RenderLayer.getSolid());
modelRenderer.render(te.getWorld(), model, blockState, te.getPos(), ms, buffer, false, new Random(), 42L, combinedOverlayIn);
// modelRenderer.render(ms.peek(), buffer, null, baseModel, 1, 1, 1, combinedLightIn, combinedOverlayIn);
float rotation = getRotation(te);
ms.translate(0.5D, 0.5D, 0.5D);
// Flip forward/up for rendering, the base model
// is facing up without any rotation
FacingToRotation.get(up, forward).push(ms);
ms.multiply(new Quaternion(0, rotation, 0, false));
ms.translate(-0.5D, -0.5D, -0.5D);
@@ -43,6 +43,8 @@ import static appeng.block.crafting.AbstractCraftingUnitBlock.CraftingUnitType;
import appeng.bootstrap.components.IInitComponent;
import appeng.bootstrap.definitions.TileEntityDefinition;
import appeng.client.render.crafting.CraftingCubeRendering;
import appeng.client.render.crafting.CraftingMonitorTESR;
import appeng.client.render.crafting.MonitorBakedModel;
import appeng.client.render.model.AutoRotatingBakedModel;
import appeng.client.render.spatial.SpatialPylonRendering;
import appeng.client.render.tesr.ChestTileEntityRenderer;
@@ -465,7 +467,7 @@ public final class ApiBlocks implements IBlocks {
@Environment(EnvType.CLIENT)
@Override
public void customize(TileEntityRendering<CraftingMonitorBlockEntity> rendering) {
// FIXME FABRIC rendering.tileEntityRenderer(CraftingMonitorTESR::new);
rendering.tileEntityRenderer(CraftingMonitorTESR::new);
}
}).build())
.rendering(new BlockRenderingCustomizer() {
@@ -475,9 +477,9 @@ public final class ApiBlocks implements IBlocks {
rendering.renderType(RenderLayer.getCutout());
rendering.modelCustomizer((path, model) -> {
// The formed model handles rotations itself, the unformed one does not
// FIXME FABRIC if (model instanceof MonitorBakedModel) {
// FIXME FABRIC return model;
// FIXME FABRIC }
if (model instanceof MonitorBakedModel) {
return model;
}
return new AutoRotatingBakedModel(model);
});
}
@@ -42,7 +42,7 @@ public final class BlockToolDispenseItemBehavior extends ItemDispenserBehavior {
if (w instanceof ServerWorld) {
ItemUsageContext context = new AutomaticItemPlacementContext(w, dispenser.getBlockPos().offset(direction),
direction, dispensedItem, direction.getOpposite());
tm.onItemUse(context);
tm.useOnBlock(context);
}
}
return dispensedItem;
+1 -1
View File
@@ -23,6 +23,6 @@ import net.minecraft.util.ActionResult;
public interface IBlockTool {
// Workaround for dispenser logic.
ActionResult onItemUse(ItemUsageContext itemUseContext);
ActionResult useOnBlock(ItemUsageContext itemUseContext);
}
@@ -0,0 +1,48 @@
package appeng.hooks;
import appeng.items.misc.EncodedPatternItem;
import appeng.mixins.ItemRendererAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.item.ItemStack;
public final class ItemRendererHooks {
// Prevents recursion in the hook below
private static final ThreadLocal<ItemStack> OVERRIDING_FOR = new ThreadLocal<>();
private ItemRendererHooks() {
}
/**
* This hook will exchange the rendered item model for encoded patterns to the item being crafted by them
* if shift is held.
*/
public static boolean onRenderGuiItemModel(ItemRenderer renderer, ItemStack stack, int x, int y, BakedModel model) {
if (stack.getItem() instanceof EncodedPatternItem && OVERRIDING_FOR.get() != stack) {
boolean shiftHeld = Screen.hasShiftDown();
ClientWorld world = MinecraftClient.getInstance().world;
if (shiftHeld && world != null) {
EncodedPatternItem iep = (EncodedPatternItem) stack.getItem();
ItemStack output = iep.getOutput(world, stack);
if (!output.isEmpty()) {
BakedModel realModel = MinecraftClient.getInstance().getItemRenderer().getModels()
.getModel(output);
ItemRendererAccessor self = (ItemRendererAccessor) renderer;
OVERRIDING_FOR.set(stack);
try {
self.callRenderGuiItemModel(stack, x, y, realModel);
} finally {
OVERRIDING_FOR.remove();
}
return true;
}
}
}
return false;
}
}
@@ -35,7 +35,6 @@ import appeng.api.util.DimensionalCoord;
import appeng.block.networking.CableBusBlock;
import appeng.block.paint.PaintSplotchesBlock;
import appeng.core.AEConfig;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.core.localization.GuiText;
import appeng.helpers.IMouseWheelItem;
@@ -118,7 +117,7 @@ public class ColorApplicatorItem extends AEBasePoweredItem
}
@Override
public ActionResult onItemUse(ItemUsageContext context) {
public ActionResult useOnBlock(ItemUsageContext context) {
World w = context.getWorld();
BlockPos pos = context.getBlockPos();
ItemStack is = context.getStack();
@@ -219,7 +219,7 @@ public class EntropyManipulatorItem extends AEBasePoweredItem implements IBlockT
if (state.getMaterial() == Material.LAVA || state.getMaterial() == Material.WATER) {
if (Platform.hasPermissions(new DimensionalCoord(w, pos), p)) {
ItemUsageContext context = new ItemUsageContext(p, hand, target);
this.onItemUse(context);
this.useOnBlock(context);
}
}
}
@@ -228,7 +228,7 @@ public class EntropyManipulatorItem extends AEBasePoweredItem implements IBlockT
}
@Override
public ActionResult onItemUse(ItemUsageContext context) {
public ActionResult useOnBlock(ItemUsageContext context) {
World w = context.getWorld();
ItemStack item = context.getStack();
BlockPos pos = context.getBlockPos();
@@ -0,0 +1,14 @@
package appeng.mixins;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.texture.Sprite;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(BakedQuad.class)
public interface BakedQuadAccessor {
@Accessor
Sprite getSprite();
}
@@ -0,0 +1,15 @@
package appeng.mixins;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ItemRenderer.class)
public interface ItemRendererAccessor {
@Invoker
void callRenderGuiItemModel(ItemStack stack, int x, int y, BakedModel model);
}
@@ -0,0 +1,26 @@
package appeng.mixins;
import appeng.hooks.ItemRendererHooks;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* This mixin specifically targets rendering of items in the user interface to allow us to
* customize _only_ the UI representation of an item, and none of the others (held items, in-world, etc.)
*/
@Mixin(ItemRenderer.class)
public abstract class RenderEncodedPatternMixin {
@Inject(method = "renderGuiItemModel", at = @At("HEAD"), cancellable = true)
protected void renderGuiItemModel(ItemStack stack, int x, int y, BakedModel model, CallbackInfo ci) {
if (ItemRendererHooks.onRenderGuiItemModel((ItemRenderer) (Object) this, stack, x, y, model)) {
ci.cancel();
}
}
}
@@ -19,6 +19,9 @@
package appeng.tile.inventory;
import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
import alexiil.mc.lib.attributes.item.compat.FixedInventoryVanillaWrapper;
import alexiil.mc.lib.attributes.item.filter.ConstantItemFilter;
import alexiil.mc.lib.attributes.item.filter.ItemFilter;
import alexiil.mc.lib.attributes.item.impl.DirectFixedItemInv;
@@ -61,6 +64,29 @@ public class AppEngInternalInventory extends DirectFixedItemInv implements Itera
this.filter = filter;
}
public FixedItemInv createFiltered(IAEItemFilter filter) {
LimitedFixedItemInv limitedFixedInv = this.createLimitedFixedInv();
for (int i = 0; i < getSlotCount(); i++) {
final int slot = i;
limitedFixedInv.getRule(i)
.filterExtracts(stack -> filter.allowExtract(this, slot, stack.getCount()));
limitedFixedInv.getRule(i)
.filterInserts(stack -> {
if (stack.isEmpty()) {
ItemStack current = this.getInvStack(slot);
if (current.isEmpty()) {
return true; // Replacing empty with empty... okay
}
return filter.allowExtract(this, slot, current.getCount());
} else {
return filter.allowInsert(this, slot, stack);
}
});
}
return limitedFixedInv;
}
@Override
public int getMaxAmount(int slot, ItemStack stack) {
return Math.min(maxStack[slot], super.getMaxAmount(slot, stack));
@@ -61,7 +61,9 @@ public class ChargerBlockEntity extends AENetworkPowerBlockEntity implements ICr
private static final int POWER_THRESHOLD = POWER_MAXIMUM_AMOUNT - 1;
private static final int POWER_PER_CRANK_TURN = 160;
private final AppEngInternalInventory inv = new AppEngInternalInventory(this, 1, 1, new ChargerInvFilter());
private final AppEngInternalInventory inv = new AppEngInternalInventory(this, 1, 1);
private final FixedItemInv externalInv = inv.createFiltered(new ChargerInvFilter());
public ChargerBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
@@ -134,7 +136,7 @@ public class ChargerBlockEntity extends AENetworkPowerBlockEntity implements ICr
@Override
public FixedItemInv getInternalInventory() {
return this.inv;
return externalInv;
}
@Override
@@ -18,6 +18,7 @@
package appeng.tile.misc;
import appeng.client.render.model.AEModelData;
import net.minecraft.block.entity.BlockEntityType;
import appeng.tile.AEBaseBlockEntity;
@@ -28,4 +29,9 @@ public class SkyCompassBlockEntity extends AEBaseBlockEntity {
super(tileEntityTypeIn);
}
@Override
public Object getRenderAttachmentData() {
// For compasses, the forward/up are flipped
return new AEModelData(getForward(), getUp());
}
}
@@ -39,7 +39,7 @@ import net.minecraft.util.math.Direction;
*/
public abstract class InventoryAdaptor implements Iterable<ItemSlot> {
public static InventoryAdaptor getAdaptor(final BlockEntity te, final Direction d) {
FixedItemInv inv = ItemAttributes.FIXED_INV.get(te.getWorld(), te.getPos().offset(d), SearchOptions.inDirection(d.getOpposite()));
FixedItemInv inv = ItemAttributes.FIXED_INV.get(te.getWorld(), te.getPos(), SearchOptions.inDirection(d.getOpposite()));
if (inv == ItemAttributes.FIXED_INV.defaultValue) {
return null;
@@ -17,7 +17,9 @@
"client": [
"ModelsReloadMixin",
"RenderPhaseMixin",
"BakedModelManagerAccessor"
"BakedModelManagerAccessor",
"RenderEncodedPatternMixin",
"ItemRendererAccessor"
],
"server": [],
"injectors": {
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "storage_16k"
}
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "storage_1k"
}
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "storage_4k"
}
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "storage_64k"
}
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "accelerator"
}
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "monitor"
}
@@ -1,4 +0,0 @@
{
"loader": "appliedenergistics2:crafting_cube",
"type": "unit"
}
@@ -1,3 +0,0 @@
{
"loader": "appliedenergistics2:paint_splotches"
}
@@ -1,3 +0,0 @@
{
"loader": "appliedenergistics2:quantum_bridge_formed"
}
@@ -1,3 +0,0 @@
{
"loader": "appliedenergistics2:glass"
}
@@ -1,3 +0,0 @@
{
"loader": "appliedenergistics2:biometric_card"
}
@@ -1,4 +1,6 @@
{
"loader": "appliedenergistics2:encoded_pattern",
"baseModel": "appliedenergistics2:item/encoded_pattern_base"
"parent": "item/generated",
"textures": {
"layer0": "appliedenergistics2:item/encoded_pattern"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "appliedenergistics2:item/encoded_pattern"
}
}
@@ -1,3 +0,0 @@
{
"loader": "appliedenergistics2:memory_card"
}
@@ -1,3 +1,2 @@
{
"parent": "appliedenergistics2:block/paint"
}
@@ -1,41 +0,0 @@
package appeng.block.qnb;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.core.AppEng;
public class QnbFormedModel implements IModelGeometry<QnbFormedModel> {
private static final Identifier MODEL_RING = new Identifier(AppEng.MOD_ID, "block/qnb/ring");
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform modelTransform,
ModelOverrideList overrides, Identifier modelLocation) {
BakedModel ringModel = bakery.getBakedModel(MODEL_RING, modelTransform, spriteGetter);
return new QnbFormedBakedModel(ringModel, spriteGetter);
}
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return QnbFormedBakedModel.getRequiredTextures();
}
}
@@ -42,7 +42,7 @@ import appeng.core.AppEng;
* The model class for facades. Since facades wrap existing models, they don't
* declare any dependencies here other than the cable anchor.
*/
public class DummyFluidItemModel implements IModelGeometry<DummyFluidItemModel> {
public class DummyFluidItemModel implements BasicUnbakedModel {
// We use this to get the default item transforms and make our lives easier
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID,
"item/dummy_fluid_item_base");
@@ -39,7 +39,7 @@ import appeng.core.AppEng;
* The model class for facades. Since facades wrap existing models, they don't
* declare any dependencies here other than the cable anchor.
*/
public class FacadeItemModel implements IModelGeometry<FacadeItemModel> {
public class FacadeItemModel implements BasicUnbakedModel {
// We use this to get the default item transforms and make our lives easier
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/facade_base");
@@ -21,7 +21,7 @@ import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.core.AppEng;
public class P2PTunnelFrequencyModel implements IModelGeometry<P2PTunnelFrequencyModel> {
public class P2PTunnelFrequencyModel implements BasicUnbakedModel {
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "parts/p2p_tunnel_frequency"));
@@ -1,61 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.render.crafting;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import net.minecraft.resources.IResourceManager;
import net.minecraftforge.client.model.IModelLoader;
import appeng.block.crafting.AbstractCraftingUnitBlock;
/**
* Loader that allows access to the built-in crafting cube model from
* block-model JSONs.
*/
public class CraftingCubeModelLoader implements IModelLoader<CraftingCubeModel> {
public static final CraftingCubeModelLoader INSTANCE = new CraftingCubeModelLoader();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
}
@Override
public CraftingCubeModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
AbstractCraftingUnitBlock.CraftingUnitType unitType = null;
JsonElement typeEl = modelContents.get("type");
if (typeEl != null) {
String typeName = deserializationContext.deserialize(typeEl, String.class);
if (typeName != null) {
unitType = AbstractCraftingUnitBlock.CraftingUnitType.valueOf(typeName.toUpperCase());
}
}
if (unitType == null) {
throw new JsonParseException("type property is missing");
}
return new CraftingCubeModel(unitType);
}
}
@@ -1,134 +0,0 @@
package appeng.client.render.crafting;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.AffineTransformation;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.client.model.PerspectiveMapWrapper;
import appeng.client.render.DelegateBakedModel;
import appeng.items.misc.EncodedPatternItem;
/**
* This model is used to substitute the crafting result's item model for our
* encoded pattern model if these two conditions are met: - The player is
* holding shift - The itemstack is being rendered in the UI (not on the ground,
* etc.)
*
* We do this by abusing a custom {@link ModelOverrideList} since it will be
* called each frame with the itemstack that is about to be rendered. We return
* a custom IBakedModel ({@link ShiftHoldingModelWrapper} if the player is
* holding down shift from the override list. This custom baked model implements
* {@link #doesHandlePerspectives()} and returns the crafting result model if
* the model for {@link ModelTransformation.Mode#GUI} is requested.
*/
public class EncodedPatternBakedModel extends DelegateBakedModel {
private final CustomOverrideList overrides;
EncodedPatternBakedModel(BakedModel baseModel) {
super(baseModel);
this.overrides = new CustomOverrideList();
}
@Override
public ModelOverrideList getOverrides() {
return this.overrides;
}
/**
* Since the ItemOverrideList handling comes before handling the perspective
* awareness (which is the first place where we know how we are being rendered)
* we need to remember the model of the crafting output, and make the decision
* on which to render later on. Sadly, Forge is pretty inconsistent when it will
* call the handlePerspective method, so some methods are called even on this
* interim-model. Usually those methods only matter for rendering on the ground
* and other cases, where we wouldn't render the crafting output model anyway,
* so in those cases we delegate to the model of the encoded pattern.
*/
private static class ShiftHoldingModelWrapper extends DelegateBakedModel {
private final BakedModel outputModel;
private ShiftHoldingModelWrapper(BakedModel patternModel, BakedModel outputModel) {
super(patternModel);
this.outputModel = outputModel;
}
@Override
public boolean doesHandlePerspectives() {
return true;
}
@Override
public BakedModel handlePerspective(ModelTransformation.Mode cameraTransformType, MatrixStack mat) {
// No need to re-check for shift being held since this model is only handed out
// in that case
if (cameraTransformType == ModelTransformation.Mode.GUI) {
ImmutableMap<ModelTransformation.Mode, AffineTransformation> transforms = PerspectiveMapWrapper
.getTransforms(outputModel.getTransformation());
return PerspectiveMapWrapper.handlePerspective(this.outputModel, transforms, cameraTransformType, mat);
} else {
return getBaseModel().handlePerspective(cameraTransformType, mat);
}
}
// This determines diffuse lighting in the UI, and since we want to render
// the outputModel in the UI, we need to use it's setting here
@Override
public boolean isSideLit() {
return outputModel.isSideLit();
}
}
@Override
public boolean doesHandlePerspectives() {
return true;
}
@Override
public BakedModel handlePerspective(ModelTransformation.Mode cameraTransformType, MatrixStack mat) {
return getBaseModel().handlePerspective(cameraTransformType, mat);
}
/**
* Item Override Lists are the only point during item rendering where we can
* access the item stack that is being rendered. So this is the point where we
* actually check if shift is being held, and if so, determine the crafting
* output model.
*/
private class CustomOverrideList extends ModelOverrideList {
@Nullable
@Override
public BakedModel getModelWithOverrides(BakedModel originalModel, ItemStack stack, @Nullable World world,
@Nullable LivingEntity entity) {
boolean shiftHeld = Screen.hasShiftDown();
if (shiftHeld && world != null) {
EncodedPatternItem iep = (EncodedPatternItem) stack.getItem();
ItemStack output = iep.getOutput(world, stack);
if (!output.isEmpty()) {
BakedModel realModel = MinecraftClient.getInstance().getItemRenderer().getItemModelMesher()
.getItemModel(output);
// Give the item model a chance to handle the overrides as well
realModel = realModel.getOverrides().getModelWithOverrides(realModel, output, world, entity);
return new ShiftHoldingModelWrapper(getBaseModel(), realModel);
}
}
return getBaseModel().getOverrides().getModelWithOverrides(originalModel, stack, world, entity);
}
}
}
@@ -1,45 +0,0 @@
package appeng.client.render.crafting;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
/**
* This model is used to provide the {@link EncodedPatternBakedModel}.
*/
public class EncodedPatternModel implements IModelGeometry<EncodedPatternModel> {
private final Identifier baseModel;
public EncodedPatternModel(Identifier baseModel) {
this.baseModel = baseModel;
}
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return modelGetter.apply(baseModel).getTextures(modelGetter, missingTextureErrors);
}
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform modelTransform,
ModelOverrideList overrides, Identifier modelLocation) {
BakedModel baseModel = bakery.getBakedModel(this.baseModel, modelTransform, spriteGetter);
return new EncodedPatternBakedModel(baseModel);
}
}
@@ -1,30 +0,0 @@
package appeng.client.render.crafting;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraftforge.client.model.IModelLoader;
/**
* Provides our custom {@link EncodedPatternBakedModel encoded pattern item
* model}.
*/
public class EncodedPatternModelLoader implements IModelLoader<EncodedPatternModel> {
public static final EncodedPatternModelLoader INSTANCE = new EncodedPatternModelLoader();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
}
@Override
public EncodedPatternModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
modelContents.remove("loader"); // Avoid recursion
Identifier baseModel = new Identifier(JsonHelper.getString(modelContents, "baseModel"));
return new EncodedPatternModel(baseModel);
}
}
@@ -1,189 +0,0 @@
package appeng.client.render.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.texture.Sprite;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import net.minecraftforge.client.model.data.EmptyModelData;
import appeng.api.implementations.items.IBiometricCard;
import appeng.api.util.AEColor;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.core.AELog;
class BiometricCardBakedModel implements BakedModel {
private final BakedModel baseModel;
private final Sprite texture;
private final int hash;
private final Cache<Integer, BiometricCardBakedModel> modelCache;
private final ImmutableList<BakedQuad> generalQuads;
BiometricCardBakedModel(BakedModel baseModel, Sprite texture) {
this(baseModel, texture, 0, createCache());
}
private BiometricCardBakedModel(BakedModel baseModel, Sprite texture, int hash,
Cache<Integer, BiometricCardBakedModel> modelCache) {
this.baseModel = baseModel;
this.texture = texture;
this.hash = hash;
this.generalQuads = ImmutableList.copyOf(this.buildGeneralQuads());
this.modelCache = modelCache;
}
private static Cache<Integer, BiometricCardBakedModel> createCache() {
return CacheBuilder.newBuilder().maximumSize(100).build();
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
List<BakedQuad> quads = this.baseModel.getQuads(state, side, rand, EmptyModelData.INSTANCE);
if (side != null) {
return quads;
}
List<BakedQuad> result = new ArrayList<>(quads.size() + this.generalQuads.size());
result.addAll(quads);
result.addAll(this.generalQuads);
return result;
}
private List<BakedQuad> buildGeneralQuads() {
CubeBuilder builder = new CubeBuilder();
builder.setTexture(this.texture);
AEColor col = AEColor.values()[Math.abs(3 + this.hash) % AEColor.values().length];
if (this.hash == 0) {
col = AEColor.BLACK;
}
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 6; y++) {
final boolean isLit;
// This makes the border always use the darker color
if (x == 0 || y == 0 || x == 7 || y == 5) {
isLit = false;
} else {
isLit = (this.hash & (1 << x)) != 0 || (this.hash & (1 << y)) != 0;
}
if (isLit) {
builder.setColorRGB(col.mediumVariant);
} else {
final float scale = 0.3f / 255.0f;
builder.setColorRGB(((col.blackVariant >> 16) & 0xff) * scale,
((col.blackVariant >> 8) & 0xff) * scale, (col.blackVariant & 0xff) * scale);
}
builder.addCube(4 + x, 6 + y, 7.5f, 4 + x + 1, 6 + y + 1, 8.5f);
}
}
return builder.getOutput();
}
@Override
public boolean useAmbientOcclusion() {
return this.baseModel.useAmbientOcclusion();
}
@Override
public boolean hasDepth() {
return this.baseModel.hasDepth();
}
@Override
public boolean isSideLit() {
return false;// TODO
}
@Override
public boolean isBuiltin() {
return this.baseModel.isBuiltin();
}
@Override
public Sprite getSprite() {
return this.baseModel.getSprite();
}
@Override
public ModelTransformation getTransformation() {
return this.baseModel.getTransformation();
}
@Override
public ModelOverrideList getOverrides() {
return new ModelOverrideList() {
@Override
public BakedModel getModelWithOverrides(BakedModel originalModel, ItemStack stack, World world,
LivingEntity entity) {
String username = "";
if (stack.getItem() instanceof IBiometricCard) {
final GameProfile gp = ((IBiometricCard) stack.getItem()).getProfile(stack);
if (gp != null) {
if (gp.getId() != null) {
username = gp.getId().toString();
} else {
username = gp.getName();
}
}
}
final int hash = !username.isEmpty() ? username.hashCode() : 0;
// Get hash
if (hash == 0) {
return BiometricCardBakedModel.this;
}
try {
return BiometricCardBakedModel.this.modelCache.get(hash,
() -> new BiometricCardBakedModel(BiometricCardBakedModel.this.baseModel,
BiometricCardBakedModel.this.texture, hash,
BiometricCardBakedModel.this.modelCache));
} catch (ExecutionException e) {
AELog.error(e);
return BiometricCardBakedModel.this;
}
}
};
}
@Override
public boolean doesHandlePerspectives() {
return true;
}
@Override
public BakedModel handlePerspective(ModelTransformation.Mode cameraTransformType, MatrixStack mat) {
baseModel.handlePerspective(cameraTransformType, mat);
return this;
}
}
@@ -1,54 +0,0 @@
package appeng.client.render.model;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.core.AppEng;
/**
* Model wrapper for the biometric card item model, which combines a base card
* layer with a "visual hash" of the player name
*/
public class BiometricCardModel implements IModelGeometry<BiometricCardModel> {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/biometric_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/biometric_card_hash"));
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return Collections.singleton(TEXTURE);
}
@Nullable
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform transformIn,
ModelOverrideList overrides, Identifier locationIn) {
Sprite texture = spriteGetter.apply(TEXTURE);
BakedModel baseModel = bakery.getBakedModel(MODEL_BASE, transformIn, spriteGetter);
return new BiometricCardBakedModel(baseModel, texture);
}
}
@@ -1,119 +0,0 @@
package appeng.client.render.model;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Random;
import javax.annotation.Nullable;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.util.math.Direction;
import net.minecraftforge.client.model.PerspectiveMapWrapper;
import net.minecraftforge.client.model.data.EmptyModelData;
class ColorApplicatorBakedModel implements BakedModel {
private final BakedModel baseModel;
private final IModelTransform transforms;
private final EnumMap<Direction, List<BakedQuad>> quadsBySide;
private final List<BakedQuad> generalQuads;
ColorApplicatorBakedModel(BakedModel baseModel, IModelTransform transforms, Sprite texDark,
Sprite texMedium, Sprite texBright) {
this.baseModel = baseModel;
this.transforms = transforms;
// Put the tint indices in... Since this is an item model, we are ignoring rand
this.generalQuads = this.fixQuadTint(null, texDark, texMedium, texBright);
this.quadsBySide = new EnumMap<>(Direction.class);
for (Direction facing : Direction.values()) {
this.quadsBySide.put(facing, this.fixQuadTint(facing, texDark, texMedium, texBright));
}
}
private List<BakedQuad> fixQuadTint(Direction facing, Sprite texDark, Sprite texMedium,
Sprite texBright) {
List<BakedQuad> quads = this.baseModel.getQuads(null, facing, new Random(0), EmptyModelData.INSTANCE);
List<BakedQuad> result = new ArrayList<>(quads.size());
for (BakedQuad quad : quads) {
int tint;
if (quad.func_187508_a() == texDark) {
tint = 1;
} else if (quad.func_187508_a() == texMedium) {
tint = 2;
} else if (quad.func_187508_a() == texBright) {
tint = 3;
} else {
result.add(quad);
continue;
}
BakedQuad newQuad = new BakedQuad(quad.getVertexData(), tint, quad.getFace(), quad.func_187508_a(),
quad.shouldApplyDiffuseLighting());
result.add(newQuad);
}
return result;
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
if (side == null) {
return this.generalQuads;
}
return this.quadsBySide.get(side);
}
@Override
public boolean useAmbientOcclusion() {
return this.baseModel.useAmbientOcclusion();
}
@Override
public boolean hasDepth() {
return this.baseModel.hasDepth();
}
@Override
public boolean isSideLit() {
return false;// TODO
}
@Override
public boolean isBuiltin() {
return this.baseModel.isBuiltin();
}
@Override
public Sprite getSprite() {
return this.baseModel.getSprite();
}
@Override
public ModelTransformation getTransformation() {
return this.baseModel.getTransformation();
}
@Override
public ModelOverrideList getOverrides() {
return this.baseModel.getOverrides();
}
@Override
public BakedModel handlePerspective(ModelTransformation.Mode cameraTransformType, MatrixStack mat) {
return PerspectiveMapWrapper.handlePerspective(this, transforms, cameraTransformType, mat);
}
}
@@ -1,58 +0,0 @@
package appeng.client.render.model;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.core.AppEng;
/**
* A color applicator uses the base model, and extends it with additional layers
* that are colored according to the selected color of the applicator.
*/
public class ColorApplicatorModel implements IModelGeometry<ColorApplicatorModel> {
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID,
"item/color_applicator_colored");
private static final SpriteIdentifier TEXTURE_DARK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_dark"));
private static final SpriteIdentifier TEXTURE_MEDIUM = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_medium"));
private static final SpriteIdentifier TEXTURE_BRIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_bright"));
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return Arrays.asList(TEXTURE_DARK, TEXTURE_MEDIUM, TEXTURE_DARK);
}
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform modelTransform,
ModelOverrideList overrides, Identifier modelLocation) {
BakedModel baseModel = bakery.getBakedModel(MODEL_BASE, modelTransform, spriteGetter);
Sprite texDark = spriteGetter.apply(TEXTURE_DARK);
Sprite texMedium = spriteGetter.apply(TEXTURE_MEDIUM);
Sprite texBright = spriteGetter.apply(TEXTURE_BRIGHT);
return new ColorApplicatorBakedModel(baseModel, modelTransform, texDark, texMedium, texBright);
}
}
@@ -1,188 +0,0 @@
package appeng.client.render.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import net.minecraftforge.client.model.data.EmptyModelData;
import appeng.api.implementations.items.IMemoryCard;
import appeng.api.util.AEColor;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.core.AELog;
class MemoryCardBakedModel implements BakedModel {
private static final AEColor[] DEFAULT_COLOR_CODE = new AEColor[] { AEColor.TRANSPARENT, AEColor.TRANSPARENT,
AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT,
AEColor.TRANSPARENT, };
private final BakedModel baseModel;
private final Sprite texture;
private final AEColor[] colorCode;
private final Cache<CacheKey, MemoryCardBakedModel> modelCache;
private final ImmutableList<BakedQuad> generalQuads;
MemoryCardBakedModel(BakedModel baseModel, Sprite texture) {
this(baseModel, texture, DEFAULT_COLOR_CODE, createCache());
}
private MemoryCardBakedModel(BakedModel baseModel, Sprite texture, AEColor[] hash,
Cache<CacheKey, MemoryCardBakedModel> modelCache) {
this.baseModel = baseModel;
this.texture = texture;
this.colorCode = hash;
this.generalQuads = ImmutableList.copyOf(this.buildGeneralQuads());
this.modelCache = modelCache;
}
private static Cache<CacheKey, MemoryCardBakedModel> createCache() {
return CacheBuilder.newBuilder().maximumSize(100).build();
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
List<BakedQuad> quads = this.baseModel.getQuads(state, side, rand, EmptyModelData.INSTANCE);
if (side != null) {
return quads;
}
List<BakedQuad> result = new ArrayList<>(quads.size() + this.generalQuads.size());
result.addAll(quads);
result.addAll(this.generalQuads);
return result;
}
private List<BakedQuad> buildGeneralQuads() {
CubeBuilder builder = new CubeBuilder();
builder.setTexture(this.texture);
for (int x = 0; x < 4; x++) {
for (int y = 0; y < 2; y++) {
final AEColor color = this.colorCode[x + y * 4];
builder.setColorRGB(color.mediumVariant);
builder.addCube(7 + x, 8 + (1 - y), 7.5f, 7 + x + 1, 8 + (1 - y) + 1, 8.5f);
}
}
return builder.getOutput();
}
@Override
public boolean useAmbientOcclusion() {
return this.baseModel.useAmbientOcclusion();
}
@Override
public boolean hasDepth() {
return this.baseModel.hasDepth();
}
@Override
public boolean isSideLit() {
return false;// TODO
}
@Override
public boolean isBuiltin() {
return this.baseModel.isBuiltin();
}
@Override
public Sprite getSprite() {
return this.baseModel.getSprite();
}
@Override
public ModelTransformation getTransformation() {
return this.baseModel.getTransformation();
}
@Override
public ModelOverrideList getOverrides() {
return new ModelOverrideList() {
@Override
public BakedModel getModelWithOverrides(BakedModel originalModel, ItemStack stack, World world,
LivingEntity entity) {
try {
if (stack.getItem() instanceof IMemoryCard) {
final IMemoryCard memoryCard = (IMemoryCard) stack.getItem();
final AEColor[] colors = memoryCard.getColorCode(stack);
return MemoryCardBakedModel.this.modelCache.get(new CacheKey(colors),
() -> new MemoryCardBakedModel(MemoryCardBakedModel.this.baseModel,
MemoryCardBakedModel.this.texture, colors,
MemoryCardBakedModel.this.modelCache));
}
} catch (ExecutionException e) {
AELog.error(e);
}
return MemoryCardBakedModel.this;
}
};
}
@Override
public BakedModel handlePerspective(ModelTransformation.Mode cameraTransformType, MatrixStack mat) {
baseModel.handlePerspective(cameraTransformType, mat);
return this;
}
private static class CacheKey {
private final AEColor[] key;
CacheKey(AEColor[] key) {
this.key = key;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(this.key);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
CacheKey other = (CacheKey) obj;
return Arrays.equals(this.key, other.key);
}
}
}
@@ -1,54 +0,0 @@
package appeng.client.render.model;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.IModelTransform;
import net.minecraft.client.render.model.IUnbakedModel;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.core.AppEng;
/**
* Model wrapper for the memory card item model, which combines a base card
* layer with a "visual hash" of the part/tile.
*/
public class MemoryCardModel implements IModelGeometry<MemoryCardModel> {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/memory_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "item/memory_card_hash"));
@Override
public Collection<SpriteIdentifier> getTextures(IModelConfiguration owner,
Function<Identifier, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return Collections.singleton(TEXTURE);
}
@Nullable
@Override
public BakedModel bake(IModelConfiguration owner, ModelLoader bakery,
Function<SpriteIdentifier, Sprite> spriteGetter, IModelTransform modelTransform,
ModelOverrideList overrides, Identifier modelLocation) {
Sprite texture = spriteGetter.apply(TEXTURE);
BakedModel baseModel = bakery.getBakedModel(MODEL_BASE, modelTransform, spriteGetter);
return new MemoryCardBakedModel(baseModel, texture);
}
}
@@ -134,7 +134,7 @@ public class UVLModelLoader implements IModelLoader<UVLModelLoader.UVLModelWrapp
}
}
public static class UVLModelWrapper implements IModelGeometry<UVLModelWrapper> {
public static class UVLModelWrapper implements BasicUnbakedModel {
private final BlockModel parent;
public UVLModelWrapper(BlockModel parent) {
@@ -40,7 +40,7 @@ import net.minecraftforge.client.model.geometry.IModelGeometry;
/**
* Built-in model for annihilation planes that supports connected textures.
*/
public class PlaneModel implements IModelGeometry<PlaneModel> {
public class PlaneModel implements BasicUnbakedModel {
private final SpriteIdentifier frontTexture;
private final SpriteIdentifier sidesTexture;