Add new system for model data, replacing extended states (#5564)

This commit is contained in:
tterrag 2019-05-09 02:10:38 -04:00 committed by GitHub
parent a7204b5cd3
commit 9209c3cbfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 718 additions and 572 deletions

View File

@ -1,15 +1,86 @@
--- a/net/minecraft/client/renderer/BlockModelRenderer.java
+++ b/net/minecraft/client/renderer/BlockModelRenderer.java
@@ -45,7 +45,7 @@
@@ -44,11 +44,17 @@
this.field_187499_a = p_i46575_1_;
}
+ @Deprecated
public boolean func_199324_a(IWorldReader p_199324_1_, IBakedModel p_199324_2_, IBlockState p_199324_3_, BlockPos p_199324_4_, BufferBuilder p_199324_5_, boolean p_199324_6_, Random p_199324_7_, long p_199324_8_) {
- boolean flag = Minecraft.func_71379_u() && p_199324_3_.func_185906_d() == 0 && p_199324_2_.func_177555_b();
+ boolean flag = Minecraft.func_71379_u() && p_199324_3_.getLightValue(p_199324_1_, p_199324_4_) == 0 && p_199324_2_.isAmbientOcclusion(p_199324_3_);
+ return renderModel(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE);
+ }
+ public boolean renderModel(IWorldReader p_199324_1_, IBakedModel p_199324_2_, IBlockState p_199324_3_, BlockPos p_199324_4_, BufferBuilder p_199324_5_, boolean p_199324_6_, Random p_199324_7_, long p_199324_8_, net.minecraftforge.client.model.data.IModelData modelData) {
+ boolean flag = Minecraft.func_71379_u() && p_199324_3_.getLightValue(p_199324_1_, p_199324_4_) == 0 && p_199324_2_.isAmbientOcclusion(p_199324_3_);
+ modelData = p_199324_2_.getModelData(p_199324_1_, p_199324_4_, p_199324_3_, modelData);
+
try {
return flag ? this.func_199326_b(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_) : this.func_199325_c(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_);
@@ -120,6 +120,13 @@
- return flag ? this.func_199326_b(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_) : this.func_199325_c(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_);
+ return flag ? this.renderModelSmooth(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_, modelData) : this.renderModelFlat(p_199324_1_, p_199324_2_, p_199324_3_, p_199324_4_, p_199324_5_, p_199324_6_, p_199324_7_, p_199324_8_, modelData);
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.func_85055_a(throwable, "Tesselating block model");
CrashReportCategory crashreportcategory = crashreport.func_85058_a("Block model being tesselated");
@@ -58,7 +64,12 @@
}
}
+ @Deprecated
public boolean func_199326_b(IWorldReader p_199326_1_, IBakedModel p_199326_2_, IBlockState p_199326_3_, BlockPos p_199326_4_, BufferBuilder p_199326_5_, boolean p_199326_6_, Random p_199326_7_, long p_199326_8_) {
+ return renderModelSmooth(p_199326_1_, p_199326_2_, p_199326_3_, p_199326_4_, p_199326_5_, p_199326_6_, p_199326_7_, p_199326_8_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE);
+ }
+
+ public boolean renderModelSmooth(IWorldReader p_199326_1_, IBakedModel p_199326_2_, IBlockState p_199326_3_, BlockPos p_199326_4_, BufferBuilder p_199326_5_, boolean p_199326_6_, Random p_199326_7_, long p_199326_8_, net.minecraftforge.client.model.data.IModelData modelData) {
boolean flag = false;
float[] afloat = new float[EnumFacing.values().length * 2];
BitSet bitset = new BitSet(3);
@@ -66,7 +77,7 @@
for(EnumFacing enumfacing : EnumFacing.values()) {
p_199326_7_.setSeed(p_199326_8_);
- List<BakedQuad> list = p_199326_2_.func_200117_a(p_199326_3_, enumfacing, p_199326_7_);
+ List<BakedQuad> list = p_199326_2_.getQuads(p_199326_3_, enumfacing, p_199326_7_, modelData);
if (!list.isEmpty() && (!p_199326_6_ || Block.func_176225_a(p_199326_3_, p_199326_1_, p_199326_4_, enumfacing))) {
this.func_187492_a(p_199326_1_, p_199326_3_, p_199326_4_, p_199326_5_, list, afloat, bitset, blockmodelrenderer$ambientocclusionface);
flag = true;
@@ -74,7 +85,7 @@
}
p_199326_7_.setSeed(p_199326_8_);
- List<BakedQuad> list1 = p_199326_2_.func_200117_a(p_199326_3_, (EnumFacing)null, p_199326_7_);
+ List<BakedQuad> list1 = p_199326_2_.getQuads(p_199326_3_, (EnumFacing)null, p_199326_7_, modelData);
if (!list1.isEmpty()) {
this.func_187492_a(p_199326_1_, p_199326_3_, p_199326_4_, p_199326_5_, list1, afloat, bitset, blockmodelrenderer$ambientocclusionface);
flag = true;
@@ -83,13 +94,18 @@
return flag;
}
+ @Deprecated
public boolean func_199325_c(IWorldReader p_199325_1_, IBakedModel p_199325_2_, IBlockState p_199325_3_, BlockPos p_199325_4_, BufferBuilder p_199325_5_, boolean p_199325_6_, Random p_199325_7_, long p_199325_8_) {
+ return renderModelFlat(p_199325_1_, p_199325_2_, p_199325_3_, p_199325_4_, p_199325_5_, p_199325_6_, p_199325_7_, p_199325_8_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE);
+ }
+
+ public boolean renderModelFlat(IWorldReader p_199325_1_, IBakedModel p_199325_2_, IBlockState p_199325_3_, BlockPos p_199325_4_, BufferBuilder p_199325_5_, boolean p_199325_6_, Random p_199325_7_, long p_199325_8_, net.minecraftforge.client.model.data.IModelData modelData) {
boolean flag = false;
BitSet bitset = new BitSet(3);
for(EnumFacing enumfacing : EnumFacing.values()) {
p_199325_7_.setSeed(p_199325_8_);
- List<BakedQuad> list = p_199325_2_.func_200117_a(p_199325_3_, enumfacing, p_199325_7_);
+ List<BakedQuad> list = p_199325_2_.getQuads(p_199325_3_, enumfacing, p_199325_7_, modelData);
if (!list.isEmpty() && (!p_199325_6_ || Block.func_176225_a(p_199325_3_, p_199325_1_, p_199325_4_, enumfacing))) {
int i = p_199325_3_.func_185889_a(p_199325_1_, p_199325_4_.func_177972_a(enumfacing));
this.func_187496_a(p_199325_1_, p_199325_3_, p_199325_4_, i, false, p_199325_5_, list, bitset);
@@ -98,7 +114,7 @@
}
p_199325_7_.setSeed(p_199325_8_);
- List<BakedQuad> list1 = p_199325_2_.func_200117_a(p_199325_3_, (EnumFacing)null, p_199325_7_);
+ List<BakedQuad> list1 = p_199325_2_.getQuads(p_199325_3_, (EnumFacing)null, p_199325_7_, modelData);
if (!list1.isEmpty()) {
this.func_187496_a(p_199325_1_, p_199325_3_, p_199325_4_, -1, true, p_199325_5_, list1, bitset);
flag = true;
@@ -120,6 +136,13 @@
p_187492_8_.func_187491_a(p_187492_1_, p_187492_2_, p_187492_3_, bakedquad.func_178210_d(), p_187492_6_, p_187492_7_);
p_187492_4_.func_178981_a(bakedquad.func_178209_a());
p_187492_4_.func_178962_a(p_187492_8_.field_178207_c[0], p_187492_8_.field_178207_c[1], p_187492_8_.field_178207_c[2], p_187492_8_.field_178207_c[3]);
@ -23,7 +94,7 @@
if (bakedquad.func_178212_b()) {
int k = this.field_187499_a.func_186724_a(p_187492_2_, p_187492_1_, p_187492_3_, bakedquad.func_178211_c());
float f = (float)(k >> 16 & 255) / 255.0F;
@@ -229,10 +236,22 @@
@@ -229,10 +252,22 @@
float f = (float)(k >> 16 & 255) / 255.0F;
float f1 = (float)(k >> 8 & 255) / 255.0F;
float f2 = (float)(k & 255) / 255.0F;

View File

@ -9,7 +9,7 @@
this.field_175025_e = new BlockFluidRenderer();
}
@@ -40,7 +40,7 @@
@@ -40,12 +40,17 @@
if (p_175020_1_.func_185901_i() == EnumBlockRenderType.MODEL) {
IBakedModel ibakedmodel = this.field_175028_a.func_178125_b(p_175020_1_);
long i = p_175020_1_.func_209533_a(p_175020_2_);
@ -18,16 +18,26 @@
this.field_175027_c.func_199324_a(p_175020_4_, ibakedmodel1, p_175020_1_, p_175020_2_, Tessellator.func_178181_a().func_178180_c(), true, this.field_195476_e, i);
}
}
@@ -53,6 +53,8 @@
+ @Deprecated
public boolean func_195475_a(IBlockState p_195475_1_, BlockPos p_195475_2_, IWorldReader p_195475_3_, BufferBuilder p_195475_4_, Random p_195475_5_) {
+ return renderBlock(p_195475_1_, p_195475_2_, p_195475_3_, p_195475_4_, p_195475_5_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE);
+ }
+
+ public boolean renderBlock(IBlockState p_195475_1_, BlockPos p_195475_2_, IWorldReader p_195475_3_, BufferBuilder p_195475_4_, Random p_195475_5_, net.minecraftforge.client.model.data.IModelData modelData) {
try {
EnumBlockRenderType enumblockrendertype = p_195475_1_.func_185901_i();
if (enumblockrendertype == EnumBlockRenderType.INVISIBLE) {
@@ -53,7 +58,7 @@
} else {
switch(enumblockrendertype) {
case MODEL:
+ IBakedModel model = this.func_184389_a(p_195475_1_);
+ p_195475_1_ = p_195475_1_.func_177230_c().getExtendedState(p_195475_1_, p_195475_3_, p_195475_2_);
return this.field_175027_c.func_199324_a(p_195475_3_, this.func_184389_a(p_195475_1_), p_195475_1_, p_195475_2_, p_195475_4_, true, p_195475_5_, p_195475_1_.func_209533_a(p_195475_2_));
- return this.field_175027_c.func_199324_a(p_195475_3_, this.func_184389_a(p_195475_1_), p_195475_1_, p_195475_2_, p_195475_4_, true, p_195475_5_, p_195475_1_.func_209533_a(p_195475_2_));
+ return this.field_175027_c.renderModel(p_195475_3_, this.func_184389_a(p_195475_1_), p_195475_1_, p_195475_2_, p_195475_4_, true, p_195475_5_, p_195475_1_.func_209533_a(p_195475_2_), modelData);
case ENTITYBLOCK_ANIMATED:
return false;
@@ -105,4 +107,9 @@
default:
@@ -105,4 +110,9 @@
public void func_195410_a(IResourceManager p_195410_1_) {
this.field_175025_e.func_178268_a();
}

View File

@ -0,0 +1,26 @@
--- a/net/minecraft/client/renderer/chunk/ChunkRenderTask.java
+++ b/net/minecraft/client/renderer/chunk/ChunkRenderTask.java
@@ -19,11 +19,14 @@
private CompiledChunk field_178547_f;
private ChunkRenderTask.Status field_178548_g = ChunkRenderTask.Status.PENDING;
private boolean field_178554_h;
+ private java.util.Map<net.minecraft.util.math.BlockPos, net.minecraftforge.client.model.data.IModelData> modelData;
public ChunkRenderTask(RenderChunk p_i46560_1_, ChunkRenderTask.Type p_i46560_2_, double p_i46560_3_) {
this.field_178553_a = p_i46560_1_;
this.field_178549_d = p_i46560_2_;
this.field_188229_e = p_i46560_3_;
+
+ modelData = net.minecraftforge.client.model.ModelDataManager.getModelData(net.minecraft.client.Minecraft.func_71410_x().field_71441_e, new net.minecraft.util.math.ChunkPos(p_i46560_1_.func_178568_j()));
}
public ChunkRenderTask.Status func_178546_a() {
@@ -128,4 +131,8 @@
REBUILD_CHUNK,
RESORT_TRANSPARENCY;
}
+
+ public net.minecraftforge.client.model.data.IModelData getModelData(net.minecraft.util.math.BlockPos pos) {
+ return modelData.getOrDefault(pos, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE);
+ }
}

View File

@ -19,7 +19,7 @@
VisGraph lvt_11_1_ = new VisGraph();
HashSet lvt_12_1_ = Sets.newHashSet();
if (lvt_10_1_ != null) {
@@ -142,22 +143,23 @@
@@ -142,22 +143,24 @@
lvt_11_1_.func_178606_a(blockpos$mutableblockpos);
}
@ -41,13 +41,14 @@
IFluidState ifluidstate = lvt_10_1_.func_204610_c(blockpos$mutableblockpos);
- if (!ifluidstate.func_206888_e()) {
- BlockRenderLayer blockrenderlayer1 = ifluidstate.func_180664_k();
+ net.minecraftforge.client.model.data.IModelData modelData = p_178581_4_.getModelData(blockpos$mutableblockpos);
+ for(BlockRenderLayer blockrenderlayer1 : BlockRenderLayer.values()) {
+ net.minecraftforge.client.ForgeHooksClient.setRenderLayer(blockrenderlayer1);
+ if (!ifluidstate.func_206888_e() && ifluidstate.canRenderInLayer(blockrenderlayer1)) {
int j = blockrenderlayer1.ordinal();
BufferBuilder bufferbuilder = p_178581_4_.func_178545_d().func_179039_a(j);
if (!compiledchunk.func_178492_d(blockrenderlayer1)) {
@@ -168,17 +170,18 @@
@@ -168,17 +171,18 @@
aboolean[j] |= blockrendererdispatcher.func_205318_a(blockpos$mutableblockpos, lvt_10_1_, bufferbuilder, ifluidstate);
}
@ -64,7 +65,8 @@
this.func_178573_a(bufferbuilder1, blockpos);
}
aboolean[k] |= blockrendererdispatcher.func_195475_a(iblockstate, blockpos$mutableblockpos, lvt_10_1_, bufferbuilder1, random);
- aboolean[k] |= blockrendererdispatcher.func_195475_a(iblockstate, blockpos$mutableblockpos, lvt_10_1_, bufferbuilder1, random);
+ aboolean[k] |= blockrendererdispatcher.renderBlock(iblockstate, blockpos$mutableblockpos, lvt_10_1_, bufferbuilder1, random, modelData);
}
+ }
+ net.minecraftforge.client.ForgeHooksClient.setRenderLayer(null);

View File

@ -1,15 +1,17 @@
--- a/net/minecraft/client/renderer/model/IBakedModel.java
+++ b/net/minecraft/client/renderer/model/IBakedModel.java
@@ -10,7 +10,7 @@
@@ -10,7 +10,9 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
-public interface IBakedModel {
+public interface IBakedModel extends net.minecraftforge.client.extensions.IForgeBakedModel {
+
+ @Deprecated
List<BakedQuad> func_200117_a(@Nullable IBlockState p_200117_1_, @Nullable EnumFacing p_200117_2_, Random p_200117_3_);
boolean func_177555_b();
@@ -21,7 +21,8 @@
@@ -21,7 +23,8 @@
TextureAtlasSprite func_177554_e();

View File

@ -1,11 +0,0 @@
--- a/net/minecraft/world/chunk/ChunkSection.java
+++ b/net/minecraft/world/chunk/ChunkSection.java
@@ -35,6 +35,8 @@
}
public void func_177484_a(int p_177484_1_, int p_177484_2_, int p_177484_3_, IBlockState p_177484_4_) {
+ if (p_177484_4_ instanceof net.minecraftforge.common.property.IExtendedBlockState)
+ p_177484_4_ = ((net.minecraftforge.common.property.IExtendedBlockState)p_177484_4_).getClean();
IBlockState iblockstate = this.func_177485_a(p_177484_1_, p_177484_2_, p_177484_3_);
IFluidState ifluidstate = this.func_206914_b(p_177484_1_, p_177484_2_, p_177484_3_);
IFluidState ifluidstate1 = p_177484_4_.func_204520_s();

View File

@ -20,14 +20,28 @@
package net.minecraftforge.client;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.chunk.RenderChunkCache;
import net.minecraft.client.renderer.texture.NativeImage;
@ -36,13 +50,10 @@ import net.minecraft.resources.IResourceManager;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.data.IModelData;
public class MinecraftForgeClient
{

View File

@ -19,17 +19,34 @@
package net.minecraftforge.client.extensions;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldReader;
import net.minecraftforge.client.model.data.IModelData;
public interface IForgeBakedModel
{
{
default IBakedModel getBakedModel()
{
return (IBakedModel) this;
}
@Nonnull
default List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, @Nonnull Random rand, @Nonnull IModelData extraData)
{
return getBakedModel().getQuads(state, side, rand);
}
default boolean isAmbientOcclusion(IBlockState state) { return getBakedModel().isAmbientOcclusion(); }
/*
@ -40,4 +57,9 @@ public interface IForgeBakedModel
{
return net.minecraftforge.client.ForgeHooksClient.handlePerspective(getBakedModel(), cameraTransformType);
}
default @Nonnull IModelData getModelData(@Nonnull IWorldReader world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull IModelData tileData)
{
return tileData;
}
}

View File

@ -0,0 +1,101 @@
package net.minecraftforge.client.model;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraft.client.Minecraft;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraftforge.client.model.data.IModelData;
public class ModelDataManager
{
private static WeakReference<World> currentWorld = new WeakReference<>(null);
private static final Map<ChunkPos, Set<BlockPos>> needModelDataRefresh = new HashMap<>();
private static final LoadingCache<ChunkPos, Map<BlockPos, IModelData>> modelDataCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.concurrencyLevel(5)
.expireAfterAccess(30, TimeUnit.SECONDS)
.build(new CacheLoader<ChunkPos, Map<BlockPos, IModelData>>(){
@Override
public Map<BlockPos, IModelData> load(@Nonnull ChunkPos key)
{
return new ConcurrentHashMap<>();
}
});
private static void cleanCaches(World world)
{
if (world != currentWorld.get())
{
currentWorld = new WeakReference<>(world);
needModelDataRefresh.clear();
modelDataCache.invalidateAll();
}
}
public static void requestModelDataRefresh(TileEntity te)
{
World world = te.getWorld();
Preconditions.checkNotNull(world, "Tile entity world must not be null");
Preconditions.checkArgument(world == Minecraft.getInstance().world, "Cannot request a model data refresh for a world other than the current client world");
synchronized (needModelDataRefresh)
{
cleanCaches(world);
needModelDataRefresh.computeIfAbsent(new ChunkPos(te.getPos()), $ -> Collections.synchronizedSet(new HashSet<>()))
.add(te.getPos());
}
}
private static void refreshModelData(World world, ChunkPos chunk)
{
Set<BlockPos> needUpdate;
synchronized (needModelDataRefresh)
{
cleanCaches(world);
needUpdate = needModelDataRefresh.remove(chunk);
}
if (needUpdate != null)
{
Map<BlockPos, IModelData> data = modelDataCache.getUnchecked(chunk);
for (BlockPos pos : needUpdate)
{
TileEntity toUpdate = world.getTileEntity(pos);
if (toUpdate != null)
{
data.put(pos, toUpdate.getModelData());
}
}
}
}
public static @Nullable IModelData getModelData(World world, BlockPos pos)
{
return getModelData(world, new ChunkPos(pos)).get(pos);
}
public static Map<BlockPos, IModelData> getModelData(World world, ChunkPos pos)
{
refreshModelData(world, pos);
return modelDataCache.getUnchecked(pos);
}
}

View File

@ -43,13 +43,13 @@ import net.minecraft.resources.IResourceManager;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.fluids.Fluid;
import org.apache.commons.lang3.tuple.Pair;
@ -103,7 +103,7 @@ public final class ModelFluid implements IUnbakedModel
bakedTextureGetter.apply(fluid.getFlowing()),
Optional.ofNullable(fluid.getOverlay()).map(bakedTextureGetter),
fluid.isLighterThanAir(),
Optional.empty()
null
);
}
@ -157,7 +157,7 @@ public final class ModelFluid implements IUnbakedModel
}
});
public CachingBakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional<TextureAtlasSprite> overlay, boolean gas, Optional<IExtendedBlockState> stateOption)
public CachingBakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional<TextureAtlasSprite> overlay, boolean gas, Optional<IModelData> stateOption)
{
super(transformation, transforms, format, color, still, flowing, overlay, gas, stateOption.isPresent(), getCorners(stateOption), getFlow(stateOption), getOverlay(stateOption));
}
@ -171,12 +171,12 @@ public final class ModelFluid implements IUnbakedModel
* while also providing good use of the available value range.
* (For fluids with default quanta, this evenly divides the per-block intervals of 1/9 by 96)
*/
private static int[] getCorners(Optional<IExtendedBlockState> stateOption)
private static int[] getCorners(Optional<IModelData> stateOption)
{
int[] cornerRound = {0, 0, 0, 0};
if (stateOption.isPresent())
{
IExtendedBlockState state = stateOption.get();
IModelData state = stateOption.get();
for (int i = 0; i < 4; i++)
{
Float level = null; // TODO fluids state.getValue(BlockFluidBase.LEVEL_CORNERS[i]);
@ -193,7 +193,7 @@ public final class ModelFluid implements IUnbakedModel
* The value is currently stored as the angle rounded to the nearest degree.
* A value of -1000 is used to signify no flow.
*/
private static int getFlow(Optional<IExtendedBlockState> stateOption)
private static int getFlow(Optional<IModelData> stateOption)
{
Float flow = -1000f;
if (stateOption.isPresent())
@ -213,12 +213,12 @@ public final class ModelFluid implements IUnbakedModel
* instead of the normal "flowing" texture (if applicable for that fluid).
* The sides are stored here by their regular horizontal index.
*/
private static boolean[] getOverlay(Optional<IExtendedBlockState> stateOption)
private static boolean[] getOverlay(Optional<IModelData> stateOption)
{
boolean[] overlaySides = new boolean[4];
if (stateOption.isPresent())
{
IExtendedBlockState state = stateOption.get();
IModelData state = stateOption.get();
for (int i = 0; i < 4; i++)
{
Boolean overlay = null; // TODO fluids state.getValue(BlockFluidBase.SIDE_OVERLAYS[i]);
@ -229,11 +229,11 @@ public final class ModelFluid implements IUnbakedModel
}
@Override
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand)
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand, IModelData modelData)
{
if (side != null && state instanceof IExtendedBlockState)
if (side != null)
{
Optional<IExtendedBlockState> exState = Optional.of((IExtendedBlockState)state);
Optional<IModelData> exState = Optional.of(modelData);
int[] cornerRound = getCorners(exState);
int flowRound = getFlow(exState);

View File

@ -77,12 +77,12 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.IRegistry;
import net.minecraftforge.client.model.animation.AnimationItemOverrideList;
import net.minecraftforge.client.model.animation.ModelBlockAnimation;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.Models;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.model.animation.IClip;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.client.ClientModLoader;
@ -510,20 +510,12 @@ public final class ModelLoader extends ModelBakery
private final ItemOverrideList overrides = new AnimationItemOverrideList(VanillaModelWrapper.this, modelState, format, bakedTextureGetter, super.getOverrides());
@Override
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand)
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand, IModelData modelData)
{
if(state instanceof IExtendedBlockState)
IModelState newState = modelData.getData(Properties.AnimationProperty);
if(newState != null)
{
IExtendedBlockState exState = (IExtendedBlockState)state;
if(exState.getUnlistedNames().contains(Properties.AnimationProperty))
{
IModelState newState = exState.getValue(Properties.AnimationProperty);
IExtendedBlockState newExState = (IExtendedBlockState) exState.withProperty(Properties.AnimationProperty, null);
if(newState != null)
{
return VanillaModelWrapper.this.bake(modelGetter, bakedTextureGetter, new ModelStateComposition(modelState, newState), uvlock, format).getQuads(newExState, side, rand);
}
}
return VanillaModelWrapper.this.bake(modelGetter, bakedTextureGetter, new ModelStateComposition(modelState, newState), uvlock, format).getQuads(state, side, rand, modelData);
}
return super.getQuads(state, side, rand);
}

View File

@ -19,26 +19,26 @@
package net.minecraftforge.client.model.animation;
import java.util.Random;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldReader;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.ModelDataManager;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.animation.Event;
import net.minecraftforge.common.animation.IEventHandler;
import net.minecraftforge.common.model.animation.CapabilityAnimation;
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import net.minecraftforge.common.util.LazyOptional;
import java.util.Random;
/**
* Generic {@link TileGameRenderer} that works with the Forge model system and animations.
*/
@ -58,30 +58,23 @@ public class TileEntityRendererAnimation<T extends TileEntity> extends TileEntit
BlockPos pos = te.getPos();
IWorldReader world = MinecraftForgeClient.getRegionRenderCache(te.getWorld(), pos);
IBlockState state = world.getBlockState(pos);
if(state.getBlock().getStateContainer().getProperties().contains(Properties.StaticProperty))
IBakedModel model = blockRenderer.getBlockModelShapes().getModel(state);
IModelData data = model.getModelData(world, pos, state, ModelDataManager.getModelData(te.getWorld(), pos));
if (data.hasProperty(Properties.AnimationProperty))
{
state = state.with(Properties.StaticProperty, false);
}
if(state instanceof IExtendedBlockState)
{
IExtendedBlockState exState = (IExtendedBlockState)state;
if(exState.getUnlistedNames().contains(Properties.AnimationProperty))
{
float time = Animation.getWorldTime(getWorld(), partialTick);
cap
.map(asm -> asm.apply(time))
.ifPresent(pair -> {
handleEvents(te, time, pair.getRight());
float time = Animation.getWorldTime(getWorld(), partialTick);
cap
.map(asm -> asm.apply(time))
.ifPresent(pair -> {
handleEvents(te, time, pair.getRight());
// TODO: caching?
IBakedModel model = blockRenderer.getBlockModelShapes().getModel(exState.getClean());
IExtendedBlockState animState = (IExtendedBlockState) exState.withProperty(Properties.AnimationProperty, pair.getLeft());
// TODO: caching?
data.setData(Properties.AnimationProperty, pair.getLeft());
renderer.setTranslation(x - pos.getX(), y - pos.getY(), z - pos.getZ());
renderer.setTranslation(x - pos.getX(), y - pos.getY(), z - pos.getZ());
blockRenderer.getBlockModelRenderer().renderModel(world, model, animState, pos, renderer, false, new Random(), 42);
});
}
blockRenderer.getBlockModelRenderer().renderModel(world, model, state, pos, renderer, false, new Random(), 42, data);
});
}
}

View File

@ -27,13 +27,33 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.base.Objects;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
@ -59,6 +79,8 @@ import net.minecraftforge.client.model.b3d.B3DModel.Mesh;
import net.minecraftforge.client.model.b3d.B3DModel.Node;
import net.minecraftforge.client.model.b3d.B3DModel.Texture;
import net.minecraftforge.client.model.b3d.B3DModel.Vertex;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.common.model.IModelPart;
import net.minecraftforge.common.model.IModelState;
@ -66,30 +88,8 @@ import net.minecraftforge.common.model.Models;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.model.animation.IClip;
import net.minecraftforge.common.model.animation.IJoint;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.Function;
import com.google.common.base.Objects;
import java.util.Optional;
import java.util.Random;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/*
* Loader for Blitz3D models.
* To enable for your mod call instance.addDomain(modId).
@ -599,7 +599,7 @@ public enum B3DLoader implements ICustomModelLoader
}
}
private static final class BakedWrapper implements IBakedModel
private static final class BakedWrapper implements IDynamicBakedModel
{
private final Node<?> node;
private final IModelState state;
@ -647,34 +647,27 @@ public enum B3DLoader implements ICustomModelLoader
}
@Override
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand)
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand, IModelData data)
{
if(side != null) return ImmutableList.of();
IModelState modelState = this.state;
if(state instanceof IExtendedBlockState)
IModelState newState = data.getData(Properties.AnimationProperty);
if(newState != null)
{
IExtendedBlockState exState = (IExtendedBlockState)state;
if(exState.getUnlistedNames().contains(Properties.AnimationProperty))
// FIXME: should animation state handle the parent state, or should it remain here?
IModelState parent = this.state;
if(parent instanceof B3DState)
{
// FIXME: should animation state handle the parent state, or should it remain here?
IModelState parent = this.state;
if(parent instanceof B3DState)
{
B3DState ps = (B3DState)parent;
parent = ps.getParent();
}
IModelState newState = exState.getValue(Properties.AnimationProperty);
if(newState != null)
{
if (parent == null)
{
modelState = newState;
}
else
{
modelState = new ModelStateComposition(parent, newState);
}
}
B3DState ps = (B3DState)parent;
parent = ps.getParent();
}
if (parent == null)
{
modelState = newState;
}
else
{
modelState = new ModelStateComposition(parent, newState);
}
}
if(quads == null)

View File

@ -0,0 +1,15 @@
package net.minecraftforge.client.model.data;
public enum EmptyModelData implements IModelData
{
INSTANCE;
@Override
public boolean hasProperty(ModelProperty<?> prop) { return false; }
@Override
public <T> T getData(ModelProperty<T> prop) { return null; }
@Override
public <T> T setData(ModelProperty<T> prop, T data) { return null; }
}

View File

@ -0,0 +1,29 @@
package net.minecraftforge.client.model.data;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.util.EnumFacing;
/**
* Convenience interface with default implementation of {@link IBakedModel#getQuads(net.minecraft.block.state.IBlockState, net.minecraft.util.EnumFacing, java.util.Random)}.
*/
public interface IDynamicBakedModel extends IBakedModel
{
@Override
default @Nonnull List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, @Nonnull Random rand)
{
return getQuads(state, side, rand, EmptyModelData.INSTANCE);
}
// Force this to be overriden otherwise this introduces a default cycle between the two overloads.
@Override
@Nonnull
List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, @Nonnull Random rand, @Nonnull IModelData extraData);
}

View File

@ -0,0 +1,25 @@
package net.minecraftforge.client.model.data;
import javax.annotation.Nullable;
public interface IModelData
{
/**
* Check if this data has a property, even if the value is {@code null}. Can be
* used by code that intends to fill in data for a render pipeline, such as the
* forge animation system.
* <p>
* IMPORTANT: {@link #getData(ModelProperty)} <em>can</em> return {@code null}
* even if this method returns {@code true}.
*
* @param prop The property to check for inclusion in this model data
* @return {@code true} if this data has the given property, even if no value is present
*/
boolean hasProperty(ModelProperty<?> prop);
@Nullable
<T> T getData(ModelProperty<T> prop);
@Nullable
<T> T setData(ModelProperty<T> prop, T data);
}

View File

@ -0,0 +1,58 @@
package net.minecraftforge.client.model.data;
import java.util.IdentityHashMap;
import java.util.Map;
import com.google.common.base.Preconditions;
public class ModelDataMap implements IModelData
{
private final Map<ModelProperty<?>, Object> backingMap;
private ModelDataMap(Map<ModelProperty<?>, Object> map)
{
this.backingMap = new IdentityHashMap<>(map);
}
@Override
public boolean hasProperty(ModelProperty<?> prop)
{
return backingMap.containsKey(prop);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getData(ModelProperty<T> prop)
{
return (T) backingMap.get(prop);
}
@SuppressWarnings("unchecked")
@Override
public <T> T setData(ModelProperty<T> prop, T data)
{
Preconditions.checkArgument(prop.test(data), "Value is invalid for this property");
return (T) backingMap.put(prop, data);
}
public static class Builder
{
private final Map<ModelProperty<?>, Object> defaults = new IdentityHashMap<>();
public Builder withProperty(ModelProperty<?> prop)
{
return withInitial(prop, null);
}
public <T> Builder withInitial(ModelProperty<T> prop, T data)
{
this.defaults.put(prop, data);
return this;
}
public ModelDataMap build()
{
return new ModelDataMap(defaults);
}
}
}

View File

@ -0,0 +1,23 @@
package net.minecraftforge.client.model.data;
import java.util.function.Predicate;
import com.google.common.base.Predicates;
public class ModelProperty<T> implements Predicate<T> {
private final Predicate<T> pred;
public ModelProperty() {
this(Predicates.alwaysTrue());
}
public ModelProperty(Predicate<T> pred) {
this.pred = pred;
}
@Override
public boolean test(T t) {
return pred.test(t);
}
}

View File

@ -54,13 +54,13 @@ import net.minecraft.resources.IResourceManager;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.*;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.common.model.IModelPart;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.Models;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.common.property.Properties;
import org.apache.commons.lang3.tuple.Pair;
@ -1255,36 +1255,7 @@ public class OBJModel implements IUnbakedModel
}
}
@Deprecated
public enum OBJProperty implements IUnlistedProperty<OBJState>
{
INSTANCE;
@Override
public String getName()
{
return "OBJProperty";
}
@Override
public boolean isValid(OBJState value)
{
return value instanceof OBJState;
}
@Override
public Class<OBJState> getType()
{
return OBJState.class;
}
@Override
public String valueToString(OBJState value)
{
return value.toString();
}
}
public class OBJBakedModel implements IBakedModel
public class OBJBakedModel implements IDynamicBakedModel
{
private final OBJModel model;
private IModelState state;
@ -1308,26 +1279,18 @@ public class OBJModel implements IUnbakedModel
// FIXME: merge with getQuads
@Override
public List<BakedQuad> getQuads(IBlockState blockState, EnumFacing side, Random rand)
public List<BakedQuad> getQuads(IBlockState blockState, EnumFacing side, Random rand, IModelData modelData)
{
if (side != null) return ImmutableList.of();
if (quads == null)
{
quads = buildQuads(this.state);
}
if (blockState instanceof IExtendedBlockState)
IModelState newState = modelData.getData(Properties.AnimationProperty);
if (newState != null)
{
IExtendedBlockState exState = (IExtendedBlockState) blockState;
if (exState.getUnlistedNames().contains(Properties.AnimationProperty))
{
IModelState newState = exState.getValue(Properties.AnimationProperty);
if (newState != null)
{
newState = new ModelStateComposition(this.state, newState);
return buildQuads(newState);
}
}
newState = new ModelStateComposition(this.state, newState);
return buildQuads(newState);
}
return quads;
}

View File

@ -19,6 +19,8 @@
package net.minecraftforge.common.extensions;
import javax.annotation.Nonnull;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
@ -29,6 +31,9 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.ModelDataManager;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
public interface IForgeTileEntity extends ICapabilitySerializable<NBTTagCompound>
@ -86,7 +91,10 @@ public interface IForgeTileEntity extends ICapabilitySerializable<NBTTagCompound
* Called when this is first added to the world (by {@link World#addTileEntity(TileEntity)}).
* Override instead of adding {@code if (firstTick)} stuff in update.
*/
default void onLoad(){}
default void onLoad()
{
requestModelDataUpdate();
}
default boolean shouldRenderInPass(int pass)
{
@ -168,4 +176,19 @@ public interface IForgeTileEntity extends ICapabilitySerializable<NBTTagCompound
{
return false;
}
default void requestModelDataUpdate()
{
TileEntity te = getTileEntity();
World world = te.getWorld();
if (world != null && world.isRemote)
{
ModelDataManager.requestModelDataRefresh(te);
}
}
default @Nonnull IModelData getModelData()
{
return EmptyModelData.INSTANCE;
}
}

View File

@ -1,178 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.property;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import net.minecraft.block.Block;
import net.minecraft.block.state.BlockState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.state.AbstractStateHolder;
import net.minecraft.state.IProperty;
import net.minecraft.state.IStateHolder;
import net.minecraft.state.StateContainer;
// TODO Extended states gotta go, I doubt this works at all
public class ExtendedStateContainer<O, S extends IExtendedState<S>> extends StateContainer<O, S>
{
private final ImmutableSet<IUnlistedProperty<?>> unlistedProperties;
public <A extends AbstractStateHolder<O, S>> ExtendedStateContainer(O blockIn, StateContainer.IFactory<O, S, A> stateFactory, net.minecraft.state.IProperty<?>[] properties, IUnlistedProperty<?>[] unlistedProperties)
{
super(blockIn, getProxyFactory(unlistedProperties, stateFactory), buildListedMap(properties));// TODO Unlisted properties?, buildUnlistedMap(unlistedProperties));
ImmutableSet.Builder<IUnlistedProperty<?>> builder = ImmutableSet.builder();
for(IUnlistedProperty<?> property : unlistedProperties)
{
builder.add(property);
}
this.unlistedProperties = builder.build();
}
private static <O, S extends IExtendedState<S>, A extends AbstractStateHolder<O, S>>
StateContainer.IFactory<O, S, AbstractStateHolder<O,S>> getProxyFactory(IUnlistedProperty<?>[] unlistedProperties, StateContainer.IFactory<O, S, A> proxy)
{
return (o, props) -> {
if (unlistedProperties == null || unlistedProperties.length == 0) return proxy.create(o, props);
return new ExtendedStateHolder<O, S>(o, props, buildUnlistedMap(unlistedProperties), null);
};
}
public Collection<IUnlistedProperty<?>> getUnlistedProperties()
{
return unlistedProperties;
}
private static Map<String, IProperty<?>> buildListedMap(IProperty<?>[] properties)
{
return Arrays.stream(properties).collect(Collectors.toMap(IProperty::getName, Function.identity()));
}
private static ImmutableMap<IUnlistedProperty<?>, Optional<?>> buildUnlistedMap(IUnlistedProperty<?>[] unlistedProperties)
{
ImmutableMap.Builder<IUnlistedProperty<?>, Optional<?>> builder = ImmutableMap.builder();
for(IUnlistedProperty<?> p : unlistedProperties)
{
builder.put(p, Optional.empty());
}
return builder.build();
}
protected static class ExtendedStateHolder<O, S extends IExtendedState<S>> extends AbstractStateHolder<O, S> implements IExtendedState<S>
{
private final ImmutableMap<IUnlistedProperty<?>, Optional<?>> unlistedProperties;
private S cleanState;
protected ExtendedStateHolder(O block, ImmutableMap<IProperty<?>, Comparable<?>> properties, ImmutableMap<IUnlistedProperty<?>, Optional<?>> unlistedProperties, S clean)
{
super(block, properties);
this.unlistedProperties = unlistedProperties;
this.cleanState = clean == null ? (S) this : clean;
}
@Override
@Nonnull
public <T extends Comparable<T>, V extends T> S with(@Nonnull IProperty<T> property, @Nonnull V value)
{
S clean = super.with(property, value);
if (clean == this.cleanState) {
return (S) this;
}
if (this == this.cleanState)
{ // no dynamic properties present, looking up in the normal table
return clean;
}
return (S) new ExtendedStateHolder(object, ((IStateHolder)clean).getValues(), unlistedProperties, this.cleanState);
}
@Override
public <V> S withProperty(IUnlistedProperty<V> property, @Nullable V value)
{
Optional<?> oldValue = unlistedProperties.get(property);
if (oldValue == null)
{
throw new IllegalArgumentException("Cannot set unlisted property " + property + " as it does not exist in " + this);
}
if (Objects.equals(oldValue.orElse(null), value))
{
return (S) this;
}
if (!property.isValid(value))
{
throw new IllegalArgumentException("Cannot set unlisted property " + property + " to " + value + " on object " + object + ", it is not an allowed value");
}
boolean clean = true;
ImmutableMap.Builder<IUnlistedProperty<?>, Optional<?>> builder = ImmutableMap.builder();
for (Map.Entry<IUnlistedProperty<?>, Optional<?>> entry : unlistedProperties.entrySet())
{
IUnlistedProperty<?> key = entry.getKey();
Optional<?> newValue = key.equals(property) ? Optional.ofNullable(value) : entry.getValue();
if (newValue.isPresent()) clean = false;
builder.put(key, newValue);
}
if (clean)
{ // no dynamic properties, lookup normal state
return (S) cleanState;
}
return (S) new ExtendedStateHolder(object, getValues(), builder.build(), this.cleanState);
}
@Override
public Collection<IUnlistedProperty<?>> getUnlistedNames()
{
return unlistedProperties.keySet();
}
@Override
@Nullable
public <V> V getValue(IUnlistedProperty<V> property)
{
Optional<?> value = unlistedProperties.get(property);
if (value == null)
{
throw new IllegalArgumentException("Cannot get unlisted property " + property + " as it does not exist in " + this);
}
return property.getType().cast(value.orElse(null));
}
public ImmutableMap<IUnlistedProperty<?>, Optional<?>> getUnlistedProperties()
{
return unlistedProperties;
}
@Override
public S getClean()
{
return cleanState;
}
}
}

View File

@ -1,27 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.property;
import net.minecraft.block.state.IBlockState;
public interface IExtendedBlockState extends IExtendedState<IBlockState>, IBlockState
{
}

View File

@ -1,41 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.property;
import java.util.Collection;
import net.minecraft.block.state.IBlockState;
import net.minecraft.state.IStateHolder;
import java.util.Optional;
import com.google.common.collect.ImmutableMap;
public interface IExtendedState<C> extends IStateHolder<C>
{
Collection<IUnlistedProperty<?>> getUnlistedNames();
<V>V getValue(IUnlistedProperty<V> property);
<V>C withProperty(IUnlistedProperty<V> property, V value);
ImmutableMap<IUnlistedProperty<?>, Optional<?>> getUnlistedProperties();
C getClean();
}

View File

@ -1,31 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.property;
public interface IUnlistedProperty<V>
{
String getName();
boolean isValid(V value);
Class<V> getType();
String valueToString(V value);
}

View File

@ -20,7 +20,7 @@
package net.minecraftforge.common.property;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.IProperty;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.common.model.IModelState;
public class Properties
@ -33,54 +33,5 @@ public class Properties
/**
* Property holding the IModelState used for animating the model in the TESR.
*/
public static final IUnlistedProperty<IModelState> AnimationProperty = new IUnlistedProperty<IModelState>()
{
@Override
public String getName() { return "forge_animation"; }
@Override
public boolean isValid(IModelState state) { return true; }
@Override
public Class<IModelState> getType() { return IModelState.class; }
@Override
public String valueToString(IModelState state) { return state.toString(); }
};
public static <V extends Comparable<V>> IUnlistedProperty<V> toUnlisted(IProperty<V> property)
{
return new PropertyAdapter<V>(property);
}
public static class PropertyAdapter<V extends Comparable<V>> implements IUnlistedProperty<V>
{
private final IProperty<V> parent;
public PropertyAdapter(IProperty<V> parent)
{
this.parent = parent;
}
@Override
public String getName()
{
return parent.getName();
}
@Override
public boolean isValid(V value)
{
return parent.getAllowedValues().contains(value);
}
@Override
public Class<V> getType()
{
return parent.getValueClass();
}
@Override
public String valueToString(V value)
{
return parent.getName(value);
}
}
public static final ModelProperty<IModelState> AnimationProperty = new ModelProperty<IModelState>();
}

View File

@ -1,70 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.property;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Range;
public class PropertyFloat implements IUnlistedProperty<Float>
{
private final String name;
private final Predicate<Float> validator;
public PropertyFloat(String name)
{
this(name, Predicates.alwaysTrue());
}
public PropertyFloat(String name, float min, float max)
{
this(name, Range.closed(min, max));
}
public PropertyFloat(String name, Predicate<Float> validator)
{
this.name = name;
this.validator = validator;
}
@Override
public String getName()
{
return name;
}
@Override
public boolean isValid(Float value)
{
return validator.apply(value);
}
@Override
public Class<Float> getType()
{
return Float.class;
}
@Override
public String valueToString(Float value)
{
return value.toString();
}
}

View File

@ -0,0 +1,5 @@
{
"variants": {
"": { "model": "forge:modeltest" }
}
}

View File

@ -4,6 +4,11 @@ net/minecraft/block/BlockRailPowered.<init>(Lnet/minecraft/block/Block$Propertie
net/minecraft/block/BlockRedstoneWire.canConnectTo(Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)Z=|p_176343_0_,world,pos,p_176343_1_
net/minecraft/client/multiplayer/WorldClient.removeEntity(Lnet/minecraft/entity/Entity;Z)V=|p_72900_1_,keepData
net/minecraft/client/renderer/BlockRendererDispatcher.renderBlock(Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/world/IWorldReader;Lnet/minecraft/client/renderer/BufferBuilder;Ljava/util/Random;Lnet/minecraftforge/client/model/data/IModelData;)Z=|p_195475_1_,p_195475_2_,p_195475_3_,p_195475_4_,p_195475_5_,modelData
net/minecraft/client/renderer/BlockModelRenderer.renderModel(Lnet/minecraft/world/IWorldReader;Lnet/minecraft/client/renderer/model/IBakedModel;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/renderer/BufferBuilder;ZLjava/util/Random;JLnet/minecraftforge/client/model/data/IModelData;)Z=|p_199324_1_,p_199324_2_,p_199324_3_,p_199324_4_,p_199324_5_,p_199324_6_,p_199324_7_,p_199324_8_,modelData
net/minecraft/client/renderer/BlockModelRenderer.renderModelSmooth(Lnet/minecraft/world/IWorldReader;Lnet/minecraft/client/renderer/model/IBakedModel;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/renderer/BufferBuilder;ZLjava/util/Random;JLnet/minecraftforge/client/model/data/IModelData;)Z=|p_199326_1_,p_199326_2_,p_199326_3_,p_199326_4_,p_199326_5_,p_199326_6_,p_199326_7_,p_199326_8_,modelData
net/minecraft/client/renderer/BlockModelRenderer.renderModelFlat(Lnet/minecraft/world/IWorldReader;Lnet/minecraft/client/renderer/model/IBakedModel;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/renderer/BufferBuilder;ZLjava/util/Random;JLnet/minecraftforge/client/model/data/IModelData;)Z=|p_199325_1_,p_199325_2_,p_199325_3_,p_199325_4_,p_199325_5_,p_199325_6_,p_199325_7_,p_199325_8_,modelData
net/minecraft/client/renderer/model/BakedQuad.<init>([IILnet/minecraft/util/EnumFacing;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;ZLnet/minecraft/client/renderer/vertex/VertexFormat;)V=|p_i46574_1_,p_i46574_2_,p_i46574_3_,p_i46574_4_,applyDiffuseLighting,format
net/minecraft/client/renderer/model/FaceBakery.makeBakedQuad(Lnet/minecraft/client/renderer/Vector3f;Lnet/minecraft/client/renderer/Vector3f;Lnet/minecraft/client/renderer/model/BlockPartFace;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/util/EnumFacing;Lnet/minecraftforge/common/model/ITransformation;Lnet/minecraft/client/renderer/model/BlockPartRotation;ZZ)Lnet/minecraft/client/renderer/model/BakedQuad;=|p_199332_1_,p_199332_2_,p_199332_3_,p_199332_4_,p_199332_5_,p_199332_6_,p_199332_7_,p_199332_8_,p_199332_9_
net/minecraft/client/renderer/model/FaceBakery.makeQuadVertexData(Lnet/minecraft/client/renderer/model/BlockFaceUV;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/util/EnumFacing;[FLnet/minecraftforge/common/model/ITransformation;Lnet/minecraft/client/renderer/model/BlockPartRotation;Z)[I=|p_188012_1_,p_188012_2_,p_188012_3_,p_188012_4_,p_188012_5_,p_188012_6_,p_188012_7_

View File

@ -0,0 +1,184 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.debug.client.model;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.MissingTextureSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.init.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.model.ModelDataManager;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@Mod(ModelDataTest.MODID)
public class ModelDataTest
{
public static final String MODID = "forgedebugmodeldata";
public static final String VERSION = "1.0";
private static final ModelProperty<Boolean> MAGIC_PROP = new ModelProperty<Boolean>();
public ModelDataTest()
{
final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addGenericListener(Block.class, this::registerBlocks);
modEventBus.addGenericListener(TileEntityType.class, this::registerTileEntities);
MinecraftForge.EVENT_BUS.addListener(this::modelBake);
}
public void modelBake(ModelBakeEvent event)
{
final IBakedModel stone = event.getModelRegistry().get(new ModelResourceLocation("minecraft:stone"));
final IBakedModel dirt = event.getModelRegistry().get(new ModelResourceLocation("minecraft:dirt"));
final IBakedModel old = event.getModelRegistry().get(new ModelResourceLocation("forge:modeltest"));
event.getModelRegistry().put(new ModelResourceLocation("forge:modeltest"), new IDynamicBakedModel()
{
@Override
public boolean isGui3d()
{
return false;
}
@Override
public boolean isBuiltInRenderer()
{
return false;
}
@Override
public boolean isAmbientOcclusion()
{
return true;
}
@Override
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, Random rand, IModelData modelData)
{
return modelData.getData(MAGIC_PROP) ? stone.getQuads(state, side, rand, modelData) : dirt.getQuads(state, side, rand, modelData);
}
@Override
public TextureAtlasSprite getParticleTexture()
{
return MissingTextureSprite.getSprite();
}
@Override
public ItemOverrideList getOverrides()
{
return null;
}
@Override
@Nonnull
public IModelData getModelData(@Nonnull IWorldReader world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull IModelData tileData)
{
if (world.getBlockState(pos.down()).getBlock() == Blocks.AIR)
{
tileData.setData(MAGIC_PROP, !tileData.getData(MAGIC_PROP));
}
return tileData;
}
});
}
private static final TileEntityType<Tile> TILE_TYPE = TileEntityType.Builder.create(Tile::new).build(null);
private static class Tile extends TileEntity implements ITickable
{
public Tile()
{
super(TILE_TYPE);
}
private int counter;
@Override
public void tick()
{
if (world.isRemote && counter++ == 100)
{
ModelDataManager.requestModelDataRefresh(this);
world.markBlockRangeForRenderUpdate(getPos(), getPos());
}
}
@Override
public IModelData getModelData()
{
return new ModelDataMap.Builder().withInitial(MAGIC_PROP, counter < 100).build();
}
}
public void registerBlocks(RegistryEvent.Register<Block> event)
{
event.getRegistry().register(new BlockContainer(Block.Properties.create(Material.ROCK))
{
@Override
@Nullable
public TileEntity createNewTileEntity(IBlockReader worldIn)
{
return new Tile();
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state)
{
return EnumBlockRenderType.MODEL;
}
}.setRegistryName("forge:modeltest"));
}
public void registerTileEntities(RegistryEvent.Register<TileEntityType<?>> event)
{
event.getRegistry().register(TILE_TYPE.setRegistryName("forge:modeltest"));
}
}