Add multi-model support for multiparts
This commit is contained in:
parent
83a2a2e852
commit
0f8d9f1353
|
@ -13,11 +13,8 @@ import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.shadowfacts.simplemultipart.SimpleMultipart;
|
import net.shadowfacts.simplemultipart.SimpleMultipart;
|
||||||
import net.shadowfacts.simplemultipart.container.MultipartContainerBlockState;
|
import net.shadowfacts.simplemultipart.container.MultipartContainerBlockState;
|
||||||
import net.shadowfacts.simplemultipart.multipart.MultipartSlot;
|
|
||||||
import net.shadowfacts.simplemultipart.multipart.MultipartState;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -42,7 +39,16 @@ public class MultipartContainerBakedModel implements BakedModel {
|
||||||
if (model instanceof MultipartBakedModel) {
|
if (model instanceof MultipartBakedModel) {
|
||||||
return ((MultipartBakedModel)model).getMultipartQuads(partState, side, random).stream();
|
return ((MultipartBakedModel)model).getMultipartQuads(partState, side, random).stream();
|
||||||
} else {
|
} else {
|
||||||
return model.getQuads(null, side, random).stream();
|
BlockState fakeState = null;
|
||||||
|
|
||||||
|
// Need to use the same fake block state as used when loading multi-models
|
||||||
|
// otherwise MultipartBakedModel will return no quads for a null state
|
||||||
|
MultipartFakeBlock fakeBlock = MultipartFakeBlock.fakeBlocks.get(partId);
|
||||||
|
if (fakeBlock != null) {
|
||||||
|
fakeState = fakeBlock.getFakeState(partState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return model.getQuads(fakeState, side, random).stream();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
@ -65,7 +71,7 @@ public class MultipartContainerBakedModel implements BakedModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Sprite getSprite() {
|
public Sprite getSprite() {
|
||||||
return MinecraftClient.getInstance().getSpriteAtlas().getSprite("blocks/stone");
|
return MinecraftClient.getInstance().getSpriteAtlas().getSprite("block/stone");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package net.shadowfacts.simplemultipart.client;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Material;
|
||||||
|
import net.minecraft.state.StateFactory;
|
||||||
|
import net.minecraft.state.property.Property;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.shadowfacts.simplemultipart.SimpleMultipart;
|
||||||
|
import net.shadowfacts.simplemultipart.multipart.Multipart;
|
||||||
|
import net.shadowfacts.simplemultipart.multipart.MultipartState;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
public class MultipartFakeBlock extends Block {
|
||||||
|
|
||||||
|
public static final Map<Identifier, MultipartFakeBlock> fakeBlocks = new HashMap<>();
|
||||||
|
|
||||||
|
private final Multipart multipart;
|
||||||
|
private final StateFactory<Block, BlockState> fakeStateFactory;
|
||||||
|
|
||||||
|
public MultipartFakeBlock(Multipart multipart) {
|
||||||
|
super(Settings.of(Material.AIR));
|
||||||
|
|
||||||
|
this.multipart = multipart;
|
||||||
|
this.fakeStateFactory = createFakeStateFactory();
|
||||||
|
|
||||||
|
setDefaultState(fakeStateFactory.getDefaultState());
|
||||||
|
|
||||||
|
Identifier partId = SimpleMultipart.MULTIPART.getId(multipart);
|
||||||
|
fakeBlocks.put(partId, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StateFactory<Block, BlockState> createFakeStateFactory() {
|
||||||
|
StateFactory.Builder<Block, BlockState> builder = new StateFactory.Builder<>(this);
|
||||||
|
multipart.getStateFactory().getProperties().forEach(builder::with);
|
||||||
|
return builder.build(BlockState::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StateFactory<Block, BlockState> getStateFactory() {
|
||||||
|
return fakeStateFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockState getFakeState(MultipartState state) {
|
||||||
|
BlockState fakeState = getDefaultState();
|
||||||
|
for (Map.Entry<Property<?>, Comparable<?>> e : state.getEntries().entrySet()) {
|
||||||
|
fakeState = with(fakeState, e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
return fakeState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockState with(BlockState state, Property prop, Comparable value) {
|
||||||
|
return state.with(prop, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package net.shadowfacts.simplemultipart.client;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.model.ModelProvider;
|
import net.fabricmc.fabric.api.client.model.ModelProvider;
|
||||||
import net.fabricmc.fabric.api.client.model.ModelProviderException;
|
import net.fabricmc.fabric.api.client.model.ModelProviderException;
|
||||||
|
import net.minecraft.class_816;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.block.BlockModels;
|
import net.minecraft.client.render.block.BlockModels;
|
||||||
import net.minecraft.client.render.model.UnbakedModel;
|
import net.minecraft.client.render.model.UnbakedModel;
|
||||||
|
@ -68,40 +69,63 @@ public class MultipartModelProvider implements ModelProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnbakedModel getOrLoadPartModel(ModelIdentifier id) throws ModelProviderException, IOException {
|
private UnbakedModel getOrLoadPartModel(ModelIdentifier modelId) throws ModelProviderException, IOException {
|
||||||
UnbakedModel existing = unbakedModels.get(id);
|
UnbakedModel existing = unbakedModels.get(modelId);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadModel(id);
|
return loadPartModel(modelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnbakedModel loadModel(ModelIdentifier id) throws ModelProviderException, IOException {
|
private UnbakedModel loadPartModel(ModelIdentifier modelId) throws ModelProviderException, IOException {
|
||||||
Identifier partStateId = new Identifier(id.getNamespace(), "multipartstates/" + id.getPath() + ".json");
|
Identifier partId = new Identifier(modelId.getNamespace(), modelId.getPath());
|
||||||
ModelVariantMap variantMap = loadVariantMap(partStateId);
|
Identifier partStateDefId = new Identifier(partId.getNamespace(), "multipartstates/" + partId.getPath() + ".json");
|
||||||
Map<String, WeightedUnbakedModel> variants = variantMap.method_3423();
|
|
||||||
variants.forEach((variant, model) -> {
|
|
||||||
unbakedModels.put(new ModelIdentifier(new Identifier(id.getNamespace(), id.getPath()), variant), model);
|
|
||||||
});
|
|
||||||
|
|
||||||
UnbakedModel model = unbakedModels.get(id);
|
Multipart part = SimpleMultipart.MULTIPART.get(partId);
|
||||||
|
MultipartFakeBlock blockAdapter = new MultipartFakeBlock(part);
|
||||||
|
|
||||||
|
ModelVariantMap variantMap = loadPartVariantMap(blockAdapter, partStateDefId);
|
||||||
|
|
||||||
|
if (variantMap.method_3422()) {
|
||||||
|
class_816 multipartUnbakedModel = variantMap.method_3421();
|
||||||
|
part.getStateFactory().getStates().forEach(state -> {
|
||||||
|
ModelIdentifier stateModelId = new ModelIdentifier(partId, BlockModels.propertyMapToString(state.getEntries()));
|
||||||
|
unbakedModels.put(stateModelId, multipartUnbakedModel);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Map<String, WeightedUnbakedModel> variants = variantMap.method_3423();
|
||||||
|
variants.forEach((variant, model) -> {
|
||||||
|
unbakedModels.put(new ModelIdentifier(partId, variant), model);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
UnbakedModel model = unbakedModels.get(modelId);
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw new ModelProviderException("Loaded multipart state " + partStateId + " for model " + id + " but still missing model");
|
throw new ModelProviderException("Loaded multipart state " + partStateDefId + " for model " + modelId + " but still missing model");
|
||||||
}
|
}
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModelVariantMap loadVariantMap(Identifier id) throws IOException {
|
// private StateFactory<Block, BlockState> getStateFactory(class_816 multipartUnbakedModel) {
|
||||||
|
// try {
|
||||||
|
// Field f = class_816.class.getDeclaredField("field_4329");
|
||||||
|
// f.setAccessible(true);
|
||||||
|
// return (StateFactory<Block, BlockState>)f.get(multipartUnbakedModel);
|
||||||
|
// } catch (ReflectiveOperationException e) {
|
||||||
|
// throw new RuntimeException(e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private ModelVariantMap loadPartVariantMap(MultipartFakeBlock blockAdapter, Identifier partStateDefId) throws IOException {
|
||||||
Resource resource = null;
|
Resource resource = null;
|
||||||
Reader reader = null;
|
Reader reader = null;
|
||||||
try {
|
try {
|
||||||
resource = MinecraftClient.getInstance().getResourceManager().getResource(id);
|
resource = MinecraftClient.getInstance().getResourceManager().getResource(partStateDefId);
|
||||||
reader = new InputStreamReader(resource.getInputStream());
|
reader = new InputStreamReader(resource.getInputStream());
|
||||||
|
|
||||||
ModelVariantMap.class_791 context = new ModelVariantMap.class_791();
|
ModelVariantMap.class_791 context = new ModelVariantMap.class_791();
|
||||||
// context.stateFactory =
|
context.method_3426(blockAdapter.getStateFactory());
|
||||||
// TODO: ^ blockstate translation
|
|
||||||
return ModelVariantMap.method_3424(context, reader);
|
return ModelVariantMap.method_3424(context, reader);
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(reader);
|
IOUtils.closeQuietly(reader);
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"texture": "block/diamond_block"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [6, 6, 6],
|
||||||
|
"to": [10, 10, 10],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#texture" },
|
||||||
|
"up": { "texture": "#texture" },
|
||||||
|
"north": { "texture": "#texture" },
|
||||||
|
"south": { "texture": "#texture" },
|
||||||
|
"west": { "texture": "#texture" },
|
||||||
|
"east": { "texture": "#texture" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
{
|
{
|
||||||
"variants": {
|
"multipart": [
|
||||||
"slot=bottom": { "model": "multipart_test:multipart/bottom" },
|
{
|
||||||
"slot=top": { "model": "multipart_test:multipart/bottom", "x": 180 },
|
"apply": { "model": "multipart_test:multipart/center" }
|
||||||
"slot=north": { "model": "multipart_test:multipart/vertical" },
|
},
|
||||||
"slot=south": { "model": "multipart_test:multipart/vertical", "y": 180 },
|
{
|
||||||
"slot=east": { "model": "multipart_test:multipart/vertical", "y": 90 },
|
"when": { "slot": "bottom" },
|
||||||
"slot=west": { "model": "multipart_test:multipart/vertical", "y": 270 },
|
"apply": { "model": "multipart_test:multipart/bottom" }
|
||||||
"inventory": { "model": "multipart_test:multipart/vertical", "y": 180 }
|
},
|
||||||
}
|
{
|
||||||
|
"when": { "slot": "north" },
|
||||||
|
"apply": { "model": "multipart_test:multipart/vertical" }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"slot=bottom": { "model": "multipart_test:multipart/bottom" },
|
||||||
|
"slot=top": { "model": "multipart_test:multipart/bottom", "x": 180 },
|
||||||
|
"slot=north": { "model": "multipart_test:multipart/vertical" },
|
||||||
|
"slot=south": { "model": "multipart_test:multipart/vertical", "y": 180 },
|
||||||
|
"slot=east": { "model": "multipart_test:multipart/vertical", "y": 90 },
|
||||||
|
"slot=west": { "model": "multipart_test:multipart/vertical", "y": 270 },
|
||||||
|
"inventory": { "model": "multipart_test:multipart/vertical", "y": 180 }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue