WIP Framned stuff

This commit is contained in:
Buuz135 2022-07-02 14:21:23 +02:00
parent 622749b0cc
commit 8ea488059a
8 changed files with 1004 additions and 0 deletions

View File

@ -0,0 +1,20 @@
package com.buuz135.functionalstorage.block;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.buuz135.functionalstorage.block.tile.DrawerTile;
import com.buuz135.functionalstorage.util.DrawerWoodType;
import com.buuz135.functionalstorage.util.IWoodType;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.apache.commons.lang3.tuple.Pair;
public class FramedDrawerBlock extends DrawerBlock{
public FramedDrawerBlock(FunctionalStorage.DrawerType type) {
super(DrawerWoodType.FRAMED, type);
}
@Override
public BlockEntityType.BlockEntitySupplier<DrawerTile> getTileEntityFactory() {
return (blockPos, state) -> new DrawerTile(this, (BlockEntityType<DrawerTile>) FunctionalStorage.DRAWER_TYPES.get(this.getType()).stream().filter(registryObjectRegistryObjectPair -> registryObjectRegistryObjectPair.getLeft().get().equals(this)).map(Pair::getRight).findFirst().get().get(), blockPos, state, this.getType());
}
}

View File

@ -0,0 +1,14 @@
package com.buuz135.functionalstorage.block.tile;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.hrznstudio.titanium.block.BasicTileBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class FramedDrawerTile extends DrawerTile{
public FramedDrawerTile(BasicTileBlock<DrawerTile> base, BlockEntityType<DrawerTile> blockEntityType, BlockPos pos, BlockState state, FunctionalStorage.DrawerType type) {
super(base, blockEntityType, pos, state, type);
}
}

View File

@ -0,0 +1,267 @@
package com.buuz135.functionalstorage.client.loader;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/model/RetexturedModel.java}
*
* Model that dynamically retextures a list of textures based on data from {@link RetexturedHelper}.
*/
@SuppressWarnings("WeakerAccess")
public class RetexturedModel implements IModelGeometry<RetexturedModel> {
private final SimpleBlockModel model;
private final Set<String> retextured;
@Override
public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation,UnbakedModel> modelGetter, Set<Pair<String,String>> missingTextureErrors) {
return model.getTextures(owner, modelGetter, missingTextureErrors);
}
@Override
public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material,TextureAtlasSprite> spriteGetter, ModelState transform, ItemOverrides overrides, ResourceLocation location) {
// bake the model and return
BakedModel baked = model.bakeModel(owner, transform, overrides, spriteGetter, location);
return new Baked(baked, owner, model, transform, getAllRetextured(owner, this.model, retextured));
}
/**
* Gets a list of all names to retexture based on the block model texture references
* @param owner Model config instance
* @param model Model fallback
* @param originalSet Original list of names to retexture
* @return Set of textures including parent textures
*/
public static Set<String> getAllRetextured(IModelConfiguration owner, SimpleBlockModel model, Set<String> originalSet) {
Set<String> retextured = Sets.newHashSet(originalSet);
for (Map<String,Either<Material, String>> textures : ModelTextureIteratable.of(owner, model)) {
textures.forEach((name, either) ->
either.ifRight(parent -> {
if (retextured.contains(parent)) {
retextured.add(name);
}
})
);
}
return ImmutableSet.copyOf(retextured);
}
/** Registered model loader instance registered */
public static class Loader implements IModelLoader<RetexturedModel> {
public static final Loader INSTANCE = new Loader();
private Loader() {}
@Override
public void onResourceManagerReload(ResourceManager resourceManager) {}
@Override
public RetexturedModel read(JsonDeserializationContext context, JsonObject json) {
// get base model
SimpleBlockModel model = SimpleBlockModel.deserialize(context, json);
// get list of textures to retexture
Set<String> retextured = getRetextured(json);
// return retextured model
return new RetexturedModel(model, retextured);
}
/**
* Gets the list of retextured textures from the model
* @param json Model json
* @return List of textures
*/
public static Set<String> getRetextured(JsonObject json) {
if (json.has("retextured")) {
// if an array, set from each texture in array
JsonElement retextured = json.get("retextured");
if (retextured.isJsonArray()) {
JsonArray array = retextured.getAsJsonArray();
if (array.size() == 0) {
throw new JsonSyntaxException("Must have at least one texture in retextured");
}
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
for (int i = 0; i < array.size(); i++) {
builder.add(GsonHelper.convertToString(array.get(i), "retextured[" + i + "]"));
}
return builder.build();
}
// if string, single texture
if (retextured.isJsonPrimitive()) {
return ImmutableSet.of(retextured.getAsString());
}
}
// if neither or missing, error
throw new JsonSyntaxException("Missing retextured, expected to find a String or a JsonArray");
}
}
/** Baked variant of the model, used to swap out quads based on the texture */
public static class Baked extends DynamicBakedWrapper<BakedModel> {
/** Cache of texture name to baked model */
private final Map<ResourceLocation,BakedModel> cache = new ConcurrentHashMap<>();
/* Properties for rebaking */
private final IModelConfiguration owner;
private final SimpleBlockModel model;
private final ModelState transform;
/** List of texture names that are retextured */
private final Set<String> retextured;
public Baked(BakedModel baked, IModelConfiguration owner, SimpleBlockModel model, ModelState transform, Set<String> retextured) {
super(baked);
this.model = model;
this.owner = owner;
this.transform = transform;
this.retextured = retextured;
}
/**
* Gets the model with the given texture applied
* @param name Texture location
* @return Retextured model
*/
private BakedModel getRetexturedModel(ResourceLocation name) {
return model.bakeDynamic(new RetexturedConfiguration(owner, retextured, name), transform);
}
/**
* Gets a cached retextured model, computing it if missing from the cache
* @param block Block determining the texture
* @return Retextured model
*/
private BakedModel getCachedModel(Block block) {
return cache.computeIfAbsent(ModelHelper.getParticleTexture(block), this::getRetexturedModel);
}
@Override
public TextureAtlasSprite getParticleIcon(IModelData data) {
// if particle is retextured, fetch particle from the cached model
if (retextured.contains("particle")) {
Block block = data.getData(RetexturedHelper.BLOCK_PROPERTY);
if (block != null) {
return getCachedModel(block).getParticleIcon(data);
}
}
return originalModel.getParticleIcon(data);
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction direction, Random random, IModelData data) {
Block block = data.getData(RetexturedHelper.BLOCK_PROPERTY);
if (block == null) {
return originalModel.getQuads(state, direction, random, data);
}
return getCachedModel(block).getQuads(state, direction, random, data);
}
@Override
public ItemOverrides getOverrides() {
return RetexturedOverride.INSTANCE;
}
}
/**
* Model configuration wrapper to retexture the block
*/
public static class RetexturedConfiguration extends ModelConfigurationWrapper {
/** List of textures to retexture */
private final Set<String> retextured;
/** Replacement texture */
private final Material texture;
/**
* Creates a new configuration wrapper
* @param base Original model configuration
* @param retextured Set of textures that should be retextured
* @param texture New texture to replace those in the set
*/
public RetexturedConfiguration(IModelConfiguration base, Set<String> retextured, ResourceLocation texture) {
super(base);
this.retextured = retextured;
this.texture = ModelLoaderRegistry.blockMaterial(texture);
}
@Override
public boolean isTexturePresent(String name) {
if (retextured.contains(name)) {
return !MissingTextureAtlasSprite.getLocation().equals(texture.texture());
}
return super.isTexturePresent(name);
}
@Override
public Material resolveTexture(String name) {
if (retextured.contains(name)) {
return texture;
}
return super.resolveTexture(name);
}
}
/** Override list to swap the texture in from NBT */
private static class RetexturedOverride extends ItemOverrides {
private static final RetexturedOverride INSTANCE = new RetexturedOverride();
@Nullable
@Override
public BakedModel resolve(BakedModel originalModel, ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int pSeed) {
if (stack.isEmpty() || !stack.hasTag()) {
return originalModel;
}
// get the block first, ensuring its valid
Block block = RetexturedBlockItem.getTexture(stack);
if (block == Blocks.AIR) {
return originalModel;
}
// if valid, use the block
return ((Baked)originalModel).getCachedModel(block);
}
}
}

View File

@ -0,0 +1,412 @@
package com.buuz135.functionalstorage.client.loader;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockElementFace;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraftforge.client.model.ForgeModelBakery;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Simplier version of {@link BlockModel} for use in an {@link net.minecraftforge.client.model.IModelLoader}, as the owner handles most block model properties
*/
@SuppressWarnings("WeakerAccess")
public class SimpleBlockModel implements IModelGeometry<SimpleBlockModel> {
/**
* Model loader for vanilla block model, mainly intended for use in fallback registration
*/
public static final Loader LOADER = new Loader();
/**
* Location used for baking dynamic models, name does not matter so just using a constant
*/
private static final ResourceLocation BAKE_LOCATION = new ResourceLocation(FunctionalStorage.MOD_ID, "dynamic_model_baking");
/**
* Parent model location, used to fetch parts and for textures if the owner is not a block model
*/
@Nullable
private ResourceLocation parentLocation;
/**
* Model parts for baked model, if empty uses parent parts
*/
private final List<BlockElement> parts;
/**
* Fallback textures in case the owner does not contain a block model
*/
private final Map<String, Either<Material, String>> textures;
private BlockModel parent;
/**
* Creates a new simple block model
*
* @param parentLocation Location of the parent model, if unset has no parent
* @param textures List of textures for iteration, in case the owner is not BlockModel
* @param parts List of parts in the model
*/
public SimpleBlockModel(@Nullable ResourceLocation parentLocation, Map<String, Either<Material, String>> textures, List<BlockElement> parts) {
this.parts = parts;
this.textures = textures;
this.parentLocation = parentLocation;
}
/* Properties */
/**
* Gets the elements in this simple block model
*
* @return Elements in the model
*/
@SuppressWarnings("deprecation")
public List<BlockElement> getElements() {
return parts.isEmpty() && parent != null ? parent.getElements() : parts;
}
/* Textures */
/**
* Fetches parent models for this model and its parents
*
* @param modelGetter Model getter function
*/
public void fetchParent(IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter) {
// no work if no parent or the parent is fetched already
if (parent != null || parentLocation == null) {
return;
}
// iterate through model parents
Set<UnbakedModel> chain = Sets.newLinkedHashSet();
// load the first model directly
parent = getParent(modelGetter, chain, parentLocation, owner.getModelName());
// null means no model, so set missing
if (parent == null) {
parent = getMissing(modelGetter);
parentLocation = ModelBakery.MISSING_MODEL_LOCATION;
}
// loop through each parent, adding in parents
for (BlockModel link = parent; link.parentLocation != null && link.parent == null; link = link.parent) {
chain.add(link);
// fetch model parent
link.parent = getParent(modelGetter, chain, link.parentLocation, link.name);
// null means no model, so set missing
if (link.parent == null) {
link.parent = getMissing(modelGetter);
link.parentLocation = ModelBakery.MISSING_MODEL_LOCATION;
}
}
}
/**
* Gets the parent for a model
*
* @param modelGetter Model getter function
* @param chain Chain of models that are in progress
* @param location Location to fetch
* @param name Name of the model being fetched
* @return Block model instance, null if there was an error
*/
@Nullable
private static BlockModel getParent(Function<ResourceLocation, UnbakedModel> modelGetter, Set<UnbakedModel> chain, ResourceLocation location, String name) {
// model must exist
UnbakedModel unbaked = modelGetter.apply(location);
if (unbaked == null) {
FunctionalStorage.LOGGER.warn("No parent '{}' while loading model '{}'", location, name);
return null;
}
// no loops in chain
if (chain.contains(unbaked)) {
FunctionalStorage.LOGGER.warn("Found 'parent' loop while loading model '{}' in chain: {} -> {}", name, chain.stream().map(Object::toString).collect(Collectors.joining(" -> ")), location);
return null;
}
// model must be block model, this is a serious error in vanilla
if (!(unbaked instanceof BlockModel)) {
throw new IllegalStateException("BlockModel parent has to be a block model.");
}
return (BlockModel) unbaked;
}
/**
* Gets the missing model, ensuring its the right type
*
* @param modelGetter Model getter function
* @return Missing model as a {@link BlockModel}
*/
@Nonnull
private static BlockModel getMissing(Function<ResourceLocation, UnbakedModel> modelGetter) {
UnbakedModel model = modelGetter.apply(ModelBakery.MISSING_MODEL_LOCATION);
if (!(model instanceof BlockModel)) {
throw new IllegalStateException("Failed to load missing model");
}
return (BlockModel) model;
}
/**
* Gets the texture dependencies for a list of elements, allows calling outside a simple block model
*
* @param owner Model configuration
* @param elements List of elements to check for textures
* @param missingTextureErrors Missing texture set
* @return Textures dependencies
*/
public static Collection<Material> getTextures(IModelConfiguration owner, List<BlockElement> elements, Set<Pair<String, String>> missingTextureErrors) {
// always need a particle texture
Set<Material> textures = Sets.newHashSet(owner.resolveTexture("particle"));
// iterate all elements, fetching needed textures from the material
for (BlockElement part : elements) {
for (BlockElementFace face : part.faces.values()) {
Material material = owner.resolveTexture(face.texture);
if (Objects.equals(material.texture(), MissingTextureAtlasSprite.getLocation())) {
missingTextureErrors.add(Pair.of(face.texture, owner.getModelName()));
}
textures.add(material);
}
}
return textures;
}
/**
* Gets the texture and model dependencies for a block model
*
* @param owner Model configuration
* @param modelGetter Model getter to fetch parent models
* @param missingTextureErrors Missing texture set
* @return Textures dependencies
*/
@Override
public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
this.fetchParent(owner, modelGetter);
return getTextures(owner, getElements(), missingTextureErrors);
}
/* Baking */
/**
* Bakes a single part of the model into the builder
*
* @param builder Baked model builder
* @param owner Model owner
* @param part Part to bake
* @param transform Model transforms
* @param spriteGetter Sprite getter
* @param location Model location
*/
public static void bakePart(SimpleBakedModel.Builder builder, IModelConfiguration owner, BlockElement part, ModelState transform, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation location) {
for (Direction direction : part.faces.keySet()) {
BlockElementFace face = part.faces.get(direction);
// ensure the name is not prefixed (it always is)
String texture = face.texture;
if (texture.charAt(0) == '#') {
texture = texture.substring(1);
}
// bake the face
TextureAtlasSprite sprite = spriteGetter.apply(owner.resolveTexture(texture));
BakedQuad bakedQuad = BlockModel.makeBakedQuad(part, face, sprite, direction, transform, location);
// apply cull face
if (face.cullForDirection == null) {
builder.addUnculledFace(bakedQuad);
} else {
builder.addCulledFace(Direction.rotate(transform.getRotation().getMatrix(), face.cullForDirection), bakedQuad);
}
}
}
/**
* Bakes a list of block part elements into a model
*
* @param owner Model configuration
* @param elements Model elements
* @param transform Model transform
* @param overrides Model overrides
* @param spriteGetter Sprite getter instance
* @param location Model bake location
* @return Baked model
*/
public static BakedModel bakeModel(IModelConfiguration owner, List<BlockElement> elements, ModelState transform, ItemOverrides overrides, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation location) {
// iterate parts, adding to the builder
TextureAtlasSprite particle = spriteGetter.apply(owner.resolveTexture("particle"));
SimpleBakedModel.Builder builder = new SimpleBakedModel.Builder(owner, overrides).particle(particle);
for (BlockElement part : elements) {
bakePart(builder, owner, part, transform, spriteGetter, location);
}
return builder.build();
}
/**
* Same as {@link #bakeModel(IModelConfiguration, List, ModelState, ItemOverrides, Function, ResourceLocation)}, but passes in sensible defaults for values unneeded in dynamic models
*
* @param owner Model configuration
* @param elements Elements to bake
* @param transform Model transform
* @return Baked model
*/
public static BakedModel bakeDynamic(IModelConfiguration owner, List<BlockElement> elements, ModelState transform) {
return bakeModel(owner, elements, transform, ItemOverrides.EMPTY, ForgeModelBakery.defaultTextureGetter(), BAKE_LOCATION);
}
/**
* Bakes the given block model
*
* @param owner Model configuration
* @param transform Transform to apply
* @param overrides Item overrides in baking
* @param spriteGetter Sprite getter instance
* @param location Bake location
* @return Baked model
*/
public BakedModel bakeModel(IModelConfiguration owner, ModelState transform, ItemOverrides overrides, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation location) {
return bakeModel(owner, this.getElements(), transform, overrides, spriteGetter, location);
}
@Override
public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState transform, ItemOverrides overrides, ResourceLocation location) {
return bakeModel(owner, transform, overrides, spriteGetter, location);
}
/**
* Same as {@link #bakeModel(IModelConfiguration, ModelState, ItemOverrides, Function, ResourceLocation)}, but passes in sensible defaults for values unneeded in dynamic models
*
* @param owner Model configuration
* @param transform Transform to apply
* @return Baked model
*/
public BakedModel bakeDynamic(IModelConfiguration owner, ModelState transform) {
return bakeDynamic(owner, this.getElements(), transform);
}
/* Deserializing */
/**
* Deserializes a SimpleBlockModel from JSON
*
* @param context Json Context
* @param json Json element containing the model
* @return Serialized JSON
*/
public static SimpleBlockModel deserialize(JsonDeserializationContext context, JsonObject json) {
// parent, null if missing
String parentName = GsonHelper.getAsString(json, "parent", "");
ResourceLocation parent = parentName.isEmpty() ? null : new ResourceLocation(parentName);
// textures, empty map if missing
Map<String, Either<Material, String>> textureMap;
if (json.has("textures")) {
ImmutableMap.Builder<String, Either<Material, String>> builder = new ImmutableMap.Builder<>();
ResourceLocation atlas = InventoryMenu.BLOCK_ATLAS;
JsonObject textures = GsonHelper.getAsJsonObject(json, "textures");
for (Entry<String, JsonElement> entry : textures.entrySet()) {
builder.put(entry.getKey(), BlockModel.Deserializer.parseTextureLocationOrReference(atlas, entry.getValue().getAsString()));
}
textureMap = builder.build();
} else {
textureMap = Collections.emptyMap();
}
// elements, empty list if missing
List<BlockElement> parts;
if (json.has("elements")) {
parts = getModelElements(context, GsonHelper.getAsJsonArray(json, "elements"), "elements");
} else {
parts = Collections.emptyList();
}
return new SimpleBlockModel(parent, textureMap, parts);
}
/**
* Gets a list of models from a JSON array
*
* @param context Json Context
* @param array Json array
* @return Model list
*/
public static List<BlockElement> getModelElements(JsonDeserializationContext context, JsonElement array, String name) {
// if just one element, array is optional
if (array.isJsonObject()) {
return ImmutableList.of(context.deserialize(array.getAsJsonObject(), BlockElement.class));
}
// if an array, get array of elements
if (array.isJsonArray()) {
ImmutableList.Builder<BlockElement> builder = ImmutableList.builder();
for (JsonElement json : array.getAsJsonArray()) {
builder.add((BlockElement) context.deserialize(json, BlockElement.class));
}
return builder.build();
}
throw new JsonSyntaxException("Missing " + name + ", expected to find a JsonArray or JsonObject");
}
/**
* Logic to implement a vanilla block model
*/
private static class Loader implements IModelLoader<SimpleBlockModel> {
@Override
public void onResourceManagerReload(ResourceManager resourceManager) {
}
@Override
public SimpleBlockModel read(JsonDeserializationContext context, JsonObject json) {
return deserialize(context, json);
}
}
@Nullable
public ResourceLocation getParentLocation() {
return parentLocation;
}
public Map<String, Either<Material, String>> getTextures() {
return textures;
}
public BlockModel getParent() {
return parent;
}
}

View File

@ -0,0 +1,135 @@
/*
* This file is part of Industrial Foregoing.
*
* Copyright 2021, Buuz135
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.buuz135.functionalstorage.client.model;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class FramedDrawerBlockModel implements IDynamicBakedModel {
public static Cache<Pair<Pair<String, Pair<Direction, Direction>>, Direction>, List<BakedQuad>> CACHE = CacheBuilder.newBuilder().build();
private VertexFormat format;
private BakedModel previousModel;
private Map<Direction, List<BakedQuad>> prevQuads = new HashMap<>();
public FramedDrawerBlockModel(BakedModel previousConveyor) {
this.previousModel = previousConveyor;
this.format = DefaultVertexFormat.BLOCK;
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) {
List<BakedQuad> bakedQuads = new ArrayList<>();
BakedModel otherModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(Blocks.STONE.defaultBlockState());
for (BakedQuad quad : previousModel.getQuads(state, side, rand)) {
if (otherModel.getQuads(state, side, rand).size() > 0) {
BakedQuadBuilder bakedQuadBuilder = new BakedQuadBuilder(otherModel.getQuads(state, side, rand).get(0).getSprite());
bakedQuadBuilder.setQuadOrientation(quad.getDirection());
bakedQuadBuilder.setQuadTint(quad.getTintIndex());
bakedQuadBuilder.setApplyDiffuseLighting(quad.isShade());
quad.pipe(bakedQuadBuilder);
bakedQuadBuilder.setTexture(otherModel.getQuads(state, side, rand).get(0).getSprite());
System.out.println(otherModel.getQuads(state, side, rand).get(0).getVertices().length);
BakedQuad extra = bakedQuadBuilder.build();
System.out.println(Arrays.toString(extra.getVertices()));
bakedQuads.add(extra);
//bakedQuadBuilder.getVertexFormat()
//bakedQuads.add(bakedQuadBuilder.build());
}
}
return bakedQuads;/*
if (state == null) {
if (!prevQuads.containsKey(side))
prevQuads.put(side, previousModel.getQuads(state, side, rand));
return prevQuads.get(side);
}
if (!prevQuads.containsKey(side))
prevQuads.put(side, previousModel.getQuads(state, side, rand));
List<BakedQuad> quads = new ArrayList<>(prevQuads.get(side));
return quads;*/
}
@Override
public boolean useAmbientOcclusion() {
return previousModel.useAmbientOcclusion();
}
@Override
public boolean isGui3d() {
return previousModel.isGui3d();
}
@Override
public boolean usesBlockLight() {
return previousModel.usesBlockLight();
}
@Override
public boolean isCustomRenderer() {
return previousModel.isCustomRenderer();
}
@Nonnull
@Override
public TextureAtlasSprite getParticleIcon() {
return previousModel.getParticleIcon();
}
@Nonnull
@Override
public ItemOverrides getOverrides() {
return previousModel.getOverrides();
}
@Override
public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack mat) {
return previousModel.handlePerspective(cameraTransformType, mat);
}
@Override
public ItemTransforms getTransforms() {
return previousModel.getTransforms();
}
}

View File

@ -0,0 +1,44 @@
/*
* This file is part of Industrial Foregoing.
*
* Copyright 2021, Buuz135
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.buuz135.functionalstorage.client.model;
import net.minecraft.core.Direction;
import net.minecraft.world.item.Item;
import net.minecraftforge.client.model.data.ModelProperty;
import java.util.Map;
public class FramedDrawerModelData {
public static final ModelProperty<FramedDrawerModelData> UPGRADE_PROPERTY = new ModelProperty<>();
private Map<Integer, Item> design;
public FramedDrawerModelData(Map<Integer, Item> design) {
this.design = design;
}
public Map<Integer, Item> getDesign() {
return design;
}
}

View File

@ -0,0 +1,102 @@
{
"credit": "Made with Blockbench",
"textures": {
"lock_icon": "functionalstorage:blocks/unlock"
},
"elements": [
{
"from": [15, 1, 0],
"to": [16, 15, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 15, 15, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [1, 1, 16, 15], "texture": "#side", "cullface": "east"},
"west": {"uv": [0, 1, 15, 15], "texture": "#side"}
}
},
{
"from": [0, 15, 0],
"to": [16, 16, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "west"},
"up": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "up"},
"down": {"uv": [0, 0, 16, 16], "texture": "#side"}
}
},
{
"from": [0, 1, 0],
"to": [1, 15, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 15, 15, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [1, 1, 16, 15], "texture": "#side"},
"west": {"uv": [0, 1, 15, 15], "texture": "#side", "cullface": "west"}
}
},
{
"from": [0, 0, 0],
"to": [16, 1, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "west"},
"up": {"uv": [0, 0, 16, 16], "texture": "#side"},
"down": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "down"}
}
},
{
"from": [0, 1, 15],
"to": [16, 15, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"east": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 1, 16, 15], "texture": "#side", "cullface": "south"},
"west": {"uv": [1, 15, 15, 16], "rotation": 90, "texture": "#side", "cullface": "west"}
}
},
{
"from": [7.5, 15, -0.01],
"to": [8.5, 16, 16],
"faces": {
"north": {"uv": [0, 0, 16, 16], "texture": "#lock_icon", "cullface": "north"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
}
}

View File

@ -0,0 +1,10 @@
{
"loader": "functionalstorage:framed",
"parent": "functionalstorage:block/base_x_1",
"textures": {
"particle": "functionalstorage:blocks/acacia_front_1",
"front": "functionalstorage:blocks/acacia_front_1",
"side": "functionalstorage:blocks/acacia_side"
},
"retextured": [ "particle", "side" ]
}