Rewrite drive model to support custom cell models (#4459)

* Rewrite driver model to support custom cell models

Each cell can now register a mapping Item -> ResourceLocation for a
custom cell model. Fallback will always be a 1k item cell.
This commit is contained in:
yueh
2020-07-11 23:07:20 +02:00
committed by GitHub
parent e8143d3618
commit 06735f5c39
30 changed files with 319 additions and 95 deletions
@@ -1,45 +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.block.storage;
import net.minecraft.util.IStringSerializable;
/**
* Describes the type of cell present in a slot.
*/
public enum DriveSlotCellType implements IStringSerializable {
EMPTY("empty"),
ITEM("item"),
FLUID("fluid");
private final String name;
DriveSlotCellType(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
}
@@ -31,22 +31,22 @@ import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.util.Direction;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import appeng.api.definitions.IItems;
import appeng.block.storage.DriveSlotCellType;
import appeng.block.storage.DriveSlotsState;
import appeng.client.render.DelegateBakedModel;
import appeng.core.Api;
public class DriveBakedModel extends DelegateBakedModel {
private final Map<DriveSlotCellType, IBakedModel> bakedCells;
private final Map<Item, IBakedModel> bakedCells;
private final IBakedModel defaultCell;
public DriveBakedModel(IBakedModel bakedBase, Map<DriveSlotCellType, IBakedModel> bakedCells) {
public DriveBakedModel(IBakedModel bakedBase, Map<Item, IBakedModel> cellModels, IBakedModel defaultCell) {
super(bakedBase);
this.bakedCells = bakedCells;
this.bakedCells = cellModels;
this.defaultCell = defaultCell;
}
@Nonnull
@@ -92,23 +92,18 @@ public class DriveBakedModel extends DelegateBakedModel {
public boolean isAmbientOcclusion() {
// We have faces inside the chassis that are facing east, but should not receive
// ambient occlusion from the east-side, but sadly this cannot be fine-tuned on
// a
// face-by-face basis.
// a face-by-face basis.
return false;
}
// Determine which drive chassis to show based on the used cell
private IBakedModel getCellChassisModel(Item cell) {
IItems items = Api.INSTANCE.definitions().items();
if (cell == null) {
return bakedCells.get(DriveSlotCellType.EMPTY);
} else if (items.fluidCell1k().item() == cell || items.fluidCell4k().item() == cell
|| items.fluidCell16k().item() == cell || items.fluidCell64k().item() == cell) {
return bakedCells.get(DriveSlotCellType.FLUID);
} else {
// Fall back to an item model
return bakedCells.get(DriveSlotCellType.ITEM);
return bakedCells.get(Items.AIR);
}
final IBakedModel model = bakedCells.get(cell);
return model != null ? model : defaultCell;
}
private static void addModel(@Nullable BlockState state, @Nonnull Random rand, @Nonnull IModelData extraData,
@@ -20,13 +20,12 @@ package appeng.client.render.model;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.renderer.model.IBakedModel;
@@ -36,39 +35,41 @@ import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.model.Material;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import appeng.block.storage.DriveSlotCellType;
import appeng.api.client.ICellModelRegistry;
import appeng.core.Api;
public class DriveModel implements IModelGeometry<DriveModel> {
private static final ResourceLocation MODEL_BASE = new ResourceLocation(
"appliedenergistics2:block/drive/drive_base");
private static final Map<DriveSlotCellType, ResourceLocation> MODELS_CELLS = ImmutableMap.of(
DriveSlotCellType.EMPTY, new ResourceLocation("appliedenergistics2:block/drive/drive_cell_empty"),
DriveSlotCellType.ITEM, new ResourceLocation("appliedenergistics2:block/drive/drive_cell_items"),
DriveSlotCellType.FLUID, new ResourceLocation("appliedenergistics2:block/drive/drive_cell_fluids"));
public static final Set<ResourceLocation> DEPENDENCIES = ImmutableSet.<ResourceLocation>builder()
.addAll(MODELS_CELLS.values()).add(MODEL_BASE).build();
private static final ResourceLocation MODEL_CELL_EMPTY = new ResourceLocation(
"appliedenergistics2:block/drive/drive_cell_empty");
@Override
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery,
Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform,
ItemOverrideList overrides, ResourceLocation modelLocation) {
EnumMap<DriveSlotCellType, IBakedModel> cellModels = new EnumMap<>(DriveSlotCellType.class);
final ICellModelRegistry cellRegistry = Api.instance().client().cells();
final Map<Item, IBakedModel> cellModels = new IdentityHashMap<>();
// Load the base model and the model for each cell state.
for (DriveSlotCellType cellType : MODELS_CELLS.keySet()) {
IBakedModel cellModel = bakery.getBakedModel(MODELS_CELLS.get(cellType), modelTransform, spriteGetter);
cellModels.put(cellType, cellModel);
// Load the base model and the model for each cell model.
for (Entry<Item, ResourceLocation> entry : cellRegistry.models().entrySet()) {
IBakedModel cellModel = bakery.getBakedModel(entry.getValue(), modelTransform, spriteGetter);
cellModels.put(entry.getKey(), cellModel);
}
IBakedModel baseModel = bakery.getBakedModel(MODEL_BASE, modelTransform, spriteGetter);
return new DriveBakedModel(baseModel, cellModels);
final IBakedModel baseModel = bakery.getBakedModel(MODEL_BASE, modelTransform, spriteGetter);
final IBakedModel defaultCell = bakery.getBakedModel(cellRegistry.getDefaultModel(), modelTransform,
spriteGetter);
cellModels.put(Items.AIR, bakery.getBakedModel(MODEL_CELL_EMPTY, modelTransform, spriteGetter));
return new DriveBakedModel(baseModel, cellModels, defaultCell);
}
@Override
+2 -2
View File
@@ -20,10 +20,10 @@ package appeng.core;
import appeng.api.AEAddon;
import appeng.api.IAppEngApi;
import appeng.api.client.IClientHelper;
import appeng.api.features.IRegistryContainer;
import appeng.api.networking.IGridHelper;
import appeng.api.storage.IStorageHelper;
import appeng.api.util.IClientHelper;
import appeng.core.api.ApiClientHelper;
import appeng.core.api.ApiGrid;
import appeng.core.api.ApiPart;
@@ -67,7 +67,7 @@ public final class Api implements IAppEngApi {
this.registryContainer = new RegistryContainer();
this.partHelper = new ApiPart();
this.definitions = new ApiDefinitions((PartModels) this.registryContainer.partModels());
this.client = new ApiClientHelper();
this.client = new ApiClientHelper(this.definitions);
}
public PartModels getPartModels() {
+2 -2
View File
@@ -125,7 +125,6 @@ import appeng.client.render.effects.MatterCannonFX;
import appeng.client.render.effects.ParticleTypes;
import appeng.client.render.effects.VibrantFX;
import appeng.client.render.model.BiometricCardModel;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.MemoryCardModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.tesr.InscriberTESR;
@@ -165,6 +164,7 @@ import appeng.container.implementations.UpgradeableContainer;
import appeng.container.implementations.VibrationChamberContainer;
import appeng.container.implementations.WirelessContainer;
import appeng.container.implementations.WirelessTermContainer;
import appeng.core.api.client.ApiCellModelRegistry;
import appeng.core.features.registries.P2PTunnelRegistry;
import appeng.core.features.registries.PartModels;
import appeng.core.features.registries.cell.BasicCellHandler;
@@ -256,7 +256,7 @@ final class Registration {
SkyCompassModel.DEPENDENCIES.forEach(ModelLoader::addSpecialModel);
ModelLoader.addSpecialModel(BiometricCardModel.MODEL_BASE);
ModelLoader.addSpecialModel(MemoryCardModel.MODEL_BASE);
DriveModel.DEPENDENCIES.forEach(ModelLoader::addSpecialModel);
ApiCellModelRegistry.registerModels();
ModelLoader.addSpecialModel(MolecularAssemblerRenderer.LIGHTS_MODEL);
PartModels partModels = (PartModels) Api.INSTANCE.registries().partModels();
@@ -1,5 +1,6 @@
/*
* This file is part of Applied Energistics 2.
*
* Copyright (c) 2013 - 2020, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
@@ -23,14 +24,24 @@ import java.util.List;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import appeng.api.client.ICellModelRegistry;
import appeng.api.client.IClientHelper;
import appeng.api.config.IncludeExclude;
import appeng.api.storage.cells.ICellInventory;
import appeng.api.storage.cells.ICellInventoryHandler;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.IClientHelper;
import appeng.core.ApiDefinitions;
import appeng.core.api.client.ApiCellModelRegistry;
import appeng.core.localization.GuiText;
public class ApiClientHelper implements IClientHelper {
private final ICellModelRegistry cells;
public ApiClientHelper(ApiDefinitions definitions) {
this.cells = new ApiCellModelRegistry(definitions);
}
@Override
public <T extends IAEStack<T>> void addCellInformation(ICellInventoryHandler<T> handler,
List<ITextComponent> lines) {
@@ -65,4 +76,9 @@ public class ApiClientHelper implements IClientHelper {
}
@Override
public ICellModelRegistry cells() {
return this.cells;
}
}
@@ -0,0 +1,119 @@
/*
* This file is part of Applied Energistics 2.
*
* Copyright (c) 2020, TeamAppliedEnergistics, 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.core.api.client;
import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader;
import appeng.api.client.ICellModelRegistry;
import appeng.core.ApiDefinitions;
public class ApiCellModelRegistry implements ICellModelRegistry {
private static final ResourceLocation MODEL_BASE = new ResourceLocation(
"appliedenergistics2:block/drive/drive_base");
private static final ResourceLocation MODEL_CELL_EMPTY = new ResourceLocation(
"appliedenergistics2:block/drive/drive_cell_empty");
private static final ResourceLocation MODEL_CELL_DEFAULT = new ResourceLocation(
"appliedenergistics2:block/drive/drive_cell");
private static final ResourceLocation MODEL_CELL_ITEMS_1K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/1k_item_cell");
private static final ResourceLocation MODEL_CELL_ITEMS_4K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/4k_item_cell");
private static final ResourceLocation MODEL_CELL_ITEMS_16K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/16k_item_cell");
private static final ResourceLocation MODEL_CELL_ITEMS_64K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/64k_item_cell");
private static final ResourceLocation MODEL_CELL_FLUIDS_1K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/1k_fluid_cell");
private static final ResourceLocation MODEL_CELL_FLUIDS_4K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/4k_fluid_cell");
private static final ResourceLocation MODEL_CELL_FLUIDS_16K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/16k_fluid_cell");
private static final ResourceLocation MODEL_CELL_FLUIDS_64K = new ResourceLocation(
"appliedenergistics2:block/drive/cells/64k_fluid_cell");
private static final ResourceLocation MODEL_CELL_CREATIVE = new ResourceLocation(
"appliedenergistics2:block/drive/cells/creative_cell");
private static final ResourceLocation[] MODELS = { MODEL_BASE, MODEL_CELL_EMPTY, MODEL_CELL_DEFAULT,
MODEL_CELL_ITEMS_1K, MODEL_CELL_ITEMS_4K, MODEL_CELL_ITEMS_16K, MODEL_CELL_ITEMS_64K, MODEL_CELL_FLUIDS_1K,
MODEL_CELL_FLUIDS_4K, MODEL_CELL_FLUIDS_16K, MODEL_CELL_FLUIDS_64K, MODEL_CELL_CREATIVE };
public static void registerModels() {
Arrays.stream(MODELS).forEach(ModelLoader::addSpecialModel);
}
private final Map<Item, ResourceLocation> registry;
public ApiCellModelRegistry(ApiDefinitions definitions) {
this.registry = new IdentityHashMap<>();
this.registry.put(definitions.items().cell1k().item(), MODEL_CELL_ITEMS_1K);
this.registry.put(definitions.items().cell4k().item(), MODEL_CELL_ITEMS_4K);
this.registry.put(definitions.items().cell16k().item(), MODEL_CELL_ITEMS_16K);
this.registry.put(definitions.items().cell64k().item(), MODEL_CELL_ITEMS_64K);
this.registry.put(definitions.items().fluidCell1k().item(), MODEL_CELL_FLUIDS_1K);
this.registry.put(definitions.items().fluidCell4k().item(), MODEL_CELL_FLUIDS_4K);
this.registry.put(definitions.items().fluidCell16k().item(), MODEL_CELL_FLUIDS_16K);
this.registry.put(definitions.items().fluidCell64k().item(), MODEL_CELL_FLUIDS_64K);
this.registry.put(definitions.items().fluidCell64k().item(), MODEL_CELL_FLUIDS_64K);
this.registry.put(definitions.items().cellCreative().item(), MODEL_CELL_CREATIVE);
}
@Override
public void registerModel(Item item, ResourceLocation model) {
Preconditions.checkNotNull(item);
Preconditions.checkNotNull(model);
Preconditions.checkArgument(!this.registry.containsKey(item), "Cannot register an item twice.");
this.registry.put(item, model);
}
@Override
@Nullable
public ResourceLocation model(@Nonnull Item item) {
Preconditions.checkNotNull(item);
return this.registry.get(item);
}
@Override
@Nonnull
public Map<Item, ResourceLocation> models() {
return Collections.unmodifiableMap(this.registry);
}
@Override
@Nonnull
public ResourceLocation getDefaultModel() {
return MODEL_CELL_DEFAULT;
}
}