Merge pull request #2282 from bonii-xx/dynbucket
Add a dynamic bucket model that displays the animated liquid contained
This commit is contained in:
commit
c7790f7b35
22 changed files with 958 additions and 0 deletions
|
@ -104,6 +104,7 @@ public class ForgeGuiFactory implements IModGuiFactory
|
|||
{
|
||||
List<IConfigElement> list = new ArrayList<IConfigElement>();
|
||||
list.add(new DummyCategoryElement("forgeCfg", "forge.configgui.ctgy.forgeGeneralConfig", GeneralEntry.class));
|
||||
list.add(new DummyCategoryElement("forgeClientCfg", "forge.configgui.ctgy.forgeClientConfig", ClientEntry.class));
|
||||
list.add(new DummyCategoryElement("forgeChunkLoadingCfg", "forge.configgui.ctgy.forgeChunkLoadingConfig", ChunkLoaderEntry.class));
|
||||
list.add(new DummyCategoryElement("forgeVersionCheckCfg", "forge.configgui.ctgy.VersionCheckConfig", VersionCheckEntry.class));
|
||||
return list;
|
||||
|
@ -133,6 +134,30 @@ public class ForgeGuiFactory implements IModGuiFactory
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides the Client only Settings entry on the Minecraft Forge Configuration screen.
|
||||
* It extends the base Category entry class and defines the IConfigElement objects that will be used to build the child screen.
|
||||
*/
|
||||
public static class ClientEntry extends CategoryEntry
|
||||
{
|
||||
public ClientEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
|
||||
{
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiScreen buildChildScreen()
|
||||
{
|
||||
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed. The parent
|
||||
// GuiConfig object's entryList will also be refreshed to reflect the changes.
|
||||
return new GuiConfig(this.owningScreen,
|
||||
(new ConfigElement(ForgeModContainer.getConfig().getCategory(Configuration.CATEGORY_CLIENT))).getChildElements(),
|
||||
this.owningScreen.modID, Configuration.CATEGORY_CLIENT, this.configElement.requiresWorldRestart() || this.owningScreen.allRequireWorldRestart,
|
||||
this.configElement.requiresMcRestart() || this.owningScreen.allRequireMcRestart,
|
||||
GuiConfig.getAbridgedConfigPath(ForgeModContainer.getConfig().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides the Forge Chunk Manager Config entry on the Minecraft Forge Configuration screen.
|
||||
* It extends the base Category entry class and defines the IConfigElement objects that will be used to build the child screen.
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
|
||||
|
||||
import javax.vecmath.Vector4f;
|
||||
import java.util.List;
|
||||
|
||||
public final class ItemTextureQuadConverter
|
||||
{
|
||||
private ItemTextureQuadConverter()
|
||||
{
|
||||
// non-instantiable
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a texture and converts it into BakedQuads.
|
||||
* The conversion is done by scanning the texture horizontally and vertically and creating "strips" of the texture.
|
||||
* Strips that are of the same size and follow each other are converted into one bigger quad.
|
||||
* </br>
|
||||
* The resulting list of quads is the texture represented as a list of horizontal OR vertical quads,
|
||||
* depending on which creates less quads. If the amount of quads is equal, horizontal is preferred.
|
||||
*
|
||||
* @param format
|
||||
* @param template The input texture to convert
|
||||
* @param sprite The texture whose UVs shall be used @return The generated quads.
|
||||
*/
|
||||
public static List<UnpackedBakedQuad> convertTexture(VertexFormat format, TRSRTransformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, EnumFacing facing, int color)
|
||||
{
|
||||
List<UnpackedBakedQuad> horizontal = convertTextureHorizontal(format, transform, template, sprite, z, facing, color);
|
||||
List<UnpackedBakedQuad> vertical = convertTextureVertical(format, transform, template, sprite, z, facing, color);
|
||||
|
||||
return horizontal.size() >= vertical.size() ? horizontal : vertical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a texture and converts it into a list of horizontal strips stacked on top of each other.
|
||||
* The height of the strips is as big as possible.
|
||||
*/
|
||||
public static List<UnpackedBakedQuad> convertTextureHorizontal(VertexFormat format, TRSRTransformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, EnumFacing facing, int color)
|
||||
{
|
||||
int w = template.getIconWidth();
|
||||
int h = template.getIconHeight();
|
||||
int[] data = template.getFrameTextureData(0)[0];
|
||||
List<UnpackedBakedQuad> quads = Lists.newArrayList();
|
||||
|
||||
// the upper left x-position of the current quad
|
||||
int start = -1;
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
// current pixel
|
||||
int pixel = data[y * w + x];
|
||||
|
||||
// no current quad but found a new one
|
||||
if (start < 0 && isVisible(pixel))
|
||||
{
|
||||
start = x;
|
||||
}
|
||||
// got a current quad, but it ends here
|
||||
if (start >= 0 && !isVisible(pixel))
|
||||
{
|
||||
// we now check if the visibility of the next row matches the one fo the current row
|
||||
// if they are, we can extend the quad downwards
|
||||
int endY = y + 1;
|
||||
boolean sameRow = true;
|
||||
while (sameRow)
|
||||
{
|
||||
for (int i = 0; i < w; i++)
|
||||
{
|
||||
int px1 = data[y * w + i];
|
||||
int px2 = data[endY * w + i];
|
||||
if (isVisible(px1) != isVisible(px2))
|
||||
{
|
||||
sameRow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sameRow)
|
||||
{
|
||||
endY++;
|
||||
}
|
||||
}
|
||||
|
||||
// create the quad
|
||||
quads.add(genQuad(format, transform, start, y, x, endY, z, sprite, facing, color));
|
||||
|
||||
// update Y if all the rows match. no need to rescan
|
||||
if (endY - y > 1)
|
||||
{
|
||||
y = endY - 1;
|
||||
}
|
||||
// clear current quad
|
||||
start = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return quads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a texture and converts it into a list of vertical strips stacked next to each other from left to right.
|
||||
* The width of the strips is as big as possible.
|
||||
*/
|
||||
public static List<UnpackedBakedQuad> convertTextureVertical(VertexFormat format, TRSRTransformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, EnumFacing facing, int color)
|
||||
{
|
||||
int w = template.getIconWidth();
|
||||
int h = template.getIconHeight();
|
||||
int[] data = template.getFrameTextureData(0)[0];
|
||||
List<UnpackedBakedQuad> quads = Lists.newArrayList();
|
||||
|
||||
// the upper left y-position of the current quad
|
||||
int start = -1;
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
// current pixel
|
||||
int pixel = data[y * w + x];
|
||||
|
||||
// no current quad but found a new one
|
||||
if (start < 0 && isVisible(pixel))
|
||||
{
|
||||
start = y;
|
||||
}
|
||||
// got a current quad, but it ends here
|
||||
if (start >= 0 && !isVisible(pixel))
|
||||
{
|
||||
// we now check if the visibility of the next column matches the one fo the current row
|
||||
// if they are, we can extend the quad downwards
|
||||
int endX = x + 1;
|
||||
boolean sameColumn = true;
|
||||
while (sameColumn)
|
||||
{
|
||||
for (int i = 0; i < h; i++)
|
||||
{
|
||||
int px1 = data[i * w + x];
|
||||
int px2 = data[i * w + endX];
|
||||
if (isVisible(px1) != isVisible(px2))
|
||||
{
|
||||
sameColumn = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sameColumn)
|
||||
{
|
||||
endX++;
|
||||
}
|
||||
}
|
||||
|
||||
// create the quad
|
||||
quads.add(genQuad(format, transform, x, start, endX, y, z, sprite, facing, color));
|
||||
|
||||
// update X if all the columns match. no need to rescan
|
||||
if (endX - x > 1)
|
||||
{
|
||||
x = endX - 1;
|
||||
}
|
||||
// clear current quad
|
||||
start = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return quads;
|
||||
}
|
||||
|
||||
// true if alpha != 0
|
||||
private static boolean isVisible(int color)
|
||||
{
|
||||
return (color >> 24 & 255) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Front/Back quad for an itemmodel. Therefore only supports facing NORTH and SOUTH.
|
||||
*/
|
||||
public static UnpackedBakedQuad genQuad(VertexFormat format, TRSRTransformation transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, EnumFacing facing, int color)
|
||||
{
|
||||
float u1 = sprite.getInterpolatedU(x1);
|
||||
float v1 = sprite.getInterpolatedV(y1);
|
||||
float u2 = sprite.getInterpolatedU(x2);
|
||||
float v2 = sprite.getInterpolatedV(y2);
|
||||
|
||||
x1 /= 16f;
|
||||
y1 /= 16f;
|
||||
x2 /= 16f;
|
||||
y2 /= 16f;
|
||||
|
||||
float tmp = y1;
|
||||
y1 = 1f - y2;
|
||||
y2 = 1f - tmp;
|
||||
|
||||
return putQuad(format, transform, facing, color, x1, y1, x2, y2, z, u1, v1, u2, v2);
|
||||
}
|
||||
|
||||
private static UnpackedBakedQuad putQuad(VertexFormat format, TRSRTransformation transform, EnumFacing side, int color,
|
||||
float x1, float y1, float x2, float y2, float z,
|
||||
float u1, float v1, float u2, float v2)
|
||||
{
|
||||
side = side.getOpposite();
|
||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadTint(-1);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setQuadColored();
|
||||
|
||||
if (side == EnumFacing.NORTH)
|
||||
{
|
||||
putVertex(builder, format, transform, side, x1, y1, z, u1, v2, color);
|
||||
putVertex(builder, format, transform, side, x2, y1, z, u2, v2, color);
|
||||
putVertex(builder, format, transform, side, x2, y2, z, u2, v1, color);
|
||||
putVertex(builder, format, transform, side, x1, y2, z, u1, v1, color);
|
||||
} else
|
||||
{
|
||||
putVertex(builder, format, transform, side, x1, y1, z, u1, v2, color);
|
||||
putVertex(builder, format, transform, side, x1, y2, z, u1, v1, color);
|
||||
putVertex(builder, format, transform, side, x2, y2, z, u2, v1, color);
|
||||
putVertex(builder, format, transform, side, x2, y1, z, u2, v2, color);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static void putVertex(UnpackedBakedQuad.Builder builder, VertexFormat format, TRSRTransformation transform, EnumFacing side,
|
||||
float x, float y, float z, float u, float v, int color)
|
||||
{
|
||||
Vector4f vec = new Vector4f();
|
||||
for (int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
switch (format.getElement(e).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
if (transform == TRSRTransformation.identity())
|
||||
{
|
||||
builder.put(e, x, y, z, 1);
|
||||
}
|
||||
// only apply the transform if it's not identity
|
||||
else
|
||||
{
|
||||
vec.x = x;
|
||||
vec.y = y;
|
||||
vec.z = z;
|
||||
vec.w = 1;
|
||||
transform.getMatrix().transform(vec);
|
||||
builder.put(e, vec.x, vec.y, vec.z, vec.w);
|
||||
}
|
||||
break;
|
||||
case COLOR:
|
||||
float r = ((color >> 16) & 0xFF) / 255f; // red
|
||||
float g = ((color >> 8) & 0xFF) / 255f; // green
|
||||
float b = ((color >> 0) & 0xFF) / 255f; // blue
|
||||
float a = ((color >> 24) & 0xFF) / 255f; // alpha
|
||||
builder.put(e, r, g, b, a);
|
||||
break;
|
||||
case UV:
|
||||
if (format.getElement(e).getIndex() == 0)
|
||||
{
|
||||
builder.put(e, u, v, 0f, 1f);
|
||||
break;
|
||||
}
|
||||
case NORMAL:
|
||||
builder.put(e, (float) side.getFrontOffsetX(), (float) side.getFrontOffsetY(), (float) side.getFrontOffsetZ(), 0f);
|
||||
break;
|
||||
default:
|
||||
builder.put(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.model.IBakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fluids.*;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Quat4f;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public class ModelDynBucket implements IModel, IModelCustomData, IRetexturableModel
|
||||
{
|
||||
public static final ModelResourceLocation LOCATION = new ModelResourceLocation(new ResourceLocation("forge", "dynbucket"), "inventory");
|
||||
|
||||
// minimal Z offset to prevent depth-fighting
|
||||
private static final float NORTH_Z_BASE = 7.496f / 16f;
|
||||
private static final float SOUTH_Z_BASE = 8.504f / 16f;
|
||||
private static final float NORTH_Z_FLUID = 7.498f / 16f;
|
||||
private static final float SOUTH_Z_FLUID = 8.502f / 16f;
|
||||
|
||||
public static final IModel MODEL = new ModelDynBucket();
|
||||
|
||||
protected final ResourceLocation baseLocation;
|
||||
protected final ResourceLocation liquidLocation;
|
||||
protected final ResourceLocation coverLocation;
|
||||
|
||||
protected final Fluid fluid;
|
||||
protected final boolean flipGas;
|
||||
|
||||
public ModelDynBucket()
|
||||
{
|
||||
this(null, null, null, FluidRegistry.WATER, false);
|
||||
}
|
||||
|
||||
public ModelDynBucket(ResourceLocation baseLocation, ResourceLocation liquidLocation, ResourceLocation coverLocation, Fluid fluid, boolean flipGas)
|
||||
{
|
||||
this.baseLocation = baseLocation;
|
||||
this.liquidLocation = liquidLocation;
|
||||
this.coverLocation = coverLocation;
|
||||
this.fluid = fluid;
|
||||
this.flipGas = flipGas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies()
|
||||
{
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
ImmutableSet.Builder<ResourceLocation> builder = ImmutableSet.builder();
|
||||
if (baseLocation != null)
|
||||
builder.add(baseLocation);
|
||||
if (liquidLocation != null)
|
||||
builder.add(liquidLocation);
|
||||
if (coverLocation != null)
|
||||
builder.add(coverLocation);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFlexibleBakedModel bake(IModelState state, VertexFormat format,
|
||||
Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
|
||||
ImmutableMap<TransformType, TRSRTransformation> transformMap = IPerspectiveAwareModel.MapWrapper.getTransforms(state);
|
||||
|
||||
// if the fluid is a gas wi manipulate the initial state to be rotated 180° to turn it upside down
|
||||
if (flipGas && fluid.isGaseous())
|
||||
{
|
||||
state = new ModelStateComposition(state, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, new Quat4f(0, 0, 1, 0), null, null)));
|
||||
}
|
||||
|
||||
TRSRTransformation transform = state.apply(Optional.<IModelPart>absent()).or(TRSRTransformation.identity());
|
||||
TextureAtlasSprite fluidSprite = bakedTextureGetter.apply(fluid.getStill());
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
if (baseLocation != null)
|
||||
{
|
||||
// build base (insidest)
|
||||
IFlexibleBakedModel model = (new ItemLayerModel(ImmutableList.of(baseLocation))).bake(state, format, bakedTextureGetter);
|
||||
builder.addAll(model.getGeneralQuads());
|
||||
}
|
||||
if (liquidLocation != null)
|
||||
{
|
||||
TextureAtlasSprite liquid = bakedTextureGetter.apply(liquidLocation);
|
||||
// build liquid layer (inside)
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, NORTH_Z_FLUID, EnumFacing.NORTH, fluid.getColor()));
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, SOUTH_Z_FLUID, EnumFacing.SOUTH, fluid.getColor()));
|
||||
}
|
||||
if (coverLocation != null)
|
||||
{
|
||||
// cover (the actual item around the other two)
|
||||
TextureAtlasSprite base = bakedTextureGetter.apply(coverLocation);
|
||||
builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, NORTH_Z_BASE, base, EnumFacing.NORTH, 0xffffffff));
|
||||
builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, SOUTH_Z_BASE, base, EnumFacing.SOUTH, 0xffffffff));
|
||||
}
|
||||
|
||||
|
||||
return new BakedDynBucket(this, builder.build(), fluidSprite, format, Maps.immutableEnumMap(transformMap), Maps.<String, IFlexibleBakedModel>newHashMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelState getDefaultState()
|
||||
{
|
||||
return TRSRTransformation.identity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the liquid in the model.
|
||||
* fluid - Name of the fluid in the FluidRegistry
|
||||
* flipGas - If "true" the model will be flipped upside down if the liquid is a gas. If "false" it wont
|
||||
* <p/>
|
||||
* If the fluid can't be found, water is used
|
||||
*/
|
||||
@Override
|
||||
public IModel process(ImmutableMap<String, String> customData)
|
||||
{
|
||||
String fluidName = customData.get("fluid");
|
||||
Fluid fluid = FluidRegistry.getFluid(fluidName);
|
||||
|
||||
if (fluid == null) fluid = this.fluid;
|
||||
|
||||
boolean flip = flipGas;
|
||||
if (customData.containsKey("flipGas"))
|
||||
{
|
||||
String flipStr = customData.get("flipGas");
|
||||
if (flipStr.equals("true")) flip = true;
|
||||
else if (flipStr.equals("false")) flip = false;
|
||||
else
|
||||
throw new IllegalArgumentException(String.format("DynBucket custom data \"flipGas\" must have value \'true\' or \'false\' (was \'%s\')", flipStr));
|
||||
}
|
||||
|
||||
// create new model with correct liquid
|
||||
return new ModelDynBucket(baseLocation, liquidLocation, coverLocation, fluid, flip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to use different textures for the model.
|
||||
* There are 3 layers:
|
||||
* base - The empty bucket/container
|
||||
* fluid - A texture representing the liquid portion. Non-transparent = liquid
|
||||
* cover - An overlay that's put over the liquid (optional)
|
||||
* <p/>
|
||||
* If no liquid is given a hardcoded variant for the bucket is used.
|
||||
*/
|
||||
@Override
|
||||
public IModel retexture(ImmutableMap<String, String> textures)
|
||||
{
|
||||
|
||||
ResourceLocation base = baseLocation;
|
||||
ResourceLocation liquid = liquidLocation;
|
||||
ResourceLocation cover = coverLocation;
|
||||
|
||||
if (textures.containsKey("base"))
|
||||
base = new ResourceLocation(textures.get("base"));
|
||||
if (textures.containsKey("fluid"))
|
||||
liquid = new ResourceLocation(textures.get("fluid"));
|
||||
if (textures.containsKey("cover"))
|
||||
cover = new ResourceLocation(textures.get("cover"));
|
||||
|
||||
return new ModelDynBucket(base, liquid, cover, fluid, flipGas);
|
||||
}
|
||||
|
||||
public enum LoaderDynBucket implements ICustomModelLoader
|
||||
{
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return modelLocation.getResourceDomain().equals("forge") && modelLocation.getResourcePath().contains("forgebucket");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation) throws IOException
|
||||
{
|
||||
return MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager)
|
||||
{
|
||||
// no need to clear cache since we create a new model instance
|
||||
}
|
||||
}
|
||||
|
||||
// the dynamic bucket is based on the empty bucket
|
||||
protected static class BakedDynBucket extends ItemLayerModel.BakedModel implements ISmartItemModel, IPerspectiveAwareModel
|
||||
{
|
||||
|
||||
private final ModelDynBucket parent;
|
||||
private final Map<String, IFlexibleBakedModel> cache; // contains all the baked models since they'll never change
|
||||
private final ImmutableMap<TransformType, TRSRTransformation> transforms;
|
||||
|
||||
public BakedDynBucket(ModelDynBucket parent,
|
||||
ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, VertexFormat format, ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms,
|
||||
Map<String, IFlexibleBakedModel> cache)
|
||||
{
|
||||
super(quads, particle, format);
|
||||
this.parent = parent;
|
||||
this.transforms = transforms;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handleItemState(ItemStack stack)
|
||||
{
|
||||
FluidStack fluidStack = FluidContainerRegistry.getFluidForFilledItem(stack);
|
||||
if (fluidStack == null)
|
||||
{
|
||||
if (stack.getItem() instanceof IFluidContainerItem)
|
||||
{
|
||||
fluidStack = ((IFluidContainerItem) stack.getItem()).getFluid(stack);
|
||||
}
|
||||
}
|
||||
|
||||
// not a fluid item apparently
|
||||
if (fluidStack == null)
|
||||
return this;
|
||||
|
||||
|
||||
Fluid fluid = fluidStack.getFluid();
|
||||
String name = fluid.getName();
|
||||
|
||||
if (!cache.containsKey(name))
|
||||
{
|
||||
IModel model = parent.process(ImmutableMap.of("fluid", name));
|
||||
Function<ResourceLocation, TextureAtlasSprite> textureGetter;
|
||||
textureGetter = new Function<ResourceLocation, TextureAtlasSprite>()
|
||||
{
|
||||
public TextureAtlasSprite apply(ResourceLocation location)
|
||||
{
|
||||
return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString());
|
||||
}
|
||||
};
|
||||
|
||||
IFlexibleBakedModel bakedModel = model.bake(new SimpleModelState(transforms), this.getFormat(), textureGetter);
|
||||
cache.put(name, bakedModel);
|
||||
return bakedModel;
|
||||
}
|
||||
|
||||
return cache.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IFlexibleBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
|
||||
{
|
||||
return IPerspectiveAwareModel.MapWrapper.handlePerspective(this, transforms, cameraTransformType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,10 +45,17 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
|
|||
import net.minecraft.client.resources.model.ModelRotation;
|
||||
import net.minecraft.client.resources.model.SimpleBakedModel;
|
||||
import net.minecraft.client.resources.model.WeightedBakedModel;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.IRegistry;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.registry.GameData;
|
||||
import net.minecraftforge.fml.common.registry.RegistryDelegate;
|
||||
|
@ -177,6 +184,7 @@ public class ModelLoader extends ModelBakery
|
|||
registerVariantNames();
|
||||
for(Item item : GameData.getItemRegistry().typeSafeIterable())
|
||||
{
|
||||
// default loading
|
||||
for(String s : (List<String>)getVariantNames(item))
|
||||
{
|
||||
ResourceLocation file = getItemLocation(s);
|
||||
|
@ -201,6 +209,68 @@ public class ModelLoader extends ModelBakery
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replace vanilla bucket models if desired. done afterwards for performance reasons
|
||||
if(ForgeModContainer.replaceVanillaBucketModel)
|
||||
{
|
||||
// empty bucket
|
||||
for(String s : getVariantNames(Items.bucket))
|
||||
{
|
||||
ModelResourceLocation memory = new ModelResourceLocation(s, "inventory");
|
||||
try
|
||||
{
|
||||
IModel model = getModel(new ResourceLocation("forge", "item/bucket"));
|
||||
// only on successful load, otherwise continue using the old model
|
||||
stateModels.put(memory, model);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
// use the original vanilla model
|
||||
}
|
||||
}
|
||||
|
||||
setBucketModel(Items.water_bucket);
|
||||
setBucketModel(Items.lava_bucket);
|
||||
// milk bucket only replaced if some mod adds milk
|
||||
if(FluidRegistry.isFluidRegistered("milk"))
|
||||
{
|
||||
// can the milk be put into a bucket?
|
||||
Fluid milk = FluidRegistry.getFluid("milk");
|
||||
FluidStack milkStack = new FluidStack(milk, FluidContainerRegistry.BUCKET_VOLUME);
|
||||
if(FluidContainerRegistry.getContainerCapacity(milkStack, new ItemStack(Items.bucket)) == FluidContainerRegistry.BUCKET_VOLUME)
|
||||
{
|
||||
setBucketModel(Items.milk_bucket);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// milk bucket if no milk fluid is present
|
||||
for(String s : getVariantNames(Items.milk_bucket))
|
||||
{
|
||||
ModelResourceLocation memory = new ModelResourceLocation(s, "inventory");
|
||||
try
|
||||
{
|
||||
IModel model = getModel(new ResourceLocation("forge", "item/bucket_milk"));
|
||||
// only on successful load, otherwise continue using the old model
|
||||
stateModels.put(memory, model);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
// use the original vanilla model
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setBucketModel(Item item)
|
||||
{
|
||||
for(String s : getVariantNames(item))
|
||||
{
|
||||
ModelResourceLocation memory = new ModelResourceLocation(s, "inventory");
|
||||
IModel model = stateModels.get(ModelDynBucket.LOCATION);
|
||||
stateModels.put(memory, model);
|
||||
}
|
||||
}
|
||||
|
||||
public IModel getModel(ResourceLocation location) throws IOException
|
||||
|
|
|
@ -34,6 +34,7 @@ public class ModelLoaderRegistry
|
|||
registerLoader(ModelFluid.FluidLoader.instance);
|
||||
registerLoader(ItemLayerModel.Loader.instance);
|
||||
registerLoader(MultiLayerModel.Loader.instance);
|
||||
registerLoader(ModelDynBucket.LoaderDynBucket.instance);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import static net.minecraftforge.common.config.Configuration.CATEGORY_CLIENT;
|
||||
import static net.minecraftforge.common.config.Configuration.CATEGORY_GENERAL;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -68,6 +69,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
|
|||
public static int defaultSpawnFuzz = 20;
|
||||
public static boolean defaultHasSpawnFuzz = true;
|
||||
public static boolean forgeLightPipelineEnabled = true;
|
||||
public static boolean replaceVanillaBucketModel = true;
|
||||
|
||||
private static Configuration config;
|
||||
private static ForgeModContainer INSTANCE;
|
||||
|
@ -244,6 +246,16 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
|
|||
|
||||
config.setCategoryPropertyOrder(VERSION_CHECK_CAT, propOrder);
|
||||
|
||||
// Client-Side only properties
|
||||
propOrder = new ArrayList<String>();
|
||||
prop = config.get(Configuration.CATEGORY_CLIENT, "replaceVanillaBucketModel", Boolean.FALSE,
|
||||
"Replace the vanilla bucket models with Forges own dynamic bucket model. Unifies bucket visuals if a mod uses the Forge bucket model.");
|
||||
prop.setLanguageKey("forge.configgui.replaceBuckets").setRequiresMcRestart(true);
|
||||
replaceVanillaBucketModel = prop.getBoolean(Boolean.FALSE);
|
||||
propOrder.add(prop.getName());
|
||||
|
||||
config.setCategoryPropertyOrder(CATEGORY_CLIENT, propOrder);
|
||||
|
||||
if (config.hasChanged())
|
||||
{
|
||||
config.save();
|
||||
|
|
|
@ -48,6 +48,7 @@ import net.minecraftforge.fml.relauncher.FMLInjectionData;
|
|||
public class Configuration
|
||||
{
|
||||
public static final String CATEGORY_GENERAL = "general";
|
||||
public static final String CATEGORY_CLIENT = "client";
|
||||
public static final String ALLOWED_CHARS = "._-";
|
||||
public static final String DEFAULT_ENCODING = "UTF-8";
|
||||
public static final String CATEGORY_SPLITTER = ".";
|
||||
|
|
18
src/main/resources/assets/forge/blockstates/dynbucket.json
Normal file
18
src/main/resources/assets/forge/blockstates/dynbucket.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"forge_marker": 1,
|
||||
"variants": {
|
||||
"inventory": {
|
||||
"model": "forge:forgebucket",
|
||||
"textures": {
|
||||
"base": "forge:items/bucket_base",
|
||||
"fluid": "forge:items/bucket_fluid",
|
||||
"cover": "forge:items/bucket_cover"
|
||||
},
|
||||
"transform": "forge:default-item",
|
||||
"custom": {
|
||||
"fluid": "water",
|
||||
"flipGas": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ forge.update.beta.2=Major issues may arise, verify before reporting.
|
|||
forge.configgui.forgeConfigTitle=Minecraft Forge Configuration
|
||||
forge.configgui.ctgy.forgeGeneralConfig.tooltip=This is where you can edit the settings contained in forge.cfg.
|
||||
forge.configgui.ctgy.forgeGeneralConfig=General Settings
|
||||
forge.configgui.ctgy.forgeClientConfig.tooltip=Settings in the forge.cfg that only concern the local client. Usually graphical settings.
|
||||
forge.configgui.ctgy.forgeClientConfig=Client Settings
|
||||
forge.configgui.ctgy.forgeChunkLoadingConfig.tooltip=This is where you can edit the settings contained in forgeChunkLoading.cfg.
|
||||
forge.configgui.ctgy.forgeChunkLoadingConfig=Forge Chunk Loader Default Settings
|
||||
forge.configgui.ctgy.forgeChunkLoadingModConfig.tooltip=This is where you can define mod-specific override settings that will be used instead of the defaults.
|
||||
|
@ -43,6 +45,7 @@ forge.configgui.zombieBaseSummonChance.tooltip=Base zombie summoning spawn chanc
|
|||
forge.configgui.zombieBaseSummonChance=Zombie Summon Chance
|
||||
forge.configgui.stencilbits=Enable GL Stencil Bits
|
||||
forge.configgui.spawnfuzz=Respawn Fuzz Diameter
|
||||
forge.configgui.replaceBuckets=Use Forges' bucket model
|
||||
|
||||
forge.configgui.modID.tooltip=The mod ID that you want to define override settings for.
|
||||
forge.configgui.modID=Mod ID
|
||||
|
|
18
src/main/resources/assets/forge/models/item/bucket.json
Normal file
18
src/main/resources/assets/forge/models/item/bucket.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"parent": "builtin/generated",
|
||||
"textures": {
|
||||
"layer0": "forge:items/bucket_base"
|
||||
},
|
||||
"display": {
|
||||
"thirdperson": {
|
||||
"rotation": [ -90, 0, 0 ],
|
||||
"translation": [ 0, 1, -3 ],
|
||||
"scale": [ 0.55, 0.55, 0.55 ]
|
||||
},
|
||||
"firstperson": {
|
||||
"rotation": [ 0, -135, 25 ],
|
||||
"translation": [ 0, 4, 2 ],
|
||||
"scale": [ 1.7, 1.7, 1.7 ]
|
||||
}
|
||||
}
|
||||
}
|
20
src/main/resources/assets/forge/models/item/bucket_milk.json
Normal file
20
src/main/resources/assets/forge/models/item/bucket_milk.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"parent": "builtin/generated",
|
||||
"textures": {
|
||||
"layer0": "forge:items/bucket_base",
|
||||
"layer1": "forge:items/bucket_fluid", # doubles as milk
|
||||
"layer2": "forge:items/bucket_cover"
|
||||
},
|
||||
"display": {
|
||||
"thirdperson": {
|
||||
"rotation": [ -90, 0, 0 ],
|
||||
"translation": [ 0, 1, -3 ],
|
||||
"scale": [ 0.55, 0.55, 0.55 ]
|
||||
},
|
||||
"firstperson": {
|
||||
"rotation": [ 0, -135, 25 ],
|
||||
"translation": [ 0, 4, 2 ],
|
||||
"scale": [ 1.7, 1.7, 1.7 ]
|
||||
}
|
||||
}
|
||||
}
|
BIN
src/main/resources/assets/forge/textures/items/bucket_base.png
Normal file
BIN
src/main/resources/assets/forge/textures/items/bucket_base.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 597 B |
BIN
src/main/resources/assets/forge/textures/items/bucket_cover.png
Normal file
BIN
src/main/resources/assets/forge/textures/items/bucket_cover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 611 B |
BIN
src/main/resources/assets/forge/textures/items/bucket_fluid.png
Normal file
BIN
src/main/resources/assets/forge/textures/items/bucket_fluid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 157 B |
179
src/test/java/net/minecraftforge/debug/DynBucketTest.java
Normal file
179
src/test/java/net/minecraftforge/debug/DynBucketTest.java
Normal file
|
@ -0,0 +1,179 @@
|
|||
package net.minecraftforge.debug;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ModelDynBucket;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.debug.ModelFluidDebug.TestFluid;
|
||||
import net.minecraftforge.debug.ModelFluidDebug.TestGas;
|
||||
import net.minecraftforge.event.entity.player.FillBucketEvent;
|
||||
import net.minecraftforge.fluids.*;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.Mod.EventHandler;
|
||||
import net.minecraftforge.fml.common.SidedProxy;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event.Result;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mod(modid = "DynBucketTest", version = "0.1", dependencies = "after:" + ModelFluidDebug.MODID)
|
||||
public class DynBucketTest
|
||||
{
|
||||
public static final Item dynBucket = new DynBucket();
|
||||
public static final Item dynBottle = new DynBottle();
|
||||
|
||||
@SidedProxy(clientSide = "net.minecraftforge.debug.DynBucketTest$ClientProxy", serverSide = "net.minecraftforge.debug.DynBucketTest$CommonProxy")
|
||||
public static CommonProxy proxy;
|
||||
|
||||
public static class CommonProxy
|
||||
{
|
||||
void setupModels()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClientProxy extends CommonProxy
|
||||
{
|
||||
@Override
|
||||
void setupModels()
|
||||
{
|
||||
ModelLoader.setCustomMeshDefinition(dynBucket, new ItemMeshDefinition()
|
||||
{
|
||||
@Override
|
||||
public ModelResourceLocation getModelLocation(ItemStack stack)
|
||||
{
|
||||
return ModelDynBucket.LOCATION;
|
||||
}
|
||||
});
|
||||
ModelBakery.addVariantName(dynBucket, "forge:dynbucket");
|
||||
|
||||
ModelLoader.setCustomMeshDefinition(dynBottle, new ItemMeshDefinition()
|
||||
{
|
||||
@Override
|
||||
public ModelResourceLocation getModelLocation(ItemStack stack)
|
||||
{
|
||||
return new ModelResourceLocation(new ResourceLocation("forge", "dynbottle"), "inventory");
|
||||
}
|
||||
});
|
||||
ModelBakery.addVariantName(dynBottle, "forge:dynbottle");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event)
|
||||
{
|
||||
GameRegistry.registerItem(dynBucket, "dynbucket");
|
||||
GameRegistry.registerItem(dynBottle, "dynbottle");
|
||||
|
||||
// register fluid containers
|
||||
int i = 0;
|
||||
//registerFluidContainer(FluidRegistry.WATER, i++);
|
||||
//registerFluidContainer(FluidRegistry.LAVA, i++);
|
||||
registerFluidContainer(FluidRegistry.getFluid(TestFluid.name), i++);
|
||||
registerFluidContainer(FluidRegistry.getFluid(TestGas.name), i++);
|
||||
|
||||
i = 0;
|
||||
registerFluidContainer2(FluidRegistry.WATER, i++);
|
||||
registerFluidContainer2(FluidRegistry.LAVA, i++);
|
||||
registerFluidContainer2(FluidRegistry.getFluid(TestFluid.name), i++);
|
||||
registerFluidContainer2(FluidRegistry.getFluid(TestGas.name), i++);
|
||||
|
||||
// Set TestFluidBlocks blockstate to use milk instead of testfluid for the texture to be loaded
|
||||
FluidContainerRegistry.registerFluidContainer(FluidRegistry.getFluid("milk"), new ItemStack(Items.milk_bucket), FluidContainerRegistry.EMPTY_BUCKET);
|
||||
|
||||
proxy.setupModels();
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
private void registerFluidContainer(Fluid fluid, int meta)
|
||||
{
|
||||
if (fluid == null)
|
||||
return;
|
||||
|
||||
FluidStack fs = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
|
||||
ItemStack stack = new ItemStack(dynBucket, 1, meta);
|
||||
FluidContainerRegistry.registerFluidContainer(fs, stack, new ItemStack(Items.bucket));
|
||||
}
|
||||
|
||||
private void registerFluidContainer2(Fluid fluid, int meta)
|
||||
{
|
||||
if (fluid == null)
|
||||
return;
|
||||
|
||||
FluidStack fs = new FluidStack(fluid, 250);
|
||||
ItemStack stack = new ItemStack(dynBottle, 1, meta);
|
||||
FluidContainerRegistry.registerFluidContainer(fs, stack, new ItemStack(Items.glass_bottle));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onBucketFill(FillBucketEvent event)
|
||||
{
|
||||
IBlockState state = event.world.getBlockState(event.target.getBlockPos());
|
||||
if (state.getBlock() instanceof IFluidBlock)
|
||||
{
|
||||
Fluid fluid = ((IFluidBlock) state.getBlock()).getFluid();
|
||||
FluidStack fs = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
|
||||
|
||||
ItemStack filled = FluidContainerRegistry.fillFluidContainer(fs, event.current);
|
||||
if (filled != null)
|
||||
{
|
||||
event.result = filled;
|
||||
event.setResult(Result.ALLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynBucket extends Item
|
||||
{
|
||||
public DynBucket()
|
||||
{
|
||||
setUnlocalizedName("dynbucket");
|
||||
setMaxStackSize(1);
|
||||
setHasSubtypes(true);
|
||||
setCreativeTab(CreativeTabs.tabMisc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSubItems(Item itemIn, CreativeTabs tab, List<ItemStack> subItems)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ItemStack bucket = new ItemStack(this, 1, i);
|
||||
if (FluidContainerRegistry.isFilledContainer(bucket))
|
||||
subItems.add(bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynBottle extends Item
|
||||
{
|
||||
public DynBottle()
|
||||
{
|
||||
setUnlocalizedName("dynbottle");
|
||||
setMaxStackSize(1);
|
||||
setHasSubtypes(true);
|
||||
setCreativeTab(CreativeTabs.tabMisc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSubItems(Item itemIn, CreativeTabs tab, List<ItemStack> subItems)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ItemStack bucket = new ItemStack(this, 1, i);
|
||||
if (FluidContainerRegistry.isFilledContainer(bucket))
|
||||
subItems.add(bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,8 @@ public class ModelFluidDebug
|
|||
@SidedProxy(serverSide = "net.minecraftforge.debug.ModelFluidDebug$CommonProxy", clientSide = "net.minecraftforge.debug.ModelFluidDebug$ClientProxy")
|
||||
public static CommonProxy proxy;
|
||||
|
||||
public static final Fluid milkFluid = new Fluid("milk", new ResourceLocation("forge", "blocks/milk_still"), new ResourceLocation("forge", "blocks/milk_flow"));
|
||||
|
||||
@EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) { proxy.preInit(event); }
|
||||
|
||||
|
@ -38,8 +40,10 @@ public class ModelFluidDebug
|
|||
{
|
||||
FluidRegistry.registerFluid(TestFluid.instance);
|
||||
FluidRegistry.registerFluid(TestGas.instance);
|
||||
FluidRegistry.registerFluid(milkFluid);
|
||||
GameRegistry.registerBlock(TestFluidBlock.instance, TestFluidBlock.name);
|
||||
GameRegistry.registerBlock(TestGasBlock.instance, TestGasBlock.name);
|
||||
GameRegistry.registerBlock(MilkFluidBlock.instance, MilkFluidBlock.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +51,7 @@ public class ModelFluidDebug
|
|||
{
|
||||
private static ModelResourceLocation fluidLocation = new ModelResourceLocation(MODID.toLowerCase() + ":" + TestFluidBlock.name, "fluid");
|
||||
private static ModelResourceLocation gasLocation = new ModelResourceLocation(MODID.toLowerCase() + ":" + TestFluidBlock.name, "gas");
|
||||
private static ModelResourceLocation milkLocation = new ModelResourceLocation(MODID.toLowerCase() + ":" + TestFluidBlock.name, "milk");
|
||||
|
||||
@Override
|
||||
public void preInit(FMLPreInitializationEvent event)
|
||||
|
@ -54,8 +59,10 @@ public class ModelFluidDebug
|
|||
super.preInit(event);
|
||||
Item fluid = Item.getItemFromBlock(TestFluidBlock.instance);
|
||||
Item gas = Item.getItemFromBlock(TestGasBlock.instance);
|
||||
Item milk = Item.getItemFromBlock(MilkFluidBlock.instance);
|
||||
ModelBakery.addVariantName(fluid);
|
||||
ModelBakery.addVariantName(gas);
|
||||
ModelBakery.addVariantName(milk);
|
||||
ModelLoader.setCustomMeshDefinition(fluid, new ItemMeshDefinition()
|
||||
{
|
||||
public ModelResourceLocation getModelLocation(ItemStack stack)
|
||||
|
@ -70,6 +77,13 @@ public class ModelFluidDebug
|
|||
return gasLocation;
|
||||
}
|
||||
});
|
||||
ModelLoader.setCustomMeshDefinition(milk, new ItemMeshDefinition()
|
||||
{
|
||||
public ModelResourceLocation getModelLocation(ItemStack stack)
|
||||
{
|
||||
return milkLocation;
|
||||
}
|
||||
});
|
||||
ModelLoader.setCustomStateMapper(TestFluidBlock.instance, new StateMapperBase()
|
||||
{
|
||||
protected ModelResourceLocation getModelResourceLocation(IBlockState state)
|
||||
|
@ -84,6 +98,13 @@ public class ModelFluidDebug
|
|||
return gasLocation;
|
||||
}
|
||||
});
|
||||
ModelLoader.setCustomStateMapper(MilkFluidBlock.instance, new StateMapperBase()
|
||||
{
|
||||
protected ModelResourceLocation getModelResourceLocation(IBlockState state)
|
||||
{
|
||||
return milkLocation;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +157,19 @@ public class ModelFluidDebug
|
|||
}
|
||||
}
|
||||
|
||||
public static final class MilkFluidBlock extends BlockFluidClassic
|
||||
{
|
||||
public static final MilkFluidBlock instance = new MilkFluidBlock();
|
||||
public static final String name = "MilkFluidBlock";
|
||||
|
||||
private MilkFluidBlock()
|
||||
{
|
||||
super(milkFluid, Material.water);
|
||||
setCreativeTab(CreativeTabs.tabBlock);
|
||||
setUnlocalizedName(MODID + ":" + name);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestGasBlock extends BlockFluidClassic
|
||||
{
|
||||
public static final TestGasBlock instance = new TestGasBlock();
|
||||
|
|
18
src/test/resources/assets/forge/blockstates/dynbottle.json
Normal file
18
src/test/resources/assets/forge/blockstates/dynbottle.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"forge_marker": 1,
|
||||
"variants": {
|
||||
"inventory": {
|
||||
"model": "forge:forgebucket",
|
||||
"textures": {
|
||||
"base": "minecraft:items/potion_bottle_empty",
|
||||
"fluid": "minecraft:items/potion_overlay",
|
||||
"cover": "minecraft:items/potion_bottle_empty"
|
||||
},
|
||||
"transform": "forge:default-item",
|
||||
"custom": {
|
||||
"fluid": "water",
|
||||
"flipGas": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
src/test/resources/assets/forge/textures/blocks/milk_flow.png
Normal file
BIN
src/test/resources/assets/forge/textures/blocks/milk_flow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5 KiB |
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"animation": {}
|
||||
}
|
BIN
src/test/resources/assets/forge/textures/blocks/milk_still.png
Normal file
BIN
src/test/resources/assets/forge/textures/blocks/milk_still.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"animation": {
|
||||
"frametime": 2
|
||||
}
|
||||
}
|
|
@ -8,6 +8,10 @@
|
|||
"gas": {
|
||||
"model": "forge:fluid",
|
||||
"custom": { "fluid": "testgas" }
|
||||
},
|
||||
"milk": {
|
||||
"model": "forge:fluid",
|
||||
"custom": { "fluid": "milk" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue