base mod created
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.advancements.critereon;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.minecraft.advancements.critereon.ItemPredicate;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemPredicates
|
||||
{
|
||||
private static final Map<ResourceLocation, Function<JsonObject, ItemPredicate>> predicates = new HashMap<>();
|
||||
|
||||
static
|
||||
{
|
||||
register(new ResourceLocation("forge:ore_dict"), OredictItemPredicate::new);
|
||||
}
|
||||
|
||||
public static void register(ResourceLocation rl, Function<JsonObject, ItemPredicate> jsonToPredicate)
|
||||
{
|
||||
predicates.put(rl, jsonToPredicate);
|
||||
}
|
||||
|
||||
public static Map<ResourceLocation, Function<JsonObject, ItemPredicate>> getPredicates()
|
||||
{
|
||||
return Collections.unmodifiableMap(predicates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.advancements.critereon;
|
||||
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import net.minecraft.advancements.critereon.ItemPredicate;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
/**
|
||||
* An {@link ItemPredicate} that matches oredicts.
|
||||
*/
|
||||
public class OredictItemPredicate extends ItemPredicate
|
||||
{
|
||||
private final String ore;
|
||||
|
||||
public OredictItemPredicate(String ore)
|
||||
{
|
||||
this.ore = ore;
|
||||
}
|
||||
|
||||
public OredictItemPredicate(JsonObject jsonObject) { this(JsonUtils.getString(jsonObject, "ore")); }
|
||||
|
||||
@Override
|
||||
public boolean test(ItemStack stack)
|
||||
{
|
||||
return !stack.isEmpty() && ArrayUtils.contains(OreDictionary.getOreIDs(stack), OreDictionary.getOreID(ore));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.classloading;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FMLForgePlugin implements IFMLLoadingPlugin
|
||||
{
|
||||
public static boolean RUNTIME_DEOBF = false;
|
||||
public static File forgeLocation;
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass()
|
||||
{
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModContainerClass()
|
||||
{
|
||||
return "net.minecraftforge.common.ForgeModContainer";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getSetupClass()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data)
|
||||
{
|
||||
RUNTIME_DEOBF = (Boolean)data.get("runtimeDeobfuscationEnabled");
|
||||
forgeLocation = (File)data.get("coremodLocation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessTransformerClass()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiChat;
|
||||
import net.minecraft.command.CommandException;
|
||||
import net.minecraft.command.CommandHandler;
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.command.WrongUsageException;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.CommandEvent;
|
||||
import net.minecraftforge.fml.client.FMLClientHandler;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import static net.minecraft.util.text.TextFormatting.*;
|
||||
|
||||
/**
|
||||
* The class that handles client-side chat commands. You should register any
|
||||
* commands that you want handled on the client with this command handler.
|
||||
*
|
||||
* If there is a command with the same name registered both on the server and
|
||||
* client, the client takes precedence!
|
||||
*
|
||||
*/
|
||||
public class ClientCommandHandler extends CommandHandler
|
||||
{
|
||||
public static final ClientCommandHandler instance = new ClientCommandHandler();
|
||||
|
||||
public String[] latestAutoComplete = null;
|
||||
|
||||
/**
|
||||
* @return 1 if successfully executed, -1 if no permission or wrong usage,
|
||||
* 0 if it doesn't exist or it was canceled (it's sent to the server)
|
||||
*/
|
||||
/**
|
||||
* Attempt to execute a command. This method should return the number of times that the command was executed. If the
|
||||
* command does not exist or if the player does not have permission, 0 will be returned. A number greater than 1 can
|
||||
* be returned if a player selector is used.
|
||||
*/
|
||||
@Override
|
||||
public int executeCommand(ICommandSender sender, String message)
|
||||
{
|
||||
message = message.trim();
|
||||
|
||||
boolean usedSlash = message.startsWith("/");
|
||||
if (usedSlash)
|
||||
{
|
||||
message = message.substring(1);
|
||||
}
|
||||
|
||||
String[] temp = message.split(" ");
|
||||
String[] args = new String[temp.length - 1];
|
||||
String commandName = temp[0];
|
||||
System.arraycopy(temp, 1, args, 0, args.length);
|
||||
ICommand icommand = getCommands().get(commandName);
|
||||
|
||||
try
|
||||
{
|
||||
if (icommand == null || (!usedSlash && icommand instanceof IClientCommand && !((IClientCommand)icommand).allowUsageWithoutPrefix(sender, message)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (icommand.checkPermission(this.getServer(), sender))
|
||||
{
|
||||
CommandEvent event = new CommandEvent(icommand, sender, args);
|
||||
if (MinecraftForge.EVENT_BUS.post(event))
|
||||
{
|
||||
if (event.getException() != null)
|
||||
{
|
||||
throw event.getException();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
this.tryExecute(sender, args, icommand, message);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sender.sendMessage(format(RED, "commands.generic.permission"));
|
||||
}
|
||||
}
|
||||
catch (WrongUsageException wue)
|
||||
{
|
||||
sender.sendMessage(format(RED, "commands.generic.usage", format(RED, wue.getMessage(), wue.getErrorObjects())));
|
||||
}
|
||||
catch (CommandException ce)
|
||||
{
|
||||
sender.sendMessage(format(RED, ce.getMessage(), ce.getErrorObjects()));
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
sender.sendMessage(format(RED, "commands.generic.exception"));
|
||||
FMLLog.log.error("Command '{}' threw an exception:", message, t);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Couple of helpers because the mcp names are stupid and long...
|
||||
private TextComponentTranslation format(TextFormatting color, String str, Object... args)
|
||||
{
|
||||
TextComponentTranslation ret = new TextComponentTranslation(str, args);
|
||||
ret.getStyle().setColor(color);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void autoComplete(String leftOfCursor)
|
||||
{
|
||||
latestAutoComplete = null;
|
||||
|
||||
if (leftOfCursor.charAt(0) == '/')
|
||||
{
|
||||
leftOfCursor = leftOfCursor.substring(1);
|
||||
|
||||
Minecraft mc = FMLClientHandler.instance().getClient();
|
||||
if (mc.currentScreen instanceof GuiChat)
|
||||
{
|
||||
List<String> commands = getTabCompletions(mc.player, leftOfCursor, mc.player.getPosition());
|
||||
if (!commands.isEmpty())
|
||||
{
|
||||
if (leftOfCursor.indexOf(' ') == -1)
|
||||
{
|
||||
for (int i = 0; i < commands.size(); i++)
|
||||
{
|
||||
commands.set(i, GRAY + "/" + commands.get(i) + RESET);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < commands.size(); i++)
|
||||
{
|
||||
commands.set(i, GRAY + commands.get(i) + RESET);
|
||||
}
|
||||
}
|
||||
|
||||
latestAutoComplete = commands.toArray(new String[commands.size()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MinecraftServer getServer() {
|
||||
return Minecraft.getMinecraft().getIntegratedServer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraftforge.client.resource.IResourceType;
|
||||
import net.minecraftforge.client.resource.VanillaResourceType;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.GLAllocation;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
|
||||
|
||||
public class CloudRenderer implements ISelectiveResourceReloadListener
|
||||
{
|
||||
// Shared constants.
|
||||
private static final float PX_SIZE = 1 / 256F;
|
||||
|
||||
// Building constants.
|
||||
private static final VertexFormat FORMAT = DefaultVertexFormats.POSITION_TEX_COLOR;
|
||||
private static final int TOP_SECTIONS = 12; // Number of slices a top face will span.
|
||||
private static final int HEIGHT = 4;
|
||||
private static final float INSET = 0.001F;
|
||||
private static final float ALPHA = 0.8F;
|
||||
|
||||
// Debug
|
||||
private static final boolean WIREFRAME = false;
|
||||
|
||||
// Instance fields
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
private final ResourceLocation texture = new ResourceLocation("textures/environment/clouds.png");
|
||||
|
||||
private int displayList = -1;
|
||||
private VertexBuffer vbo;
|
||||
private int cloudMode = -1;
|
||||
private int renderDistance = -1;
|
||||
|
||||
private DynamicTexture COLOR_TEX = null;
|
||||
|
||||
private int texW;
|
||||
private int texH;
|
||||
|
||||
public CloudRenderer()
|
||||
{
|
||||
// Resource manager should always be reloadable.
|
||||
((IReloadableResourceManager) mc.getResourceManager()).registerReloadListener(this);
|
||||
}
|
||||
|
||||
private int getScale()
|
||||
{
|
||||
return cloudMode == 2 ? 12 : 8;
|
||||
}
|
||||
|
||||
private float ceilToScale(float value)
|
||||
{
|
||||
float scale = getScale();
|
||||
return MathHelper.ceil(value / scale) * scale;
|
||||
}
|
||||
|
||||
private void vertices(BufferBuilder buffer)
|
||||
{
|
||||
boolean fancy = cloudMode == 2; // Defines whether to hide all but the bottom.
|
||||
|
||||
float scale = getScale();
|
||||
float CULL_DIST = 2 * scale;
|
||||
|
||||
float bCol = fancy ? 0.7F : 1F;
|
||||
|
||||
float sectEnd = ceilToScale((renderDistance * 2) * 16);
|
||||
float sectStart = -sectEnd;
|
||||
|
||||
float sectStep = ceilToScale(sectEnd * 2 / TOP_SECTIONS);
|
||||
float sectPx = PX_SIZE / scale;
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, FORMAT);
|
||||
|
||||
float sectX0 = sectStart;
|
||||
float sectX1 = sectX0;
|
||||
|
||||
while (sectX1 < sectEnd)
|
||||
{
|
||||
sectX1 += sectStep;
|
||||
|
||||
if (sectX1 > sectEnd)
|
||||
sectX1 = sectEnd;
|
||||
|
||||
float sectZ0 = sectStart;
|
||||
float sectZ1 = sectZ0;
|
||||
|
||||
while (sectZ1 < sectEnd)
|
||||
{
|
||||
sectZ1 += sectStep;
|
||||
|
||||
if (sectZ1 > sectEnd)
|
||||
sectZ1 = sectEnd;
|
||||
|
||||
float u0 = sectX0 * sectPx;
|
||||
float u1 = sectX1 * sectPx;
|
||||
float v0 = sectZ0 * sectPx;
|
||||
float v1 = sectZ1 * sectPx;
|
||||
|
||||
// Bottom
|
||||
buffer.pos(sectX0, 0, sectZ0).tex(u0, v0).color(bCol, bCol, bCol, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, 0, sectZ0).tex(u1, v0).color(bCol, bCol, bCol, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, 0, sectZ1).tex(u1, v1).color(bCol, bCol, bCol, ALPHA).endVertex();
|
||||
buffer.pos(sectX0, 0, sectZ1).tex(u0, v1).color(bCol, bCol, bCol, ALPHA).endVertex();
|
||||
|
||||
if (fancy)
|
||||
{
|
||||
// Top
|
||||
buffer.pos(sectX0, HEIGHT, sectZ0).tex(u0, v0).color(1, 1, 1, ALPHA).endVertex();
|
||||
buffer.pos(sectX0, HEIGHT, sectZ1).tex(u0, v1).color(1, 1, 1, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, HEIGHT, sectZ1).tex(u1, v1).color(1, 1, 1, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, HEIGHT, sectZ0).tex(u1, v0).color(1, 1, 1, ALPHA).endVertex();
|
||||
|
||||
float slice;
|
||||
float sliceCoord0;
|
||||
float sliceCoord1;
|
||||
|
||||
for (slice = sectX0; slice < sectX1;)
|
||||
{
|
||||
sliceCoord0 = slice * sectPx;
|
||||
sliceCoord1 = sliceCoord0 + PX_SIZE;
|
||||
|
||||
// X sides
|
||||
if (slice > -CULL_DIST)
|
||||
{
|
||||
slice += INSET;
|
||||
buffer.pos(slice, 0, sectZ1).tex(sliceCoord0, v1).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
buffer.pos(slice, HEIGHT, sectZ1).tex(sliceCoord1, v1).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
buffer.pos(slice, HEIGHT, sectZ0).tex(sliceCoord1, v0).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
buffer.pos(slice, 0, sectZ0).tex(sliceCoord0, v0).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
slice -= INSET;
|
||||
}
|
||||
|
||||
slice += scale;
|
||||
|
||||
if (slice <= CULL_DIST)
|
||||
{
|
||||
slice -= INSET;
|
||||
buffer.pos(slice, 0, sectZ0).tex(sliceCoord0, v0).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
buffer.pos(slice, HEIGHT, sectZ0).tex(sliceCoord1, v0).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
buffer.pos(slice, HEIGHT, sectZ1).tex(sliceCoord1, v1).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
buffer.pos(slice, 0, sectZ1).tex(sliceCoord0, v1).color(0.9F, 0.9F, 0.9F, ALPHA).endVertex();
|
||||
slice += INSET;
|
||||
}
|
||||
}
|
||||
|
||||
for (slice = sectZ0; slice < sectZ1;)
|
||||
{
|
||||
sliceCoord0 = slice * sectPx;
|
||||
sliceCoord1 = sliceCoord0 + PX_SIZE;
|
||||
|
||||
// Z sides
|
||||
if (slice > -CULL_DIST)
|
||||
{
|
||||
slice += INSET;
|
||||
buffer.pos(sectX0, 0, slice).tex(u0, sliceCoord0).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
buffer.pos(sectX0, HEIGHT, slice).tex(u0, sliceCoord1).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, HEIGHT, slice).tex(u1, sliceCoord1).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, 0, slice).tex(u1, sliceCoord0).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
slice -= INSET;
|
||||
}
|
||||
|
||||
slice += scale;
|
||||
|
||||
if (slice <= CULL_DIST)
|
||||
{
|
||||
slice -= INSET;
|
||||
buffer.pos(sectX1, 0, slice).tex(u1, sliceCoord0).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
buffer.pos(sectX1, HEIGHT, slice).tex(u1, sliceCoord1).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
buffer.pos(sectX0, HEIGHT, slice).tex(u0, sliceCoord1).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
buffer.pos(sectX0, 0, slice).tex(u0, sliceCoord0).color(0.8F, 0.8F, 0.8F, ALPHA).endVertex();
|
||||
slice += INSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sectZ0 = sectZ1;
|
||||
}
|
||||
|
||||
sectX0 = sectX1;
|
||||
}
|
||||
}
|
||||
|
||||
private void dispose()
|
||||
{
|
||||
if (vbo != null)
|
||||
{
|
||||
vbo.deleteGlBuffers();
|
||||
vbo = null;
|
||||
}
|
||||
if (displayList >= 0)
|
||||
{
|
||||
GLAllocation.deleteDisplayLists(displayList);
|
||||
displayList = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void build()
|
||||
{
|
||||
Tessellator tess = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tess.getBuffer();
|
||||
|
||||
if (OpenGlHelper.useVbo())
|
||||
vbo = new VertexBuffer(FORMAT);
|
||||
else
|
||||
GlStateManager.glNewList(displayList = GLAllocation.generateDisplayLists(1), GL11.GL_COMPILE);
|
||||
|
||||
vertices(buffer);
|
||||
|
||||
if (OpenGlHelper.useVbo())
|
||||
{
|
||||
buffer.finishDrawing();
|
||||
buffer.reset();
|
||||
vbo.bufferData(buffer.getByteBuffer());
|
||||
}
|
||||
else
|
||||
{
|
||||
tess.draw();
|
||||
GlStateManager.glEndList();
|
||||
}
|
||||
}
|
||||
|
||||
private int fullCoord(double coord, int scale)
|
||||
{ // Corrects misalignment of UV offset when on negative coords.
|
||||
return ((int) coord / scale) - (coord < 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
private boolean isBuilt()
|
||||
{
|
||||
return OpenGlHelper.useVbo() ? vbo != null : displayList >= 0;
|
||||
}
|
||||
|
||||
public void checkSettings()
|
||||
{
|
||||
boolean newEnabled = ForgeModContainer.forgeCloudsEnabled
|
||||
&& mc.gameSettings.shouldRenderClouds() != 0
|
||||
&& mc.world != null
|
||||
&& mc.world.provider.isSurfaceWorld();
|
||||
|
||||
if (isBuilt()
|
||||
&& (!newEnabled
|
||||
|| mc.gameSettings.shouldRenderClouds() != cloudMode
|
||||
|| mc.gameSettings.renderDistanceChunks != renderDistance))
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
cloudMode = mc.gameSettings.shouldRenderClouds();
|
||||
renderDistance = mc.gameSettings.renderDistanceChunks;
|
||||
|
||||
if (newEnabled && !isBuilt())
|
||||
{
|
||||
build();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean render(int cloudTicks, float partialTicks)
|
||||
{
|
||||
if (!isBuilt())
|
||||
return false;
|
||||
|
||||
Entity entity = mc.getRenderViewEntity();
|
||||
|
||||
double totalOffset = cloudTicks + partialTicks;
|
||||
|
||||
double x = entity.prevPosX + (entity.posX - entity.prevPosX) * partialTicks
|
||||
+ totalOffset * 0.03;
|
||||
double y = mc.world.provider.getCloudHeight()
|
||||
- (entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks)
|
||||
+ 0.33;
|
||||
double z = entity.prevPosZ + (entity.posZ - entity.prevPosZ) * partialTicks;
|
||||
|
||||
int scale = getScale();
|
||||
|
||||
if (cloudMode == 2)
|
||||
z += 0.33 * scale;
|
||||
|
||||
// Integer UVs to translate the texture matrix by.
|
||||
int offU = fullCoord(x, scale);
|
||||
int offV = fullCoord(z, scale);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
// Translate by the remainder after the UV offset.
|
||||
GlStateManager.translate((offU * scale) - x, y, (offV * scale) - z);
|
||||
|
||||
// Modulo to prevent texture samples becoming inaccurate at extreme offsets.
|
||||
offU = offU % texW;
|
||||
offV = offV % texH;
|
||||
|
||||
// Translate the texture.
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.translate(offU * PX_SIZE, offV * PX_SIZE, 0);
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.disableCull();
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(
|
||||
GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA,
|
||||
GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
|
||||
// Color multiplier.
|
||||
Vec3d color = mc.world.getCloudColour(partialTicks);
|
||||
float r = (float) color.x;
|
||||
float g = (float) color.y;
|
||||
float b = (float) color.z;
|
||||
|
||||
if (mc.gameSettings.anaglyph)
|
||||
{
|
||||
float tempR = r * 0.3F + g * 0.59F + b * 0.11F;
|
||||
float tempG = r * 0.3F + g * 0.7F;
|
||||
float tempB = r * 0.3F + b * 0.7F;
|
||||
r = tempR;
|
||||
g = tempG;
|
||||
b = tempB;
|
||||
}
|
||||
|
||||
if (COLOR_TEX == null)
|
||||
COLOR_TEX = new DynamicTexture(1, 1);
|
||||
|
||||
// Apply a color multiplier through a texture upload if shaders aren't supported.
|
||||
COLOR_TEX.getTextureData()[0] = 255 << 24
|
||||
| ((int) (r * 255)) << 16
|
||||
| ((int) (g * 255)) << 8
|
||||
| (int) (b * 255);
|
||||
COLOR_TEX.updateDynamicTexture();
|
||||
|
||||
GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
GlStateManager.bindTexture(COLOR_TEX.getGlTextureId());
|
||||
GlStateManager.enableTexture2D();
|
||||
|
||||
// Bind the clouds texture last so the shader's sampler2D is correct.
|
||||
GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
mc.renderEngine.bindTexture(texture);
|
||||
|
||||
ByteBuffer buffer = Tessellator.getInstance().getBuffer().getByteBuffer();
|
||||
|
||||
// Set up pointers for the display list/VBO.
|
||||
if (OpenGlHelper.useVbo())
|
||||
{
|
||||
vbo.bindBuffer();
|
||||
|
||||
int stride = FORMAT.getNextOffset();
|
||||
GlStateManager.glVertexPointer(3, GL11.GL_FLOAT, stride, 0);
|
||||
GlStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
GlStateManager.glTexCoordPointer(2, GL11.GL_FLOAT, stride, 12);
|
||||
GlStateManager.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GlStateManager.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, stride, 20);
|
||||
GlStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.limit(FORMAT.getNextOffset());
|
||||
for (int i = 0; i < FORMAT.getElementCount(); i++)
|
||||
FORMAT.getElements().get(i).getUsage().preDraw(FORMAT, i, FORMAT.getNextOffset(), buffer);
|
||||
buffer.position(0);
|
||||
}
|
||||
|
||||
// Depth pass to prevent insides rendering from the outside.
|
||||
GlStateManager.colorMask(false, false, false, false);
|
||||
if (OpenGlHelper.useVbo())
|
||||
vbo.drawArrays(GL11.GL_QUADS);
|
||||
else
|
||||
GlStateManager.callList(displayList);
|
||||
|
||||
// Full render.
|
||||
if (!mc.gameSettings.anaglyph)
|
||||
{
|
||||
GlStateManager.colorMask(true, true, true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (EntityRenderer.anaglyphField)
|
||||
{
|
||||
case 0:
|
||||
GlStateManager.colorMask(false, true, true, true);
|
||||
break;
|
||||
case 1:
|
||||
GlStateManager.colorMask(true, false, false, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wireframe for debug.
|
||||
if (WIREFRAME)
|
||||
{
|
||||
GlStateManager.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
|
||||
GlStateManager.glLineWidth(2.0F);
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.depthMask(false);
|
||||
GlStateManager.disableFog();
|
||||
if (OpenGlHelper.useVbo())
|
||||
vbo.drawArrays(GL11.GL_QUADS);
|
||||
else
|
||||
GlStateManager.callList(displayList);
|
||||
GlStateManager.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
||||
GlStateManager.depthMask(true);
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.enableFog();
|
||||
}
|
||||
|
||||
if (OpenGlHelper.useVbo())
|
||||
{
|
||||
vbo.drawArrays(GL11.GL_QUADS);
|
||||
vbo.unbindBuffer(); // Unbind buffer and disable pointers.
|
||||
}
|
||||
else
|
||||
{
|
||||
GlStateManager.callList(displayList);
|
||||
}
|
||||
|
||||
buffer.limit(0);
|
||||
for (int i = 0; i < FORMAT.getElementCount(); i++)
|
||||
FORMAT.getElements().get(i).getUsage().postDraw(FORMAT, i, FORMAT.getNextOffset(), buffer);
|
||||
buffer.position(0);
|
||||
|
||||
// Disable our coloring.
|
||||
GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
|
||||
// Reset texture matrix.
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableCull();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void reloadTextures()
|
||||
{
|
||||
if (mc.renderEngine != null)
|
||||
{
|
||||
mc.renderEngine.bindTexture(texture);
|
||||
texW = GlStateManager.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH);
|
||||
texH = GlStateManager.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(@Nonnull IResourceManager resourceManager, @Nonnull Predicate<IResourceType> resourcePredicate)
|
||||
{
|
||||
if (resourcePredicate.test(VanillaResourceType.TEXTURES))
|
||||
{
|
||||
reloadTextures();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import net.minecraft.client.audio.MusicTicker;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.Util.EnumOS;
|
||||
import net.minecraft.world.GameType;
|
||||
import net.minecraft.client.settings.GameSettings.Options;
|
||||
import net.minecraftforge.common.util.EnumHelper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class EnumHelperClient extends EnumHelper
|
||||
{
|
||||
private static Class<?>[][] clientTypes =
|
||||
{
|
||||
{GameType.class, int.class, String.class, String.class},
|
||||
{Options.class, String.class, boolean.class, boolean.class},
|
||||
{EnumOS.class},
|
||||
{MusicTicker.MusicType.class, SoundEvent.class, int.class, int.class}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
public static GameType addGameType(String name, int id, String displayName, String shortName)
|
||||
{
|
||||
return addEnum(GameType.class, name, id, displayName, shortName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Options addOptions(String name, String langName, boolean isSlider, boolean isToggle)
|
||||
{
|
||||
return addEnum(Options.class, name, langName, isSlider, isToggle);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Options addOptions(String name, String langName, boolean isSlider, boolean isToggle, float valMin, float valMax, float valStep)
|
||||
{
|
||||
return addEnum(Options.class, name,
|
||||
new Class<?>[]{String.class, boolean.class, boolean.class, float.class, float.class, float.class},
|
||||
langName, isSlider, isToggle, valMin, valMax, valStep);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EnumOS addOS2(String name)
|
||||
{
|
||||
return addEnum(EnumOS.class, name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static MusicTicker.MusicType addMusicType(String name, SoundEvent sound, int minDelay, int maxDelay)
|
||||
{
|
||||
return addEnum(MusicTicker.MusicType.class, name, sound, minDelay, maxDelay);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Object... paramValues)
|
||||
{
|
||||
return addEnum(clientTypes, enumType, enumName, paramValues);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import net.minecraft.client.renderer.color.IItemColor;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class FluidContainerColorer implements IItemColor
|
||||
{
|
||||
@Override
|
||||
public int colorMultiplier(@Nonnull ItemStack stack, int tintIndex)
|
||||
{
|
||||
if (tintIndex != 1) return 0xFFFFFFFF;
|
||||
FluidStack fluidStack = FluidUtil.getFluidContained(stack);
|
||||
if (fluidStack == null) return 0xFFFFFFFF;
|
||||
return fluidStack.getFluid().getColor(fluidStack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import net.minecraftforge.client.event.ColorHandlerEvent;
|
||||
import net.minecraftforge.client.event.ModelRegistryEvent;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
public class ForgeClientHandler
|
||||
{
|
||||
@SubscribeEvent
|
||||
public static void registerModels(ModelRegistryEvent event)
|
||||
{
|
||||
// register model for the universal bucket, if it exists
|
||||
if (FluidRegistry.isUniversalBucketEnabled())
|
||||
{
|
||||
ModelLoader.setBucketModelDefinition(ForgeModContainer.getInstance().universalBucket);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerItemHandlers(ColorHandlerEvent.Item event)
|
||||
{
|
||||
if (FluidRegistry.isUniversalBucketEnabled())
|
||||
{
|
||||
event.getItemColors().registerItemColorHandler(new FluidContainerColorer(), ForgeModContainer.getInstance().universalBucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,784 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.BOSSINFO;
|
||||
import static net.minecraftforge.common.ForgeVersion.Status.BETA;
|
||||
import static net.minecraftforge.common.ForgeVersion.Status.BETA_OUTDATED;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.vecmath.Matrix3f;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Vector3f;
|
||||
import javax.vecmath.Vector4f;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundHandler;
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
import net.minecraft.client.gui.BossInfoClient;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.renderer.BlockRendererDispatcher;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.RenderItem;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.BlockFaceUV;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransformVec3f;
|
||||
import net.minecraft.client.renderer.block.model.ModelManager;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.model.ModelRotation;
|
||||
import net.minecraft.client.renderer.block.model.SimpleBakedModel;
|
||||
import net.minecraft.client.renderer.color.BlockColors;
|
||||
import net.minecraft.client.renderer.color.ItemColors;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
|
||||
import net.minecraft.client.resources.FoliageColorReloadListener;
|
||||
import net.minecraft.client.resources.GrassColorReloadListener;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.client.resources.LanguageManager;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.client.util.SearchTreeManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.passive.EntityHorse;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.MovementInput;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.registry.IRegistry;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraftforge.client.event.ColorHandlerEvent;
|
||||
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
|
||||
import net.minecraftforge.client.event.EntityViewRenderEvent;
|
||||
import net.minecraftforge.client.event.FOVUpdateEvent;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.client.event.InputUpdateEvent;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.event.MouseEvent;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.client.event.RenderSpecificHandEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.client.event.ScreenshotEvent;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.client.event.sound.PlaySoundEvent;
|
||||
import net.minecraftforge.client.model.ModelDynBucket;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.animation.Animation;
|
||||
import net.minecraftforge.client.resource.IResourceType;
|
||||
import net.minecraftforge.client.resource.SelectiveReloadStateHandler;
|
||||
import net.minecraftforge.client.resource.VanillaResourceType;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.ForgeVersion.Status;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.model.IModelPart;
|
||||
import net.minecraftforge.common.model.ITransformation;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.fml.client.FMLClientHandler;
|
||||
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class ForgeHooksClient
|
||||
{
|
||||
//private static final ResourceLocation ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
|
||||
|
||||
static TextureManager engine()
|
||||
{
|
||||
return FMLClientHandler.instance().getClient().renderEngine;
|
||||
}
|
||||
|
||||
public static String getArmorTexture(Entity entity, ItemStack armor, String _default, EntityEquipmentSlot slot, String type)
|
||||
{
|
||||
String result = armor.getItem().getArmorTexture(armor, entity, slot, type);
|
||||
return result != null ? result : _default;
|
||||
}
|
||||
|
||||
//Optifine Helper Functions u.u, these are here specifically for Optifine
|
||||
//Note: When using Optifine, these methods are invoked using reflection, which
|
||||
//incurs a major performance penalty.
|
||||
public static void orientBedCamera(IBlockAccess world, BlockPos pos, IBlockState state, Entity entity)
|
||||
{
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block != null && block.isBed(state, world, pos, entity))
|
||||
{
|
||||
GL11.glRotatef((float)(block.getBedDirection(state, world, pos).getHorizontalIndex() * 90), 0.0F, 1.0F, 0.0F);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, RayTraceResult target, int subID, float partialTicks)
|
||||
{
|
||||
return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, partialTicks));
|
||||
}
|
||||
|
||||
public static void dispatchRenderLast(RenderGlobal context, float partialTicks)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, partialTicks));
|
||||
}
|
||||
|
||||
public static boolean renderFirstPersonHand(RenderGlobal context, float partialTicks, int renderPass)
|
||||
{
|
||||
return MinecraftForge.EVENT_BUS.post(new RenderHandEvent(context, partialTicks, renderPass));
|
||||
}
|
||||
|
||||
public static boolean renderSpecificFirstPersonHand(EnumHand hand, float partialTicks, float interpPitch, float swingProgress, float equipProgress, ItemStack stack)
|
||||
{
|
||||
return MinecraftForge.EVENT_BUS.post(new RenderSpecificHandEvent(hand, partialTicks, interpPitch, swingProgress, equipProgress, stack));
|
||||
}
|
||||
|
||||
public static void onTextureStitchedPre(TextureMap map)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Pre(map));
|
||||
ModelLoader.White.INSTANCE.register(map);
|
||||
ModelDynBucket.LoaderDynBucket.INSTANCE.register(map);
|
||||
}
|
||||
|
||||
public static void onTextureStitchedPost(TextureMap map)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
|
||||
}
|
||||
|
||||
public static void onBlockColorsInit(BlockColors blockColors)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new ColorHandlerEvent.Block(blockColors));
|
||||
}
|
||||
|
||||
public static void onItemColorsInit(ItemColors itemColors, BlockColors blockColors)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new ColorHandlerEvent.Item(itemColors, blockColors));
|
||||
}
|
||||
|
||||
static int renderPass = -1;
|
||||
public static void setRenderPass(int pass)
|
||||
{
|
||||
renderPass = pass;
|
||||
}
|
||||
|
||||
static final ThreadLocal<BlockRenderLayer> renderLayer = new ThreadLocal<BlockRenderLayer>();
|
||||
|
||||
public static void setRenderLayer(BlockRenderLayer layer)
|
||||
{
|
||||
renderLayer.set(layer);
|
||||
}
|
||||
|
||||
public static ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, EntityEquipmentSlot slot, ModelBiped _default)
|
||||
{
|
||||
ModelBiped model = itemStack.getItem().getArmorModel(entityLiving, itemStack, slot, _default);
|
||||
return model == null ? _default : model;
|
||||
}
|
||||
|
||||
//This properly moves the domain, if provided, to the front of the string before concatenating
|
||||
public static String fixDomain(String base, String complex)
|
||||
{
|
||||
int idx = complex.indexOf(':');
|
||||
if (idx == -1)
|
||||
{
|
||||
return base + complex;
|
||||
}
|
||||
|
||||
String name = complex.substring(idx + 1, complex.length());
|
||||
if (idx > 1)
|
||||
{
|
||||
String domain = complex.substring(0, idx);
|
||||
return domain + ':' + base + name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base + name;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean postMouseEvent()
|
||||
{
|
||||
return MinecraftForge.EVENT_BUS.post(new MouseEvent());
|
||||
}
|
||||
|
||||
public static float getOffsetFOV(EntityPlayer entity, float fov)
|
||||
{
|
||||
FOVUpdateEvent fovUpdateEvent = new FOVUpdateEvent(entity, fov);
|
||||
MinecraftForge.EVENT_BUS.post(fovUpdateEvent);
|
||||
return fovUpdateEvent.getNewfov();
|
||||
}
|
||||
|
||||
public static float getFOVModifier(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks, float fov) {
|
||||
EntityViewRenderEvent.FOVModifier event = new EntityViewRenderEvent.FOVModifier(renderer, entity, state, renderPartialTicks, fov);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event.getFOV();
|
||||
}
|
||||
|
||||
private static int skyX, skyZ;
|
||||
|
||||
private static boolean skyInit;
|
||||
private static int skyRGBMultiplier;
|
||||
|
||||
public static int getSkyBlendColour(World world, BlockPos center)
|
||||
{
|
||||
if (center.getX() == skyX && center.getZ() == skyZ && skyInit)
|
||||
{
|
||||
return skyRGBMultiplier;
|
||||
}
|
||||
skyInit = true;
|
||||
|
||||
GameSettings settings = Minecraft.getMinecraft().gameSettings;
|
||||
int[] ranges = ForgeModContainer.blendRanges;
|
||||
int distance = 0;
|
||||
if (settings.fancyGraphics && ranges.length > 0)
|
||||
{
|
||||
distance = ranges[MathHelper.clamp(settings.renderDistanceChunks, 0, ranges.length-1)];
|
||||
}
|
||||
|
||||
int r = 0;
|
||||
int g = 0;
|
||||
int b = 0;
|
||||
|
||||
int divider = 0;
|
||||
for (int x = -distance; x <= distance; ++x)
|
||||
{
|
||||
for (int z = -distance; z <= distance; ++z)
|
||||
{
|
||||
BlockPos pos = center.add(x, 0, z);
|
||||
Biome biome = world.getBiome(pos);
|
||||
int colour = biome.getSkyColorByTemp(biome.getTemperature(pos));
|
||||
r += (colour & 0xFF0000) >> 16;
|
||||
g += (colour & 0x00FF00) >> 8;
|
||||
b += colour & 0x0000FF;
|
||||
divider++;
|
||||
}
|
||||
}
|
||||
|
||||
int multiplier = (r / divider & 255) << 16 | (g / divider & 255) << 8 | b / divider & 255;
|
||||
|
||||
skyX = center.getX();
|
||||
skyZ = center.getZ();
|
||||
skyRGBMultiplier = multiplier;
|
||||
return skyRGBMultiplier;
|
||||
}
|
||||
/**
|
||||
* Initialization of Forge Renderers.
|
||||
*/
|
||||
static
|
||||
{
|
||||
//FluidRegistry.renderIdFluid = RenderingRegistry.getNextAvailableRenderId();
|
||||
//RenderingRegistry.registerBlockHandler(RenderBlockFluid.instance);
|
||||
}
|
||||
|
||||
private static int updatescrollcounter = 0;
|
||||
public static String renderMainMenu(GuiMainMenu gui, FontRenderer font, int width, int height, String splashText)
|
||||
{
|
||||
Status status = ForgeVersion.getStatus();
|
||||
if (status == BETA || status == BETA_OUTDATED)
|
||||
{
|
||||
// render a warning at the top of the screen,
|
||||
String line = I18n.format("forge.update.beta.1", TextFormatting.RED, TextFormatting.RESET);
|
||||
gui.drawString(font, line, (width - font.getStringWidth(line)) / 2, 4 + (0 * (font.FONT_HEIGHT + 1)), -1);
|
||||
line = I18n.format("forge.update.beta.2");
|
||||
gui.drawString(font, line, (width - font.getStringWidth(line)) / 2, 4 + (1 * (font.FONT_HEIGHT + 1)), -1);
|
||||
}
|
||||
|
||||
String line = null;
|
||||
switch(status)
|
||||
{
|
||||
//case FAILED: line = " Version check failed"; break;
|
||||
//case UP_TO_DATE: line = "Forge up to date"}; break;
|
||||
//case AHEAD: line = "Using non-recommended Forge build, issues may arise."}; break;
|
||||
case OUTDATED:
|
||||
case BETA_OUTDATED: line = I18n.format("forge.update.newversion", ForgeVersion.getTarget()); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (line != null)
|
||||
{
|
||||
// if we have a line, render it in the bottom right, above Mojang's copyright line
|
||||
gui.drawString(font, line, width - font.getStringWidth(line) - 2, height - (2 * (font.FONT_HEIGHT + 1)), -1);
|
||||
}
|
||||
|
||||
return splashText;
|
||||
}
|
||||
|
||||
public static ISound playSound(SoundManager manager, ISound sound)
|
||||
{
|
||||
PlaySoundEvent e = new PlaySoundEvent(manager, sound);
|
||||
MinecraftForge.EVENT_BUS.post(e);
|
||||
return e.getResultSound();
|
||||
}
|
||||
|
||||
//static RenderBlocks VertexBufferRB;
|
||||
static int worldRenderPass;
|
||||
|
||||
public static int getWorldRenderPass()
|
||||
{
|
||||
return worldRenderPass;
|
||||
}
|
||||
|
||||
public static void drawScreen(GuiScreen screen, int mouseX, int mouseY, float partialTicks)
|
||||
{
|
||||
if (!MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.DrawScreenEvent.Pre(screen, mouseX, mouseY, partialTicks)))
|
||||
screen.drawScreen(mouseX, mouseY, partialTicks);
|
||||
MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.DrawScreenEvent.Post(screen, mouseX, mouseY, partialTicks));
|
||||
}
|
||||
|
||||
public static float getFogDensity(EntityRenderer renderer, Entity entity, IBlockState state, float partial, float density)
|
||||
{
|
||||
EntityViewRenderEvent.FogDensity event = new EntityViewRenderEvent.FogDensity(renderer, entity, state, partial, density);
|
||||
if (MinecraftForge.EVENT_BUS.post(event)) return event.getDensity();
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void onFogRender(EntityRenderer renderer, Entity entity, IBlockState state, float partial, int mode, float distance)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new EntityViewRenderEvent.RenderFogEvent(renderer, entity, state, partial, mode, distance));
|
||||
}
|
||||
|
||||
public static void onModelBake(ModelManager modelManager, IRegistry<ModelResourceLocation, IBakedModel> modelRegistry, ModelLoader modelLoader)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new ModelBakeEvent(modelManager, modelRegistry, modelLoader));
|
||||
modelLoader.onPostBakeEvent(modelRegistry);
|
||||
}
|
||||
|
||||
private static final Matrix4f flipX;
|
||||
static {
|
||||
flipX = new Matrix4f();
|
||||
flipX.setIdentity();
|
||||
flipX.m00 = -1;
|
||||
}
|
||||
|
||||
public static IBakedModel handleCameraTransforms(IBakedModel model, ItemCameraTransforms.TransformType cameraTransformType, boolean leftHandHackery)
|
||||
{
|
||||
Pair<? extends IBakedModel, Matrix4f> pair = model.handlePerspective(cameraTransformType);
|
||||
|
||||
if (pair.getRight() != null)
|
||||
{
|
||||
Matrix4f matrix = new Matrix4f(pair.getRight());
|
||||
if (leftHandHackery)
|
||||
{
|
||||
matrix.mul(flipX, matrix);
|
||||
matrix.mul(matrix, flipX);
|
||||
}
|
||||
multiplyCurrentGlMatrix(matrix);
|
||||
}
|
||||
return pair.getLeft();
|
||||
}
|
||||
|
||||
private static final FloatBuffer matrixBuf = BufferUtils.createFloatBuffer(16);
|
||||
|
||||
public static void multiplyCurrentGlMatrix(Matrix4f matrix)
|
||||
{
|
||||
matrixBuf.clear();
|
||||
float[] t = new float[4];
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
matrix.getColumn(i, t);
|
||||
matrixBuf.put(t);
|
||||
}
|
||||
matrixBuf.flip();
|
||||
GL11.glMultMatrix(matrixBuf);
|
||||
}
|
||||
|
||||
// moved and expanded from WorldVertexBufferUploader.draw
|
||||
|
||||
public static void preDraw(EnumUsage attrType, VertexFormat format, int element, int stride, ByteBuffer buffer)
|
||||
{
|
||||
VertexFormatElement attr = format.getElement(element);
|
||||
int count = attr.getElementCount();
|
||||
int constant = attr.getType().getGlConstant();
|
||||
buffer.position(format.getOffset(element));
|
||||
switch(attrType)
|
||||
{
|
||||
case POSITION:
|
||||
GlStateManager.glVertexPointer(count, constant, stride, buffer);
|
||||
GlStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
break;
|
||||
case NORMAL:
|
||||
if(count != 3)
|
||||
{
|
||||
throw new IllegalArgumentException("Normal attribute should have the size 3: " + attr);
|
||||
}
|
||||
GlStateManager.glNormalPointer(constant, stride, buffer);
|
||||
GlStateManager.glEnableClientState(GL11.GL_NORMAL_ARRAY);
|
||||
break;
|
||||
case COLOR:
|
||||
GlStateManager.glColorPointer(count, constant, stride, buffer);
|
||||
GlStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY);
|
||||
break;
|
||||
case UV:
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + attr.getIndex());
|
||||
GlStateManager.glTexCoordPointer(count, constant, stride, buffer);
|
||||
GlStateManager.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
break;
|
||||
case PADDING:
|
||||
break;
|
||||
case GENERIC:
|
||||
GL20.glEnableVertexAttribArray(attr.getIndex());
|
||||
GL20.glVertexAttribPointer(attr.getIndex(), count, constant, false, stride, buffer);
|
||||
default:
|
||||
FMLLog.log.fatal("Unimplemented vanilla attribute upload: {}", attrType.getDisplayName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void postDraw(EnumUsage attrType, VertexFormat format, int element, int stride, ByteBuffer buffer)
|
||||
{
|
||||
VertexFormatElement attr = format.getElement(element);
|
||||
switch(attrType)
|
||||
{
|
||||
case POSITION:
|
||||
GlStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
break;
|
||||
case NORMAL:
|
||||
GlStateManager.glDisableClientState(GL11.GL_NORMAL_ARRAY);
|
||||
break;
|
||||
case COLOR:
|
||||
GlStateManager.glDisableClientState(GL11.GL_COLOR_ARRAY);
|
||||
// is this really needed?
|
||||
GlStateManager.resetColor();
|
||||
break;
|
||||
case UV:
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + attr.getIndex());
|
||||
GlStateManager.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
break;
|
||||
case PADDING:
|
||||
break;
|
||||
case GENERIC:
|
||||
GL20.glDisableVertexAttribArray(attr.getIndex());
|
||||
default:
|
||||
FMLLog.log.fatal("Unimplemented vanilla attribute upload: {}", attrType.getDisplayName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void transform(org.lwjgl.util.vector.Vector3f vec, Matrix4f m)
|
||||
{
|
||||
Vector4f tmp = new Vector4f(vec.x, vec.y, vec.z, 1f);
|
||||
m.transform(tmp);
|
||||
if(Math.abs(tmp.w - 1f) > 1e-5) tmp.scale(1f / tmp.w);
|
||||
vec.set(tmp.x, tmp.y, tmp.z);
|
||||
}
|
||||
|
||||
public static Matrix4f getMatrix(ModelRotation modelRotation)
|
||||
{
|
||||
Matrix4f ret = new Matrix4f(TRSRTransformation.toVecmath(modelRotation.getMatrix4d())), tmp = new Matrix4f();
|
||||
tmp.setIdentity();
|
||||
tmp.m03 = tmp.m13 = tmp.m23 = .5f;
|
||||
ret.mul(tmp, ret);
|
||||
tmp.invert();
|
||||
//tmp.m03 = tmp.m13 = tmp.m23 = -.5f;
|
||||
ret.mul(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void putQuadColor(BufferBuilder renderer, BakedQuad quad, int color)
|
||||
{
|
||||
float cb = color & 0xFF;
|
||||
float cg = (color >>> 8) & 0xFF;
|
||||
float cr = (color >>> 16) & 0xFF;
|
||||
float ca = (color >>> 24) & 0xFF;
|
||||
VertexFormat format = quad.getFormat();
|
||||
int size = format.getIntegerSize();
|
||||
int offset = format.getColorOffset() / 4; // assumes that color is aligned
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
int vc = quad.getVertexData()[offset + size * i];
|
||||
float vcr = vc & 0xFF;
|
||||
float vcg = (vc >>> 8) & 0xFF;
|
||||
float vcb = (vc >>> 16) & 0xFF;
|
||||
float vca = (vc >>> 24) & 0xFF;
|
||||
int ncr = Math.min(0xFF, (int)(cr * vcr / 0xFF));
|
||||
int ncg = Math.min(0xFF, (int)(cg * vcg / 0xFF));
|
||||
int ncb = Math.min(0xFF, (int)(cb * vcb / 0xFF));
|
||||
int nca = Math.min(0xFF, (int)(ca * vca / 0xFF));
|
||||
renderer.putColorRGBA(renderer.getColorIndex(4 - i), ncr, ncg, ncb, nca);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Pair<Item, Integer>, Class<? extends TileEntity>> tileItemMap = Maps.newHashMap();
|
||||
|
||||
public static void renderTileItem(Item item, int metadata)
|
||||
{
|
||||
Class<? extends TileEntity> tileClass = tileItemMap.get(Pair.of(item, metadata));
|
||||
if (tileClass != null)
|
||||
{
|
||||
TileEntitySpecialRenderer<?> r = TileEntityRendererDispatcher.instance.getRenderer(tileClass);
|
||||
if (r != null)
|
||||
{
|
||||
r.render(null, 0, 0, 0, 0, -1, 0.0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Will be removed as soon as possible. See {@link Item#getTileEntityItemStackRenderer()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void registerTESRItemStack(Item item, int metadata, Class<? extends TileEntity> TileClass)
|
||||
{
|
||||
tileItemMap.put(Pair.of(item, metadata), TileClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* internal, relies on fixed format of FaceBakery
|
||||
*/
|
||||
public static void fillNormal(int[] faceData, EnumFacing facing)
|
||||
{
|
||||
Vector3f v1 = getVertexPos(faceData, 3);
|
||||
Vector3f t = getVertexPos(faceData, 1);
|
||||
Vector3f v2 = getVertexPos(faceData, 2);
|
||||
v1.sub(t);
|
||||
t.set(getVertexPos(faceData, 0));
|
||||
v2.sub(t);
|
||||
v1.cross(v2, v1);
|
||||
v1.normalize();
|
||||
|
||||
int x = ((byte) Math.round(v1.x * 127)) & 0xFF;
|
||||
int y = ((byte) Math.round(v1.y * 127)) & 0xFF;
|
||||
int z = ((byte) Math.round(v1.z * 127)) & 0xFF;
|
||||
|
||||
int normal = x | (y << 0x08) | (z << 0x10);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
faceData[i * 7 + 6] = normal;
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3f getVertexPos(int[] data, int vertex)
|
||||
{
|
||||
int idx = vertex * 7;
|
||||
|
||||
float x = Float.intBitsToFloat(data[idx]);
|
||||
float y = Float.intBitsToFloat(data[idx + 1]);
|
||||
float z = Float.intBitsToFloat(data[idx + 2]);
|
||||
|
||||
return new Vector3f(x, y, z);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Optional<TRSRTransformation> applyTransform(ItemTransformVec3f transform, Optional<? extends IModelPart> part)
|
||||
{
|
||||
if(part.isPresent()) return Optional.empty();
|
||||
return Optional.of(TRSRTransformation.blockCenterToCorner(TRSRTransformation.from(transform)));
|
||||
}
|
||||
|
||||
public static Optional<TRSRTransformation> applyTransform(ModelRotation rotation, Optional<? extends IModelPart> part)
|
||||
{
|
||||
if(part.isPresent()) return Optional.empty();
|
||||
return Optional.of(TRSRTransformation.from(rotation));
|
||||
}
|
||||
|
||||
public static Optional<TRSRTransformation> applyTransform(Matrix4f matrix, Optional<? extends IModelPart> part)
|
||||
{
|
||||
if(part.isPresent()) return Optional.empty();
|
||||
return Optional.of(new TRSRTransformation(matrix));
|
||||
}
|
||||
|
||||
public static void loadEntityShader(Entity entity, EntityRenderer entityRenderer)
|
||||
{
|
||||
if (entity != null)
|
||||
{
|
||||
ResourceLocation shader = ClientRegistry.getEntityShader(entity.getClass());
|
||||
if (shader != null)
|
||||
{
|
||||
entityRenderer.loadShader(shader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IBakedModel getDamageModel(IBakedModel ibakedmodel, TextureAtlasSprite texture, IBlockState state, IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
state = state.getBlock().getExtendedState(state, world, pos);
|
||||
return (new SimpleBakedModel.Builder(state, ibakedmodel, texture, pos)).makeBakedModel();
|
||||
}
|
||||
|
||||
private static int slotMainHand = 0;
|
||||
|
||||
public static boolean shouldCauseReequipAnimation(@Nonnull ItemStack from, @Nonnull ItemStack to, int slot)
|
||||
{
|
||||
boolean fromInvalid = from.isEmpty();
|
||||
boolean toInvalid = to.isEmpty();
|
||||
|
||||
if (fromInvalid && toInvalid) return false;
|
||||
if (fromInvalid || toInvalid) return true;
|
||||
|
||||
boolean changed = false;
|
||||
if (slot != -1)
|
||||
{
|
||||
changed = slot != slotMainHand;
|
||||
slotMainHand = slot;
|
||||
}
|
||||
return from.getItem().shouldCauseReequipAnimation(from, to, changed);
|
||||
}
|
||||
|
||||
public static boolean shouldCauseBlockBreakReset(@Nonnull ItemStack from, @Nonnull ItemStack to)
|
||||
{
|
||||
return from.getItem().shouldCauseBlockBreakReset(from, to);
|
||||
}
|
||||
|
||||
public static BlockFaceUV applyUVLock(BlockFaceUV blockFaceUV, EnumFacing originalSide, ITransformation rotation)
|
||||
{
|
||||
TRSRTransformation global = new TRSRTransformation(rotation.getMatrix());
|
||||
Matrix4f uv = global.getUVLockTransform(originalSide).getMatrix();
|
||||
Vector4f vec = new Vector4f(0, 0, 0, 1);
|
||||
float u0 = blockFaceUV.getVertexU(blockFaceUV.getVertexRotatedRev(0));
|
||||
float v0 = blockFaceUV.getVertexV(blockFaceUV.getVertexRotatedRev(0));
|
||||
vec.x = u0 / 16;
|
||||
vec.y = v0 / 16;
|
||||
uv.transform(vec);
|
||||
float uMin = 16 * vec.x; // / vec.w;
|
||||
float vMin = 16 * vec.y; // / vec.w;
|
||||
float u1 = blockFaceUV.getVertexU(blockFaceUV.getVertexRotatedRev(2));
|
||||
float v1 = blockFaceUV.getVertexV(blockFaceUV.getVertexRotatedRev(2));
|
||||
vec.x = u1 / 16;
|
||||
vec.y = v1 / 16;
|
||||
vec.z = 0;
|
||||
vec.w = 1;
|
||||
uv.transform(vec);
|
||||
float uMax = 16 * vec.x; // / vec.w;
|
||||
float vMax = 16 * vec.y; // / vec.w;
|
||||
if (uMin > uMax && u0 < u1 || uMin < uMax && u0 > u1)
|
||||
{
|
||||
float t = uMin;
|
||||
uMin = uMax;
|
||||
uMax = t;
|
||||
}
|
||||
if (vMin > vMax && v0 < v1 || vMin < vMax && v0 > v1)
|
||||
{
|
||||
float t = vMin;
|
||||
vMin = vMax;
|
||||
vMax = t;
|
||||
}
|
||||
float a = (float)Math.toRadians(blockFaceUV.rotation);
|
||||
Vector3f rv = new Vector3f(MathHelper.cos(a), MathHelper.sin(a), 0);
|
||||
Matrix3f rot = new Matrix3f();
|
||||
uv.getRotationScale(rot);
|
||||
rot.transform(rv);
|
||||
int angle = MathHelper.normalizeAngle(-(int)Math.round(Math.toDegrees(Math.atan2(rv.y, rv.x)) / 90) * 90, 360);
|
||||
return new BlockFaceUV(new float[]{ uMin, vMin, uMax, vMax }, angle);
|
||||
}
|
||||
|
||||
public static RenderGameOverlayEvent.BossInfo bossBarRenderPre(ScaledResolution res, BossInfoClient bossInfo, int x, int y, int increment)
|
||||
{
|
||||
RenderGameOverlayEvent.BossInfo evt = new RenderGameOverlayEvent.BossInfo(new RenderGameOverlayEvent(Animation.getPartialTickTime(), res),
|
||||
BOSSINFO, bossInfo, x, y, increment);
|
||||
MinecraftForge.EVENT_BUS.post(evt);
|
||||
return evt;
|
||||
}
|
||||
|
||||
public static void bossBarRenderPost(ScaledResolution res)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(new RenderGameOverlayEvent(Animation.getPartialTickTime(), res), BOSSINFO));
|
||||
}
|
||||
|
||||
public static ScreenshotEvent onScreenshot(BufferedImage image, File screenshotFile)
|
||||
{
|
||||
ScreenshotEvent event = new ScreenshotEvent(image, screenshotFile);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Pair<? extends IBakedModel,Matrix4f> handlePerspective(IBakedModel model, ItemCameraTransforms.TransformType type)
|
||||
{
|
||||
TRSRTransformation tr = TRSRTransformation.from(model.getItemCameraTransforms().getTransform(type));
|
||||
Matrix4f mat = null;
|
||||
if (!tr.isIdentity()) mat = tr.getMatrix();
|
||||
return Pair.of(model, mat);
|
||||
}
|
||||
|
||||
public static void onInputUpdate(EntityPlayer player, MovementInput movementInput)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new InputUpdateEvent(player, movementInput));
|
||||
}
|
||||
|
||||
public static String getHorseArmorTexture(EntityHorse horse, ItemStack armorStack)
|
||||
{
|
||||
String texture = armorStack.getItem().getHorseArmorTexture(horse, armorStack);
|
||||
if(texture == null) texture = horse.getHorseArmorType().getTextureName();
|
||||
return texture;
|
||||
}
|
||||
|
||||
public static boolean shouldUseVanillaReloadableListener(IResourceManagerReloadListener listener)
|
||||
{
|
||||
Predicate<IResourceType> predicate = SelectiveReloadStateHandler.INSTANCE.get();
|
||||
|
||||
if (listener instanceof ModelManager || listener instanceof RenderItem)
|
||||
return predicate.test(VanillaResourceType.MODELS);
|
||||
else if (listener instanceof BlockRendererDispatcher || listener instanceof RenderGlobal)
|
||||
return predicate.test(VanillaResourceType.MODELS);
|
||||
else if (listener instanceof TextureManager || listener instanceof FontRenderer)
|
||||
return predicate.test(VanillaResourceType.TEXTURES);
|
||||
else if (listener instanceof FoliageColorReloadListener || listener instanceof GrassColorReloadListener)
|
||||
return predicate.test(VanillaResourceType.TEXTURES);
|
||||
else if (listener instanceof SoundHandler)
|
||||
return predicate.test(VanillaResourceType.SOUNDS);
|
||||
else if (listener instanceof EntityRenderer)
|
||||
return predicate.test(VanillaResourceType.SHADERS);
|
||||
else if (listener instanceof LanguageManager || listener instanceof SearchTreeManager)
|
||||
return predicate.test(VanillaResourceType.LANGUAGES);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiIngame;
|
||||
import net.minecraft.client.gui.GuiOverlayDebug;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.attributes.IAttributeInstance;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.scoreboard.ScoreObjective;
|
||||
import net.minecraft.scoreboard.ScorePlayerTeam;
|
||||
import net.minecraft.scoreboard.Scoreboard;
|
||||
import net.minecraft.util.FoodStats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StringUtils;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class GuiIngameForge extends GuiIngame
|
||||
{
|
||||
//private static final ResourceLocation VIGNETTE = new ResourceLocation("textures/misc/vignette.png");
|
||||
//private static final ResourceLocation WIDGITS = new ResourceLocation("textures/gui/widgets.png");
|
||||
//private static final ResourceLocation PUMPKIN_BLUR = new ResourceLocation("textures/misc/pumpkinblur.png");
|
||||
|
||||
private static final int WHITE = 0xFFFFFF;
|
||||
|
||||
//Flags to toggle the rendering of certain aspects of the HUD, valid conditions
|
||||
//must be met for them to render normally. If those conditions are met, but this flag
|
||||
//is false, they will not be rendered.
|
||||
public static boolean renderVignette = true;
|
||||
public static boolean renderHelmet = true;
|
||||
public static boolean renderPortal = true;
|
||||
public static boolean renderHotbar = true;
|
||||
public static boolean renderCrosshairs = true;
|
||||
public static boolean renderBossHealth = true;
|
||||
public static boolean renderHealth = true;
|
||||
public static boolean renderArmor = true;
|
||||
public static boolean renderFood = true;
|
||||
public static boolean renderHealthMount = true;
|
||||
public static boolean renderAir = true;
|
||||
public static boolean renderExperiance = true;
|
||||
public static boolean renderJumpBar = true;
|
||||
public static boolean renderObjective = true;
|
||||
|
||||
public static int left_height = 39;
|
||||
public static int right_height = 39;
|
||||
|
||||
private ScaledResolution res = null;
|
||||
private FontRenderer fontrenderer = null;
|
||||
private RenderGameOverlayEvent eventParent;
|
||||
//private static final String MC_VERSION = MinecraftForge.MC_VERSION;
|
||||
private GuiOverlayDebugForge debugOverlay;
|
||||
|
||||
public GuiIngameForge(Minecraft mc)
|
||||
{
|
||||
super(mc);
|
||||
debugOverlay = new GuiOverlayDebugForge(mc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderGameOverlay(float partialTicks)
|
||||
{
|
||||
res = new ScaledResolution(mc);
|
||||
eventParent = new RenderGameOverlayEvent(partialTicks, res);
|
||||
int width = res.getScaledWidth();
|
||||
int height = res.getScaledHeight();
|
||||
renderHealthMount = mc.player.getRidingEntity() instanceof EntityLivingBase;
|
||||
renderFood = mc.player.getRidingEntity() == null;
|
||||
renderJumpBar = mc.player.isRidingHorse();
|
||||
|
||||
right_height = 39;
|
||||
left_height = 39;
|
||||
|
||||
if (pre(ALL)) return;
|
||||
|
||||
fontrenderer = mc.fontRenderer;
|
||||
mc.entityRenderer.setupOverlayRendering();
|
||||
GlStateManager.enableBlend();
|
||||
|
||||
if (renderVignette && Minecraft.isFancyGraphicsEnabled())
|
||||
{
|
||||
renderVignette(mc.player.getBrightness(), res);
|
||||
}
|
||||
else
|
||||
{
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
}
|
||||
|
||||
if (renderHelmet) renderHelmet(res, partialTicks);
|
||||
|
||||
if (renderPortal && !mc.player.isPotionActive(MobEffects.NAUSEA))
|
||||
{
|
||||
renderPortal(res, partialTicks);
|
||||
}
|
||||
|
||||
if (renderHotbar) renderHotbar(res, partialTicks);
|
||||
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
zLevel = -90.0F;
|
||||
rand.setSeed((long)(updateCounter * 312871));
|
||||
|
||||
if (renderCrosshairs) renderCrosshairs(partialTicks);
|
||||
if (renderBossHealth) renderBossHealth();
|
||||
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
if (this.mc.playerController.shouldDrawHUD() && this.mc.getRenderViewEntity() instanceof EntityPlayer)
|
||||
{
|
||||
if (renderHealth) renderHealth(width, height);
|
||||
if (renderArmor) renderArmor(width, height);
|
||||
if (renderFood) renderFood(width, height);
|
||||
if (renderHealthMount) renderHealthMount(width, height);
|
||||
if (renderAir) renderAir(width, height);
|
||||
}
|
||||
|
||||
renderSleepFade(width, height);
|
||||
|
||||
if (renderJumpBar)
|
||||
{
|
||||
renderJumpBar(width, height);
|
||||
}
|
||||
else if (renderExperiance)
|
||||
{
|
||||
renderExperience(width, height);
|
||||
}
|
||||
|
||||
renderToolHighlight(res);
|
||||
renderHUDText(width, height);
|
||||
renderFPSGraph();
|
||||
renderPotionIcons(res);
|
||||
renderRecordOverlay(width, height, partialTicks);
|
||||
renderSubtitles(res);
|
||||
renderTitle(width, height, partialTicks);
|
||||
|
||||
|
||||
Scoreboard scoreboard = this.mc.world.getScoreboard();
|
||||
ScoreObjective objective = null;
|
||||
ScorePlayerTeam scoreplayerteam = scoreboard.getPlayersTeam(mc.player.getName());
|
||||
if (scoreplayerteam != null)
|
||||
{
|
||||
int slot = scoreplayerteam.getColor().getColorIndex();
|
||||
if (slot >= 0) objective = scoreboard.getObjectiveInDisplaySlot(3 + slot);
|
||||
}
|
||||
ScoreObjective scoreobjective1 = objective != null ? objective : scoreboard.getObjectiveInDisplaySlot(1);
|
||||
if (renderObjective && scoreobjective1 != null)
|
||||
{
|
||||
this.renderScoreboard(scoreobjective1, res);
|
||||
}
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0);
|
||||
GlStateManager.disableAlpha();
|
||||
|
||||
renderChat(width, height);
|
||||
|
||||
renderPlayerList(width, height);
|
||||
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.enableAlpha();
|
||||
|
||||
post(ALL);
|
||||
}
|
||||
|
||||
public ScaledResolution getResolution()
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
protected void renderCrosshairs(float partialTicks)
|
||||
{
|
||||
if (pre(CROSSHAIRS)) return;
|
||||
bind(Gui.ICONS);
|
||||
GlStateManager.enableBlend();
|
||||
super.renderAttackIndicator(partialTicks, res);
|
||||
post(CROSSHAIRS);
|
||||
}
|
||||
|
||||
protected void renderPotionIcons(ScaledResolution resolution)
|
||||
{
|
||||
if (pre(POTION_ICONS)) return;
|
||||
super.renderPotionEffects(resolution);
|
||||
post(POTION_ICONS);
|
||||
}
|
||||
|
||||
protected void renderSubtitles(ScaledResolution resolution)
|
||||
{
|
||||
if (pre(SUBTITLES)) return;
|
||||
this.overlaySubtitle.renderSubtitles(res);
|
||||
post(SUBTITLES);
|
||||
}
|
||||
|
||||
//@Override
|
||||
protected void renderBossHealth()
|
||||
{
|
||||
if (pre(BOSSHEALTH)) return;
|
||||
bind(Gui.ICONS);
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
mc.mcProfiler.startSection("bossHealth");
|
||||
GlStateManager.enableBlend();
|
||||
this.overlayBoss.renderBossHealth();
|
||||
GlStateManager.disableBlend();
|
||||
mc.mcProfiler.endSection();
|
||||
post(BOSSHEALTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a Vignette arount the entire screen that changes with light level.
|
||||
*/
|
||||
@Override
|
||||
protected void renderVignette(float lightLevel, ScaledResolution scaledRes)
|
||||
{
|
||||
if (pre(VIGNETTE))
|
||||
{
|
||||
// Need to put this here, since Vanilla assumes this state after the vignette was rendered.
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
return;
|
||||
}
|
||||
super.renderVignette(lightLevel, scaledRes);
|
||||
post(VIGNETTE);
|
||||
}
|
||||
|
||||
private void renderHelmet(ScaledResolution res, float partialTicks)
|
||||
{
|
||||
if (pre(HELMET)) return;
|
||||
|
||||
ItemStack itemstack = this.mc.player.inventory.armorItemInSlot(3);
|
||||
|
||||
if (this.mc.gameSettings.thirdPersonView == 0 && !itemstack.isEmpty())
|
||||
{
|
||||
Item item = itemstack.getItem();
|
||||
if (item == Item.getItemFromBlock(Blocks.PUMPKIN))
|
||||
{
|
||||
renderPumpkinOverlay(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.renderHelmetOverlay(itemstack, mc.player, res, partialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
post(HELMET);
|
||||
}
|
||||
|
||||
protected void renderArmor(int width, int height)
|
||||
{
|
||||
if (pre(ARMOR)) return;
|
||||
mc.mcProfiler.startSection("armor");
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
int left = width / 2 - 91;
|
||||
int top = height - left_height;
|
||||
|
||||
int level = ForgeHooks.getTotalArmorValue(mc.player);
|
||||
for (int i = 1; level > 0 && i < 20; i += 2)
|
||||
{
|
||||
if (i < level)
|
||||
{
|
||||
drawTexturedModalRect(left, top, 34, 9, 9, 9);
|
||||
}
|
||||
else if (i == level)
|
||||
{
|
||||
drawTexturedModalRect(left, top, 25, 9, 9, 9);
|
||||
}
|
||||
else if (i > level)
|
||||
{
|
||||
drawTexturedModalRect(left, top, 16, 9, 9, 9);
|
||||
}
|
||||
left += 8;
|
||||
}
|
||||
left_height += 10;
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
mc.mcProfiler.endSection();
|
||||
post(ARMOR);
|
||||
}
|
||||
|
||||
protected void renderPortal(ScaledResolution res, float partialTicks)
|
||||
{
|
||||
if (pre(PORTAL)) return;
|
||||
|
||||
float f1 = mc.player.prevTimeInPortal + (mc.player.timeInPortal - mc.player.prevTimeInPortal) * partialTicks;
|
||||
|
||||
if (f1 > 0.0F)
|
||||
{
|
||||
renderPortal(f1, res);
|
||||
}
|
||||
|
||||
post(PORTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderHotbar(ScaledResolution res, float partialTicks)
|
||||
{
|
||||
if (pre(HOTBAR)) return;
|
||||
|
||||
if (mc.playerController.isSpectator())
|
||||
{
|
||||
this.spectatorGui.renderTooltip(res, partialTicks);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.renderHotbar(res, partialTicks);
|
||||
}
|
||||
|
||||
post(HOTBAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverlayMessage(ITextComponent component, boolean animateColor)
|
||||
{
|
||||
this.setOverlayMessage(component.getFormattedText(), animateColor);
|
||||
}
|
||||
|
||||
protected void renderAir(int width, int height)
|
||||
{
|
||||
if (pre(AIR)) return;
|
||||
mc.mcProfiler.startSection("air");
|
||||
EntityPlayer player = (EntityPlayer)this.mc.getRenderViewEntity();
|
||||
GlStateManager.enableBlend();
|
||||
int left = width / 2 + 91;
|
||||
int top = height - right_height;
|
||||
|
||||
if (player.isInsideOfMaterial(Material.WATER))
|
||||
{
|
||||
int air = player.getAir();
|
||||
int full = MathHelper.ceil((double)(air - 2) * 10.0D / 300.0D);
|
||||
int partial = MathHelper.ceil((double)air * 10.0D / 300.0D) - full;
|
||||
|
||||
for (int i = 0; i < full + partial; ++i)
|
||||
{
|
||||
drawTexturedModalRect(left - i * 8 - 9, top, (i < full ? 16 : 25), 18, 9, 9);
|
||||
}
|
||||
right_height += 10;
|
||||
}
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
mc.mcProfiler.endSection();
|
||||
post(AIR);
|
||||
}
|
||||
|
||||
public void renderHealth(int width, int height)
|
||||
{
|
||||
bind(ICONS);
|
||||
if (pre(HEALTH)) return;
|
||||
mc.mcProfiler.startSection("health");
|
||||
GlStateManager.enableBlend();
|
||||
|
||||
EntityPlayer player = (EntityPlayer)this.mc.getRenderViewEntity();
|
||||
int health = MathHelper.ceil(player.getHealth());
|
||||
boolean highlight = healthUpdateCounter > (long)updateCounter && (healthUpdateCounter - (long)updateCounter) / 3L %2L == 1L;
|
||||
|
||||
if (health < this.playerHealth && player.hurtResistantTime > 0)
|
||||
{
|
||||
this.lastSystemTime = Minecraft.getSystemTime();
|
||||
this.healthUpdateCounter = (long)(this.updateCounter + 20);
|
||||
}
|
||||
else if (health > this.playerHealth && player.hurtResistantTime > 0)
|
||||
{
|
||||
this.lastSystemTime = Minecraft.getSystemTime();
|
||||
this.healthUpdateCounter = (long)(this.updateCounter + 10);
|
||||
}
|
||||
|
||||
if (Minecraft.getSystemTime() - this.lastSystemTime > 1000L)
|
||||
{
|
||||
this.playerHealth = health;
|
||||
this.lastPlayerHealth = health;
|
||||
this.lastSystemTime = Minecraft.getSystemTime();
|
||||
}
|
||||
|
||||
this.playerHealth = health;
|
||||
int healthLast = this.lastPlayerHealth;
|
||||
|
||||
IAttributeInstance attrMaxHealth = player.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH);
|
||||
float healthMax = (float)attrMaxHealth.getAttributeValue();
|
||||
float absorb = MathHelper.ceil(player.getAbsorptionAmount());
|
||||
|
||||
int healthRows = MathHelper.ceil((healthMax + absorb) / 2.0F / 10.0F);
|
||||
int rowHeight = Math.max(10 - (healthRows - 2), 3);
|
||||
|
||||
this.rand.setSeed((long)(updateCounter * 312871));
|
||||
|
||||
int left = width / 2 - 91;
|
||||
int top = height - left_height;
|
||||
left_height += (healthRows * rowHeight);
|
||||
if (rowHeight != 10) left_height += 10 - rowHeight;
|
||||
|
||||
int regen = -1;
|
||||
if (player.isPotionActive(MobEffects.REGENERATION))
|
||||
{
|
||||
regen = updateCounter % 25;
|
||||
}
|
||||
|
||||
final int TOP = 9 * (mc.world.getWorldInfo().isHardcoreModeEnabled() ? 5 : 0);
|
||||
final int BACKGROUND = (highlight ? 25 : 16);
|
||||
int MARGIN = 16;
|
||||
if (player.isPotionActive(MobEffects.POISON)) MARGIN += 36;
|
||||
else if (player.isPotionActive(MobEffects.WITHER)) MARGIN += 72;
|
||||
float absorbRemaining = absorb;
|
||||
|
||||
for (int i = MathHelper.ceil((healthMax + absorb) / 2.0F) - 1; i >= 0; --i)
|
||||
{
|
||||
//int b0 = (highlight ? 1 : 0);
|
||||
int row = MathHelper.ceil((float)(i + 1) / 10.0F) - 1;
|
||||
int x = left + i % 10 * 8;
|
||||
int y = top - row * rowHeight;
|
||||
|
||||
if (health <= 4) y += rand.nextInt(2);
|
||||
if (i == regen) y -= 2;
|
||||
|
||||
drawTexturedModalRect(x, y, BACKGROUND, TOP, 9, 9);
|
||||
|
||||
if (highlight)
|
||||
{
|
||||
if (i * 2 + 1 < healthLast)
|
||||
drawTexturedModalRect(x, y, MARGIN + 54, TOP, 9, 9); //6
|
||||
else if (i * 2 + 1 == healthLast)
|
||||
drawTexturedModalRect(x, y, MARGIN + 63, TOP, 9, 9); //7
|
||||
}
|
||||
|
||||
if (absorbRemaining > 0.0F)
|
||||
{
|
||||
if (absorbRemaining == absorb && absorb % 2.0F == 1.0F)
|
||||
{
|
||||
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
|
||||
absorbRemaining -= 1.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
|
||||
absorbRemaining -= 2.0F;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i * 2 + 1 < health)
|
||||
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
|
||||
else if (i * 2 + 1 == health)
|
||||
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
|
||||
}
|
||||
}
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
mc.mcProfiler.endSection();
|
||||
post(HEALTH);
|
||||
}
|
||||
|
||||
public void renderFood(int width, int height)
|
||||
{
|
||||
if (pre(FOOD)) return;
|
||||
mc.mcProfiler.startSection("food");
|
||||
|
||||
EntityPlayer player = (EntityPlayer)this.mc.getRenderViewEntity();
|
||||
GlStateManager.enableBlend();
|
||||
int left = width / 2 + 91;
|
||||
int top = height - right_height;
|
||||
right_height += 10;
|
||||
boolean unused = false;// Unused flag in vanilla, seems to be part of a 'fade out' mechanic
|
||||
|
||||
FoodStats stats = mc.player.getFoodStats();
|
||||
int level = stats.getFoodLevel();
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
int idx = i * 2 + 1;
|
||||
int x = left - i * 8 - 9;
|
||||
int y = top;
|
||||
int icon = 16;
|
||||
byte background = 0;
|
||||
|
||||
if (mc.player.isPotionActive(MobEffects.HUNGER))
|
||||
{
|
||||
icon += 36;
|
||||
background = 13;
|
||||
}
|
||||
if (unused) background = 1; //Probably should be a += 1 but vanilla never uses this
|
||||
|
||||
if (player.getFoodStats().getSaturationLevel() <= 0.0F && updateCounter % (level * 3 + 1) == 0)
|
||||
{
|
||||
y = top + (rand.nextInt(3) - 1);
|
||||
}
|
||||
|
||||
drawTexturedModalRect(x, y, 16 + background * 9, 27, 9, 9);
|
||||
|
||||
if (idx < level)
|
||||
drawTexturedModalRect(x, y, icon + 36, 27, 9, 9);
|
||||
else if (idx == level)
|
||||
drawTexturedModalRect(x, y, icon + 45, 27, 9, 9);
|
||||
}
|
||||
GlStateManager.disableBlend();
|
||||
mc.mcProfiler.endSection();
|
||||
post(FOOD);
|
||||
}
|
||||
|
||||
protected void renderSleepFade(int width, int height)
|
||||
{
|
||||
if (mc.player.getSleepTimer() > 0)
|
||||
{
|
||||
mc.mcProfiler.startSection("sleep");
|
||||
GlStateManager.disableDepth();
|
||||
GlStateManager.disableAlpha();
|
||||
int sleepTime = mc.player.getSleepTimer();
|
||||
float opacity = (float)sleepTime / 100.0F;
|
||||
|
||||
if (opacity > 1.0F)
|
||||
{
|
||||
opacity = 1.0F - (float)(sleepTime - 100) / 10.0F;
|
||||
}
|
||||
|
||||
int color = (int)(220.0F * opacity) << 24 | 1052704;
|
||||
drawRect(0, 0, width, height, color);
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.enableDepth();
|
||||
mc.mcProfiler.endSection();
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderExperience(int width, int height)
|
||||
{
|
||||
bind(ICONS);
|
||||
if (pre(EXPERIENCE)) return;
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlStateManager.disableBlend();
|
||||
|
||||
if (mc.playerController.gameIsSurvivalOrAdventure())
|
||||
{
|
||||
mc.mcProfiler.startSection("expBar");
|
||||
int cap = this.mc.player.xpBarCap();
|
||||
int left = width / 2 - 91;
|
||||
|
||||
if (cap > 0)
|
||||
{
|
||||
short barWidth = 182;
|
||||
int filled = (int)(mc.player.experience * (float)(barWidth + 1));
|
||||
int top = height - 32 + 3;
|
||||
drawTexturedModalRect(left, top, 0, 64, barWidth, 5);
|
||||
|
||||
if (filled > 0)
|
||||
{
|
||||
drawTexturedModalRect(left, top, 0, 69, filled, 5);
|
||||
}
|
||||
}
|
||||
|
||||
this.mc.mcProfiler.endSection();
|
||||
|
||||
|
||||
if (mc.playerController.gameIsSurvivalOrAdventure() && mc.player.experienceLevel > 0)
|
||||
{
|
||||
mc.mcProfiler.startSection("expLevel");
|
||||
boolean flag1 = false;
|
||||
int color = flag1 ? 16777215 : 8453920;
|
||||
String text = "" + mc.player.experienceLevel;
|
||||
int x = (width - fontrenderer.getStringWidth(text)) / 2;
|
||||
int y = height - 31 - 4;
|
||||
fontrenderer.drawString(text, x + 1, y, 0);
|
||||
fontrenderer.drawString(text, x - 1, y, 0);
|
||||
fontrenderer.drawString(text, x, y + 1, 0);
|
||||
fontrenderer.drawString(text, x, y - 1, 0);
|
||||
fontrenderer.drawString(text, x, y, color);
|
||||
mc.mcProfiler.endSection();
|
||||
}
|
||||
}
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
post(EXPERIENCE);
|
||||
}
|
||||
|
||||
protected void renderJumpBar(int width, int height)
|
||||
{
|
||||
bind(ICONS);
|
||||
if (pre(JUMPBAR)) return;
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlStateManager.disableBlend();
|
||||
|
||||
mc.mcProfiler.startSection("jumpBar");
|
||||
float charge = mc.player.getHorseJumpPower();
|
||||
final int barWidth = 182;
|
||||
int x = (width / 2) - (barWidth / 2);
|
||||
int filled = (int)(charge * (float)(barWidth + 1));
|
||||
int top = height - 32 + 3;
|
||||
|
||||
drawTexturedModalRect(x, top, 0, 84, barWidth, 5);
|
||||
|
||||
if (filled > 0)
|
||||
{
|
||||
this.drawTexturedModalRect(x, top, 0, 89, filled, 5);
|
||||
}
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
mc.mcProfiler.endSection();
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
post(JUMPBAR);
|
||||
}
|
||||
|
||||
protected void renderToolHighlight(ScaledResolution res)
|
||||
{
|
||||
if (this.mc.gameSettings.heldItemTooltips && !this.mc.playerController.isSpectator())
|
||||
{
|
||||
mc.mcProfiler.startSection("toolHighlight");
|
||||
|
||||
if (this.remainingHighlightTicks > 0 && !this.highlightingItemStack.isEmpty())
|
||||
{
|
||||
String name = this.highlightingItemStack.getDisplayName();
|
||||
if (this.highlightingItemStack.hasDisplayName())
|
||||
name = TextFormatting.ITALIC + name;
|
||||
|
||||
name = this.highlightingItemStack.getItem().getHighlightTip(this.highlightingItemStack, name);
|
||||
|
||||
int opacity = (int)((float)this.remainingHighlightTicks * 256.0F / 10.0F);
|
||||
if (opacity > 255) opacity = 255;
|
||||
|
||||
if (opacity > 0)
|
||||
{
|
||||
int y = res.getScaledHeight() - 59;
|
||||
if (!mc.playerController.shouldDrawHUD()) y += 14;
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
FontRenderer font = highlightingItemStack.getItem().getFontRenderer(highlightingItemStack);
|
||||
if (font != null)
|
||||
{
|
||||
int x = (res.getScaledWidth() - font.getStringWidth(name)) / 2;
|
||||
font.drawStringWithShadow(name, x, y, WHITE | (opacity << 24));
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = (res.getScaledWidth() - fontrenderer.getStringWidth(name)) / 2;
|
||||
fontrenderer.drawStringWithShadow(name, x, y, WHITE | (opacity << 24));
|
||||
}
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
mc.mcProfiler.endSection();
|
||||
}
|
||||
else if (this.mc.player.isSpectator())
|
||||
{
|
||||
this.spectatorGui.renderSelectedItem(res);
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderHUDText(int width, int height)
|
||||
{
|
||||
mc.mcProfiler.startSection("forgeHudText");
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0);
|
||||
ArrayList<String> listL = new ArrayList<String>();
|
||||
ArrayList<String> listR = new ArrayList<String>();
|
||||
|
||||
if (mc.isDemo())
|
||||
{
|
||||
long time = mc.world.getTotalWorldTime();
|
||||
if (time >= 120500L)
|
||||
{
|
||||
listR.add(I18n.format("demo.demoExpired"));
|
||||
}
|
||||
else
|
||||
{
|
||||
listR.add(I18n.format("demo.remainingTime", StringUtils.ticksToElapsedTime((int)(120500L - time))));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mc.gameSettings.showDebugInfo && !pre(DEBUG))
|
||||
{
|
||||
listL.addAll(debugOverlay.getLeft());
|
||||
listR.addAll(debugOverlay.getRight());
|
||||
post(DEBUG);
|
||||
}
|
||||
|
||||
RenderGameOverlayEvent.Text event = new RenderGameOverlayEvent.Text(eventParent, listL, listR);
|
||||
if (!MinecraftForge.EVENT_BUS.post(event))
|
||||
{
|
||||
int top = 2;
|
||||
for (String msg : listL)
|
||||
{
|
||||
if (msg == null) continue;
|
||||
drawRect(1, top - 1, 2 + fontrenderer.getStringWidth(msg) + 1, top + fontrenderer.FONT_HEIGHT - 1, -1873784752);
|
||||
fontrenderer.drawString(msg, 2, top, 14737632);
|
||||
top += fontrenderer.FONT_HEIGHT;
|
||||
}
|
||||
|
||||
top = 2;
|
||||
for (String msg : listR)
|
||||
{
|
||||
if (msg == null) continue;
|
||||
int w = fontrenderer.getStringWidth(msg);
|
||||
int left = width - 2 - w;
|
||||
drawRect(left - 1, top - 1, left + w + 1, top + fontrenderer.FONT_HEIGHT - 1, -1873784752);
|
||||
fontrenderer.drawString(msg, left, top, 14737632);
|
||||
top += fontrenderer.FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
mc.mcProfiler.endSection();
|
||||
post(TEXT);
|
||||
}
|
||||
|
||||
protected void renderFPSGraph()
|
||||
{
|
||||
if (this.mc.gameSettings.showDebugInfo && this.mc.gameSettings.showLagometer && !pre(FPS_GRAPH))
|
||||
{
|
||||
this.debugOverlay.renderLagometer();
|
||||
post(FPS_GRAPH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderRecordOverlay(int width, int height, float partialTicks)
|
||||
{
|
||||
if (overlayMessageTime > 0)
|
||||
{
|
||||
mc.mcProfiler.startSection("overlayMessage");
|
||||
float hue = (float)overlayMessageTime - partialTicks;
|
||||
int opacity = (int)(hue * 256.0F / 20.0F);
|
||||
if (opacity > 255) opacity = 255;
|
||||
|
||||
if (opacity > 0)
|
||||
{
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate((float)(width / 2), (float)(height - 68), 0.0F);
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
int color = (animateOverlayMessageColor ? Color.HSBtoRGB(hue / 50.0F, 0.7F, 0.6F) & WHITE : WHITE);
|
||||
fontrenderer.drawString(overlayMessage, -fontrenderer.getStringWidth(overlayMessage) / 2, -4, color | (opacity << 24));
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
mc.mcProfiler.endSection();
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderTitle(int width, int height, float partialTicks)
|
||||
{
|
||||
if (titlesTimer > 0)
|
||||
{
|
||||
mc.mcProfiler.startSection("titleAndSubtitle");
|
||||
float age = (float)this.titlesTimer - partialTicks;
|
||||
int opacity = 255;
|
||||
|
||||
if (titlesTimer > titleFadeOut + titleDisplayTime)
|
||||
{
|
||||
float f3 = (float)(titleFadeIn + titleDisplayTime + titleFadeOut) - age;
|
||||
opacity = (int)(f3 * 255.0F / (float)titleFadeIn);
|
||||
}
|
||||
if (titlesTimer <= titleFadeOut) opacity = (int)(age * 255.0F / (float)this.titleFadeOut);
|
||||
|
||||
opacity = MathHelper.clamp(opacity, 0, 255);
|
||||
|
||||
if (opacity > 8)
|
||||
{
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate((float)(width / 2), (float)(height / 2), 0.0F);
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.scale(4.0F, 4.0F, 4.0F);
|
||||
int l = opacity << 24 & -16777216;
|
||||
this.getFontRenderer().drawString(this.displayedTitle, (float)(-this.getFontRenderer().getStringWidth(this.displayedTitle) / 2), -10.0F, 16777215 | l, true);
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.scale(2.0F, 2.0F, 2.0F);
|
||||
this.getFontRenderer().drawString(this.displayedSubTitle, (float)(-this.getFontRenderer().getStringWidth(this.displayedSubTitle) / 2), 5.0F, 16777215 | l, true);
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
this.mc.mcProfiler.endSection();
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderChat(int width, int height)
|
||||
{
|
||||
mc.mcProfiler.startSection("chat");
|
||||
|
||||
RenderGameOverlayEvent.Chat event = new RenderGameOverlayEvent.Chat(eventParent, 0, height - 48);
|
||||
if (MinecraftForge.EVENT_BUS.post(event)) return;
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate((float) event.getPosX(), (float) event.getPosY(), 0.0F);
|
||||
persistantChatGUI.drawChat(updateCounter);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
post(CHAT);
|
||||
|
||||
mc.mcProfiler.endSection();
|
||||
}
|
||||
|
||||
protected void renderPlayerList(int width, int height)
|
||||
{
|
||||
ScoreObjective scoreobjective = this.mc.world.getScoreboard().getObjectiveInDisplaySlot(0);
|
||||
NetHandlerPlayClient handler = mc.player.connection;
|
||||
|
||||
if (mc.gameSettings.keyBindPlayerList.isKeyDown() && (!mc.isIntegratedServerRunning() || handler.getPlayerInfoMap().size() > 1 || scoreobjective != null))
|
||||
{
|
||||
this.overlayPlayerList.updatePlayerList(true);
|
||||
if (pre(PLAYER_LIST)) return;
|
||||
this.overlayPlayerList.renderPlayerlist(width, this.mc.world.getScoreboard(), scoreobjective);
|
||||
post(PLAYER_LIST);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.overlayPlayerList.updatePlayerList(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderHealthMount(int width, int height)
|
||||
{
|
||||
EntityPlayer player = (EntityPlayer)mc.getRenderViewEntity();
|
||||
Entity tmp = player.getRidingEntity();
|
||||
if (!(tmp instanceof EntityLivingBase)) return;
|
||||
|
||||
bind(ICONS);
|
||||
|
||||
if (pre(HEALTHMOUNT)) return;
|
||||
|
||||
boolean unused = false;
|
||||
int left_align = width / 2 + 91;
|
||||
|
||||
mc.mcProfiler.endStartSection("mountHealth");
|
||||
GlStateManager.enableBlend();
|
||||
EntityLivingBase mount = (EntityLivingBase)tmp;
|
||||
int health = (int)Math.ceil((double)mount.getHealth());
|
||||
float healthMax = mount.getMaxHealth();
|
||||
int hearts = (int)(healthMax + 0.5F) / 2;
|
||||
|
||||
if (hearts > 30) hearts = 30;
|
||||
|
||||
final int MARGIN = 52;
|
||||
final int BACKGROUND = MARGIN + (unused ? 1 : 0);
|
||||
final int HALF = MARGIN + 45;
|
||||
final int FULL = MARGIN + 36;
|
||||
|
||||
for (int heart = 0; hearts > 0; heart += 20)
|
||||
{
|
||||
int top = height - right_height;
|
||||
|
||||
int rowCount = Math.min(hearts, 10);
|
||||
hearts -= rowCount;
|
||||
|
||||
for (int i = 0; i < rowCount; ++i)
|
||||
{
|
||||
int x = left_align - i * 8 - 9;
|
||||
drawTexturedModalRect(x, top, BACKGROUND, 9, 9, 9);
|
||||
|
||||
if (i * 2 + 1 + heart < health)
|
||||
drawTexturedModalRect(x, top, FULL, 9, 9, 9);
|
||||
else if (i * 2 + 1 + heart == health)
|
||||
drawTexturedModalRect(x, top, HALF, 9, 9, 9);
|
||||
}
|
||||
|
||||
right_height += 10;
|
||||
}
|
||||
GlStateManager.disableBlend();
|
||||
post(HEALTHMOUNT);
|
||||
}
|
||||
|
||||
//Helper macros
|
||||
private boolean pre(ElementType type)
|
||||
{
|
||||
return MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Pre(eventParent, type));
|
||||
}
|
||||
private void post(ElementType type)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(eventParent, type));
|
||||
}
|
||||
private void bind(ResourceLocation res)
|
||||
{
|
||||
mc.getTextureManager().bindTexture(res);
|
||||
}
|
||||
|
||||
private class GuiOverlayDebugForge extends GuiOverlayDebug
|
||||
{
|
||||
private Minecraft mc;
|
||||
private GuiOverlayDebugForge(Minecraft mc)
|
||||
{
|
||||
super(mc);
|
||||
this.mc = mc;
|
||||
}
|
||||
@Override protected void renderDebugInfoLeft(){}
|
||||
@Override protected void renderDebugInfoRight(ScaledResolution res){}
|
||||
private List<String> getLeft()
|
||||
{
|
||||
List<String> ret = this.call();
|
||||
ret.add("");
|
||||
ret.add("Debug: Pie [shift]: " + (this.mc.gameSettings.showDebugProfilerChart ? "visible" : "hidden") + " FPS [alt]: " + (this.mc.gameSettings.showLagometer ? "visible" : "hidden"));
|
||||
ret.add("For help: press F3 + Q");
|
||||
return ret;
|
||||
}
|
||||
private List<String> getRight(){ return this.getDebugInfoRight(); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
|
||||
/**
|
||||
* Client-side commands can implement this interface to allow additional control over when the command may be used.
|
||||
*/
|
||||
public interface IClientCommand extends ICommand
|
||||
{
|
||||
|
||||
/**
|
||||
* Determine whether this command can be used without the "/" prefix. By default this is true.
|
||||
* @param sender the command sender
|
||||
* @param message the message, without potential prefix
|
||||
* @return true to allow the usage of this command without the prefix
|
||||
*/
|
||||
boolean allowUsageWithoutPrefix(ICommandSender sender, String message);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
/**
|
||||
* @deprecated TODO remove in 1.13. This has never been used
|
||||
*/
|
||||
@Deprecated
|
||||
public interface IRenderContextHandler
|
||||
{
|
||||
/** Run before the specified rendering context.
|
||||
*/
|
||||
void beforeRenderContext();
|
||||
|
||||
/** Run after the specified rendering context.
|
||||
*/
|
||||
void afterRenderContext();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
|
||||
public abstract class IRenderHandler
|
||||
{
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract void render(float partialTicks, WorldClient world, Minecraft mc);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||
import net.minecraft.client.renderer.ItemModelMesher;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||
import net.minecraft.client.renderer.block.model.ModelManager;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Wrapper around ItemModeMesher that cleans up the internal maps to respect ID remapping.
|
||||
*/
|
||||
public class ItemModelMesherForge extends ItemModelMesher
|
||||
{
|
||||
final Map<IRegistryDelegate<Item>, Int2ObjectMap<ModelResourceLocation>> locations = Maps.newHashMap();
|
||||
final Map<IRegistryDelegate<Item>, Int2ObjectMap<IBakedModel>> models = Maps.newHashMap();
|
||||
|
||||
public ItemModelMesherForge(ModelManager manager)
|
||||
{
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected IBakedModel getItemModel(Item item, int meta)
|
||||
{
|
||||
Int2ObjectMap<IBakedModel> map = models.get(item.delegate);
|
||||
return map == null ? null : map.get(meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Item item, int meta, ModelResourceLocation location)
|
||||
{
|
||||
IRegistryDelegate<Item> key = item.delegate;
|
||||
Int2ObjectMap<ModelResourceLocation> locs = locations.get(key);
|
||||
Int2ObjectMap<IBakedModel> mods = models.get(key);
|
||||
if (locs == null)
|
||||
{
|
||||
locs = new Int2ObjectOpenHashMap<>();
|
||||
locations.put(key, locs);
|
||||
}
|
||||
if (mods == null)
|
||||
{
|
||||
mods = new Int2ObjectOpenHashMap<>();
|
||||
models.put(key, mods);
|
||||
}
|
||||
locs.put(meta, location);
|
||||
mods.put(meta, getModelManager().getModel(location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildCache()
|
||||
{
|
||||
final ModelManager manager = this.getModelManager();
|
||||
for (Map.Entry<IRegistryDelegate<Item>, Int2ObjectMap<ModelResourceLocation>> e : locations.entrySet())
|
||||
{
|
||||
Int2ObjectMap<IBakedModel> mods = models.get(e.getKey());
|
||||
if (mods != null)
|
||||
{
|
||||
mods.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
mods = new Int2ObjectOpenHashMap<>();
|
||||
models.put(e.getKey(), mods);
|
||||
}
|
||||
final Int2ObjectMap<IBakedModel> map = mods;
|
||||
e.getValue().int2ObjectEntrySet().forEach(entry ->
|
||||
map.put(entry.getIntKey(), manager.getModel(entry.getValue()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ModelResourceLocation getLocation(@Nonnull ItemStack stack)
|
||||
{
|
||||
Item item = stack.getItem();
|
||||
ModelResourceLocation location = null;
|
||||
|
||||
Int2ObjectMap<ModelResourceLocation> map = locations.get(item.delegate);
|
||||
if (map != null)
|
||||
{
|
||||
location = map.get(getMetadata(stack));
|
||||
}
|
||||
|
||||
if (location == null)
|
||||
{
|
||||
ItemMeshDefinition definition = shapers.get(item);
|
||||
if (definition != null)
|
||||
{
|
||||
location = definition.getModelLocation(stack);
|
||||
}
|
||||
}
|
||||
|
||||
if (location == null)
|
||||
{
|
||||
location = ModelBakery.MODEL_MISSING;
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.ChunkCache;
|
||||
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;
|
||||
|
||||
public class MinecraftForgeClient
|
||||
{
|
||||
public static int getRenderPass()
|
||||
{
|
||||
return ForgeHooksClient.renderPass;
|
||||
}
|
||||
|
||||
public static BlockRenderLayer getRenderLayer()
|
||||
{
|
||||
return ForgeHooksClient.renderLayer.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the Locale set by the player in Minecraft.
|
||||
* Useful for creating string and number formatters.
|
||||
*/
|
||||
public static Locale getLocale()
|
||||
{
|
||||
return Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getJavaLocale();
|
||||
}
|
||||
|
||||
private static BitSet stencilBits = new BitSet(8);
|
||||
static
|
||||
{
|
||||
stencilBits.set(0,8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve a stencil bit for use in rendering
|
||||
*
|
||||
* Note: you must check the Framebuffer you are working with to
|
||||
* determine if stencil bits are enabled on it before use.
|
||||
*
|
||||
* @return A bit or -1 if no further stencil bits are available
|
||||
*/
|
||||
public static int reserveStencilBit()
|
||||
{
|
||||
int bit = stencilBits.nextSetBit(0);
|
||||
if (bit >= 0)
|
||||
{
|
||||
stencilBits.clear(bit);
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the stencil bit for other use
|
||||
*
|
||||
* @param bit The bit from {@link #reserveStencilBit()}
|
||||
*/
|
||||
public static void releaseStencilBit(int bit)
|
||||
{
|
||||
if (bit >= 0 && bit < stencilBits.length())
|
||||
{
|
||||
stencilBits.set(bit);
|
||||
}
|
||||
}
|
||||
|
||||
private static final LoadingCache<Pair<World, BlockPos>, ChunkCache> regionCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(500)
|
||||
.concurrencyLevel(5)
|
||||
.expireAfterAccess(1, TimeUnit.SECONDS)
|
||||
.build(new CacheLoader<Pair<World, BlockPos>, ChunkCache>()
|
||||
{
|
||||
@Override
|
||||
public ChunkCache load(Pair<World, BlockPos> key)
|
||||
{
|
||||
return new ChunkCache(key.getLeft(), key.getRight().add(-1, -1, -1), key.getRight().add(16, 16, 16), 1);
|
||||
}
|
||||
});
|
||||
|
||||
public static void onRebuildChunk(World world, BlockPos position, ChunkCache cache)
|
||||
{
|
||||
regionCache.put(Pair.of(world, position), cache);
|
||||
}
|
||||
|
||||
public static ChunkCache getRegionRenderCache(World world, BlockPos pos)
|
||||
{
|
||||
int x = pos.getX() & ~0xF;
|
||||
int y = pos.getY() & ~0xF;
|
||||
int z = pos.getZ() & ~0xF;
|
||||
return regionCache.getUnchecked(Pair.of(world, new BlockPos(x, y, z)));
|
||||
}
|
||||
|
||||
public static void clearRenderCache()
|
||||
{
|
||||
regionCache.invalidateAll();
|
||||
regionCache.cleanUp();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
/**
|
||||
* ClientChatEvent is fired whenever the client is about to send a chat message or command to the server. <br>
|
||||
* This event is fired via {@link ForgeEventFactory#onClientSendMessage(String)},
|
||||
* which is executed by {@link GuiScreen#sendChatMessage(String, boolean)}<br>
|
||||
* <br>
|
||||
* {@link #message} contains the message that will be sent to the server. This can be changed by mods.<br>
|
||||
* {@link #originalMessage} contains the original message that was going to be sent to the server. This cannot be changed by mods.<br>
|
||||
* <br>
|
||||
* This event is {@link Cancelable}. <br>
|
||||
* If this event is canceled, the chat message or command is never sent to the server.<br>
|
||||
* <br>
|
||||
* This event does not have a result. {@link HasResult}<br>
|
||||
* <br>
|
||||
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
|
||||
**/
|
||||
@Cancelable
|
||||
public class ClientChatEvent extends Event
|
||||
{
|
||||
private String message;
|
||||
private final String originalMessage;
|
||||
public ClientChatEvent(String message)
|
||||
{
|
||||
this.setMessage(message);
|
||||
this.originalMessage = Strings.nullToEmpty(message);
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message)
|
||||
{
|
||||
this.message = Strings.nullToEmpty(message);
|
||||
}
|
||||
|
||||
public String getOriginalMessage()
|
||||
{
|
||||
return originalMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.util.text.ChatType;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
@Cancelable
|
||||
public class ClientChatReceivedEvent extends Event
|
||||
{
|
||||
private ITextComponent message;
|
||||
private final ChatType type;
|
||||
public ClientChatReceivedEvent(ChatType type, ITextComponent message)
|
||||
{
|
||||
this.type = type;
|
||||
this.setMessage(message);
|
||||
}
|
||||
|
||||
public ITextComponent getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(ITextComponent message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ChatType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.client.renderer.color.BlockColors;
|
||||
import net.minecraft.client.renderer.color.ItemColors;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Use these events to register block/item
|
||||
* color handlers at the appropriate time.
|
||||
*/
|
||||
public abstract class ColorHandlerEvent extends Event
|
||||
{
|
||||
public static class Block extends ColorHandlerEvent
|
||||
{
|
||||
private final BlockColors blockColors;
|
||||
|
||||
public Block(BlockColors blockColors)
|
||||
{
|
||||
this.blockColors = blockColors;
|
||||
}
|
||||
|
||||
public BlockColors getBlockColors()
|
||||
{
|
||||
return blockColors;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Item extends ColorHandlerEvent
|
||||
{
|
||||
private final ItemColors itemColors;
|
||||
private final BlockColors blockColors;
|
||||
|
||||
public Item(ItemColors itemColors, BlockColors blockColors)
|
||||
{
|
||||
this.itemColors = itemColors;
|
||||
this.blockColors = blockColors;
|
||||
}
|
||||
|
||||
public ItemColors getItemColors()
|
||||
{
|
||||
return itemColors;
|
||||
}
|
||||
|
||||
public BlockColors getBlockColors()
|
||||
{
|
||||
return blockColors;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
|
||||
@Cancelable
|
||||
public class DrawBlockHighlightEvent extends Event
|
||||
{
|
||||
private final RenderGlobal context;
|
||||
private final EntityPlayer player;
|
||||
private final RayTraceResult target;
|
||||
private final int subID;
|
||||
private final float partialTicks;
|
||||
|
||||
public DrawBlockHighlightEvent(RenderGlobal context, EntityPlayer player, RayTraceResult target, int subID, float partialTicks)
|
||||
{
|
||||
this.context = context;
|
||||
this.player = player;
|
||||
this.target = target;
|
||||
this.subID = subID;
|
||||
this.partialTicks= partialTicks;
|
||||
}
|
||||
|
||||
public RenderGlobal getContext() { return context; }
|
||||
public EntityPlayer getPlayer() { return player; }
|
||||
public RayTraceResult getTarget() { return target; }
|
||||
public int getSubID() { return subID; }
|
||||
public float getPartialTicks() { return partialTicks; }
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Event.HasResult;
|
||||
|
||||
/**
|
||||
* Event that hooks into EntityRenderer, allowing any feature to customize visual attributes
|
||||
* the player sees.
|
||||
*/
|
||||
public abstract class EntityViewRenderEvent extends Event
|
||||
{
|
||||
private final EntityRenderer renderer;
|
||||
private final Entity entity;
|
||||
private final IBlockState state;
|
||||
private final double renderPartialTicks;
|
||||
|
||||
public EntityViewRenderEvent(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.entity = entity;
|
||||
this.state = state;
|
||||
this.renderPartialTicks = renderPartialTicks;
|
||||
}
|
||||
|
||||
public EntityRenderer getRenderer()
|
||||
{
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public Entity getEntity()
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
|
||||
public IBlockState getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
public double getRenderPartialTicks()
|
||||
{
|
||||
return renderPartialTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that allows any feature to customize the fog density the player sees.
|
||||
* NOTE: In order to make this event have an effect, you must cancel the event
|
||||
*/
|
||||
@Cancelable
|
||||
public static class FogDensity extends EntityViewRenderEvent
|
||||
{
|
||||
private float density;
|
||||
|
||||
public FogDensity(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks, float density)
|
||||
{
|
||||
super(renderer, entity, state, renderPartialTicks);
|
||||
this.setDensity(density);
|
||||
}
|
||||
|
||||
public float getDensity()
|
||||
{
|
||||
return density;
|
||||
}
|
||||
|
||||
public void setDensity(float density)
|
||||
{
|
||||
this.density = density;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that allows any feature to customize the rendering of fog.
|
||||
*/
|
||||
@HasResult
|
||||
public static class RenderFogEvent extends EntityViewRenderEvent
|
||||
{
|
||||
private final int fogMode;
|
||||
private final float farPlaneDistance;
|
||||
|
||||
public RenderFogEvent(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks, int fogMode, float farPlaneDistance)
|
||||
{
|
||||
super(renderer, entity, state, renderPartialTicks);
|
||||
this.fogMode = fogMode;
|
||||
this.farPlaneDistance = farPlaneDistance;
|
||||
}
|
||||
|
||||
public int getFogMode()
|
||||
{
|
||||
return fogMode;
|
||||
}
|
||||
|
||||
public float getFarPlaneDistance()
|
||||
{
|
||||
return farPlaneDistance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that allows any feature to customize the color of fog the player sees.
|
||||
* NOTE: Any change made to one of the color variables will affect the result seen in-game.
|
||||
*/
|
||||
public static class FogColors extends EntityViewRenderEvent
|
||||
{
|
||||
private float red;
|
||||
private float green;
|
||||
private float blue;
|
||||
|
||||
public FogColors(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks, float red, float green, float blue)
|
||||
{
|
||||
super(renderer, entity, state, renderPartialTicks);
|
||||
this.setRed(red);
|
||||
this.setGreen(green);
|
||||
this.setBlue(blue);
|
||||
}
|
||||
|
||||
public float getRed() { return red; }
|
||||
public void setRed(float red) { this.red = red; }
|
||||
public float getGreen() { return green; }
|
||||
public void setGreen(float green) { this.green = green; }
|
||||
public float getBlue() { return blue; }
|
||||
public void setBlue(float blue) { this.blue = blue; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that allows mods to alter the angles of the player's camera. Mainly useful for applying roll.
|
||||
*/
|
||||
public static class CameraSetup extends EntityViewRenderEvent
|
||||
{
|
||||
private float yaw;
|
||||
private float pitch;
|
||||
private float roll;
|
||||
|
||||
public CameraSetup(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks, float yaw, float pitch, float roll)
|
||||
{
|
||||
super(renderer, entity, state, renderPartialTicks);
|
||||
this.setYaw(yaw);
|
||||
this.setPitch(pitch);
|
||||
this.setRoll(roll);
|
||||
}
|
||||
|
||||
public float getYaw() { return yaw; }
|
||||
public void setYaw(float yaw) { this.yaw = yaw; }
|
||||
public float getPitch() { return pitch; }
|
||||
public void setPitch(float pitch) { this.pitch = pitch; }
|
||||
public float getRoll() { return roll; }
|
||||
public void setRoll(float roll) { this.roll = roll; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that allows mods to alter the raw FOV itself.
|
||||
* This directly affects to the FOV without being modified.
|
||||
* */
|
||||
public static class FOVModifier extends EntityViewRenderEvent
|
||||
{
|
||||
private float fov;
|
||||
|
||||
public FOVModifier(EntityRenderer renderer, Entity entity, IBlockState state, double renderPartialTicks, float fov) {
|
||||
super(renderer, entity, state, renderPartialTicks);
|
||||
this.setFOV(fov);
|
||||
}
|
||||
|
||||
public float getFOV() {
|
||||
return fov;
|
||||
}
|
||||
|
||||
public void setFOV(float fov) {
|
||||
this.fov = fov;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Author: MachineMuse (Claire Semple)
|
||||
* Created: 6:07 PM, 9/5/13
|
||||
*/
|
||||
public class FOVUpdateEvent extends Event
|
||||
{
|
||||
private final EntityPlayer entity;
|
||||
private final float fov;
|
||||
private float newfov;
|
||||
|
||||
public FOVUpdateEvent(EntityPlayer entity, float fov)
|
||||
{
|
||||
this.entity = entity;
|
||||
this.fov = fov;
|
||||
this.setNewfov(fov);
|
||||
}
|
||||
|
||||
public EntityPlayer getEntity()
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
|
||||
public float getFov()
|
||||
{
|
||||
return fov;
|
||||
}
|
||||
|
||||
public float getNewfov()
|
||||
{
|
||||
return newfov;
|
||||
}
|
||||
|
||||
public void setNewfov(float newfov)
|
||||
{
|
||||
this.newfov = newfov;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Event class for handling GuiContainer specific events.
|
||||
*/
|
||||
public class GuiContainerEvent extends Event
|
||||
{
|
||||
|
||||
private final GuiContainer guiContainer;
|
||||
|
||||
public GuiContainerEvent(GuiContainer guiContainer)
|
||||
{
|
||||
this.guiContainer = guiContainer;
|
||||
}
|
||||
|
||||
public GuiContainer getGuiContainer()
|
||||
{
|
||||
return guiContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is fired directly after the GuiContainer has draw any foreground elements,
|
||||
* But before the "dragged" stack, and before any tooltips.
|
||||
* This is useful for any slot / item specific overlays.
|
||||
* Things that need to be on top of All GUI elements but bellow tooltips and dragged stacks.
|
||||
*/
|
||||
public static class DrawForeground extends GuiContainerEvent
|
||||
{
|
||||
private final int mouseX;
|
||||
private final int mouseY;
|
||||
|
||||
/**
|
||||
* Called directly after the GuiContainer has drawn any foreground elements.
|
||||
*
|
||||
* @param guiContainer The container.
|
||||
* @param mouseX The current X position of the players mouse.
|
||||
* @param mouseY The current Y position of the players mouse.
|
||||
*/
|
||||
public DrawForeground(GuiContainer guiContainer, int mouseX, int mouseY)
|
||||
{
|
||||
super(guiContainer);
|
||||
this.mouseX = mouseX;
|
||||
this.mouseY = mouseY;
|
||||
}
|
||||
|
||||
public int getMouseX()
|
||||
{
|
||||
return mouseX;
|
||||
}
|
||||
|
||||
public int getMouseY()
|
||||
{
|
||||
return mouseY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
/**
|
||||
* This event is called before any Gui will open.
|
||||
* If you don't want this to happen, cancel the event.
|
||||
* If you want to override this Gui, simply set the gui variable to your own Gui.
|
||||
*
|
||||
* @author jk-5
|
||||
*/
|
||||
@Cancelable
|
||||
public class GuiOpenEvent extends Event
|
||||
{
|
||||
private GuiScreen gui;
|
||||
public GuiOpenEvent(GuiScreen gui)
|
||||
{
|
||||
this.setGui(gui);
|
||||
}
|
||||
|
||||
public GuiScreen getGui()
|
||||
{
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void setGui(GuiScreen gui)
|
||||
{
|
||||
this.gui = gui;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.InventoryEffectRenderer;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* Event classes for GuiScreen events.
|
||||
*
|
||||
* @author bspkrs
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class GuiScreenEvent extends Event
|
||||
{
|
||||
private final GuiScreen gui;
|
||||
|
||||
public GuiScreenEvent(GuiScreen gui)
|
||||
{
|
||||
this.gui = gui;
|
||||
}
|
||||
|
||||
/**
|
||||
* The GuiScreen object generating this event.
|
||||
*/
|
||||
public GuiScreen getGui()
|
||||
{
|
||||
return gui;
|
||||
}
|
||||
|
||||
public static class InitGuiEvent extends GuiScreenEvent
|
||||
{
|
||||
private List<GuiButton> buttonList;
|
||||
|
||||
public InitGuiEvent(GuiScreen gui, List<GuiButton> buttonList)
|
||||
{
|
||||
super(gui);
|
||||
this.setButtonList(buttonList);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link #buttonList} field from the GuiScreen object referenced by {@link #gui}.
|
||||
*/
|
||||
public List<GuiButton> getButtonList()
|
||||
{
|
||||
return buttonList;
|
||||
}
|
||||
|
||||
public void setButtonList(List<GuiButton> buttonList)
|
||||
{
|
||||
this.buttonList = buttonList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires just after initializing {@link GuiScreen#mc}, {@link GuiScreen#fontRenderer},
|
||||
* {@link GuiScreen#width}, and {@link GuiScreen#height}.<br/><br/>
|
||||
*
|
||||
* If canceled the following lines are skipped in {@link GuiScreen#setWorldAndResolution(Minecraft, int, int)}:<br/>
|
||||
* {@code this.buttonList.clear();}<br/>
|
||||
* {@code this.initGui();}<br/>
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Pre extends InitGuiEvent
|
||||
{
|
||||
public Pre(GuiScreen gui, List<GuiButton> buttonList)
|
||||
{
|
||||
super(gui, buttonList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires right after {@link GuiScreen#initGui()}.
|
||||
* This is a good place to alter a GuiScreen's component layout if desired.
|
||||
*/
|
||||
public static class Post extends InitGuiEvent
|
||||
{
|
||||
public Post(GuiScreen gui, List<GuiButton> buttonList)
|
||||
{
|
||||
super(gui, buttonList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DrawScreenEvent extends GuiScreenEvent
|
||||
{
|
||||
private final int mouseX;
|
||||
private final int mouseY;
|
||||
private final float renderPartialTicks;
|
||||
|
||||
public DrawScreenEvent(GuiScreen gui, int mouseX, int mouseY, float renderPartialTicks)
|
||||
{
|
||||
super(gui);
|
||||
this.mouseX = mouseX;
|
||||
this.mouseY = mouseY;
|
||||
this.renderPartialTicks = renderPartialTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* The x coordinate of the mouse pointer on the screen.
|
||||
*/
|
||||
public int getMouseX()
|
||||
{
|
||||
return mouseX;
|
||||
}
|
||||
|
||||
/**
|
||||
* The y coordinate of the mouse pointer on the screen.
|
||||
*/
|
||||
public int getMouseY()
|
||||
{
|
||||
return mouseY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial render ticks elapsed.
|
||||
*/
|
||||
public float getRenderPartialTicks()
|
||||
{
|
||||
return renderPartialTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires just before {@link GuiScreen#drawScreen(int, int, float)} is called.
|
||||
* Cancel this event to skip {@link GuiScreen#drawScreen(int, int, float)}.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Pre extends DrawScreenEvent
|
||||
{
|
||||
public Pre(GuiScreen gui, int mouseX, int mouseY, float renderPartialTicks)
|
||||
{
|
||||
super(gui, mouseX, mouseY, renderPartialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires just after {@link GuiScreen#drawScreen(int, int, float)} is called.
|
||||
*/
|
||||
public static class Post extends DrawScreenEvent
|
||||
{
|
||||
public Post(GuiScreen gui, int mouseX, int mouseY, float renderPartialTicks)
|
||||
{
|
||||
super(gui, mouseX, mouseY, renderPartialTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires at the end of {@link GuiScreen#drawDefaultBackground()} and before the rest of the Gui draws.
|
||||
* This allows drawing next to Guis, above the background but below any tooltips.
|
||||
*/
|
||||
public static class BackgroundDrawnEvent extends GuiScreenEvent
|
||||
{
|
||||
private final int mouseX;
|
||||
private final int mouseY;
|
||||
|
||||
public BackgroundDrawnEvent(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
final ScaledResolution scaledresolution = new ScaledResolution(gui.mc);
|
||||
final int scaledWidth = scaledresolution.getScaledWidth();
|
||||
final int scaledHeight = scaledresolution.getScaledHeight();
|
||||
this.mouseX = Mouse.getX() * scaledWidth / gui.mc.displayWidth;
|
||||
this.mouseY = scaledHeight - Mouse.getY() * scaledHeight / gui.mc.displayHeight - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The x coordinate of the mouse pointer on the screen.
|
||||
*/
|
||||
public int getMouseX()
|
||||
{
|
||||
return mouseX;
|
||||
}
|
||||
|
||||
/**
|
||||
* The y coordinate of the mouse pointer on the screen.
|
||||
*/
|
||||
public int getMouseY()
|
||||
{
|
||||
return mouseY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires in {@link InventoryEffectRenderer#updateActivePotionEffects()}
|
||||
* when potion effects are active and the gui wants to move over.
|
||||
* Cancel this event to prevent the Gui from being moved.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class PotionShiftEvent extends GuiScreenEvent
|
||||
{
|
||||
public PotionShiftEvent(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActionPerformedEvent extends GuiScreenEvent
|
||||
{
|
||||
private GuiButton button;
|
||||
private List<GuiButton> buttonList;
|
||||
|
||||
public ActionPerformedEvent(GuiScreen gui, GuiButton button, List<GuiButton> buttonList)
|
||||
{
|
||||
super(gui);
|
||||
this.setButton(button);
|
||||
this.setButtonList(new ArrayList<GuiButton>(buttonList));
|
||||
}
|
||||
|
||||
/**
|
||||
* The button that was clicked.
|
||||
*/
|
||||
public GuiButton getButton()
|
||||
{
|
||||
return button;
|
||||
}
|
||||
|
||||
public void setButton(GuiButton button)
|
||||
{
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* A COPY of the {@link #buttonList} field from the GuiScreen referenced by {@link #gui}.
|
||||
*/
|
||||
public List<GuiButton> getButtonList()
|
||||
{
|
||||
return buttonList;
|
||||
}
|
||||
|
||||
public void setButtonList(List<GuiButton> buttonList)
|
||||
{
|
||||
this.buttonList = buttonList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires once it has been determined that a GuiButton object has been clicked.
|
||||
* Cancel this event to bypass {@link GuiScreen#actionPerformed(GuiButton)}.
|
||||
* Replace button with a different button from buttonList to have that button's action executed.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Pre extends ActionPerformedEvent
|
||||
{
|
||||
public Pre(GuiScreen gui, GuiButton button, List<GuiButton> buttonList)
|
||||
{
|
||||
super(gui, button, buttonList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires after {@link GuiScreen#actionPerformed(GuiButton)} provided that the active
|
||||
* screen has not been changed as a result of {@link GuiScreen#actionPerformed(GuiButton)}.
|
||||
*/
|
||||
public static class Post extends ActionPerformedEvent
|
||||
{
|
||||
public Post(GuiScreen gui, GuiButton button, List<GuiButton> buttonList)
|
||||
{
|
||||
super(gui, button, buttonList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MouseInputEvent extends GuiScreenEvent
|
||||
{
|
||||
public MouseInputEvent(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires when mouse input is detected by a GuiScreen.
|
||||
* Cancel this event to bypass {@link GuiScreen#handleMouseInput()}.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Pre extends MouseInputEvent
|
||||
{
|
||||
public Pre(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires after {@link GuiScreen#handleMouseInput()} provided that the active
|
||||
* screen has not been changed as a result of {@link GuiScreen#handleMouseInput()} and
|
||||
* the {@link GuiScreen#mouseHandled} flag has not been set.
|
||||
* Cancel this event when you successfully use the mouse input to prevent other handlers from using the same input.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Post extends MouseInputEvent
|
||||
{
|
||||
public Post(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeyboardInputEvent extends GuiScreenEvent
|
||||
{
|
||||
public KeyboardInputEvent(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires when keyboard input is detected by a GuiScreen.
|
||||
* Cancel this event to bypass {@link GuiScreen#handleKeyboardInput()}.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Pre extends KeyboardInputEvent
|
||||
{
|
||||
public Pre(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event fires after {@link GuiScreen#handleKeyboardInput()} provided that the active
|
||||
* screen has not been changed as a result of {@link GuiScreen#handleKeyboardInput()} and
|
||||
* the {@link GuiScreen#keyHandled} flag has not been set.
|
||||
* Cancel this event when you successfully use the keyboard input to prevent other handlers from using the same input.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Post extends KeyboardInputEvent
|
||||
{
|
||||
public Post(GuiScreen gui)
|
||||
{
|
||||
super(gui);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.MovementInput;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
|
||||
/**
|
||||
* This event is fired after player movement inputs are updated.<br>
|
||||
* Handlers can freely manipulate {@link MovementInput} to cancel movement.<br>
|
||||
*/
|
||||
public class InputUpdateEvent extends PlayerEvent
|
||||
{
|
||||
private final MovementInput movementInput;
|
||||
|
||||
public InputUpdateEvent(EntityPlayer player, MovementInput movementInput)
|
||||
{
|
||||
super(player);
|
||||
this.movementInput = movementInput;
|
||||
}
|
||||
|
||||
public MovementInput getMovementInput()
|
||||
{
|
||||
return movementInput;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelManager;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.util.registry.IRegistry;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Fired when the ModelManager is notified of the resource manager reloading.
|
||||
* Called after model registry is setup, but before it's passed to BlockModelShapes.
|
||||
*/
|
||||
// TODO: try to merge with ICustomModelLoader
|
||||
public class ModelBakeEvent extends Event
|
||||
{
|
||||
private final ModelManager modelManager;
|
||||
private final IRegistry<ModelResourceLocation, IBakedModel> modelRegistry;
|
||||
private final ModelLoader modelLoader;
|
||||
|
||||
public ModelBakeEvent(ModelManager modelManager, IRegistry<ModelResourceLocation, IBakedModel> modelRegistry, ModelLoader modelLoader)
|
||||
{
|
||||
this.modelManager = modelManager;
|
||||
this.modelRegistry = modelRegistry;
|
||||
this.modelLoader = modelLoader;
|
||||
}
|
||||
|
||||
public ModelManager getModelManager()
|
||||
{
|
||||
return modelManager;
|
||||
}
|
||||
|
||||
public IRegistry<ModelResourceLocation, IBakedModel> getModelRegistry()
|
||||
{
|
||||
return modelRegistry;
|
||||
}
|
||||
|
||||
public ModelLoader getModelLoader()
|
||||
{
|
||||
return modelLoader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraftforge.fml.common.eventhandler.IContextSetter;
|
||||
|
||||
/**
|
||||
* Fired when the {@link net.minecraftforge.client.model.ModelLoader} is ready to receive registrations
|
||||
*/
|
||||
public class ModelRegistryEvent extends Event implements IContextSetter
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Author: MachineMuse (Claire Semple)
|
||||
* Created: 2:46 PM, 9/4/13
|
||||
*/
|
||||
@Cancelable
|
||||
public class MouseEvent extends Event
|
||||
{
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int dx;
|
||||
private final int dy;
|
||||
private final int dwheel;
|
||||
private final int button;
|
||||
private final boolean buttonstate;
|
||||
private final long nanoseconds;
|
||||
|
||||
public MouseEvent()
|
||||
{
|
||||
this.x = Mouse.getEventX();
|
||||
this.y = Mouse.getEventY();
|
||||
this.dx = Mouse.getEventDX();
|
||||
this.dy = Mouse.getEventDY();
|
||||
this.dwheel = Mouse.getEventDWheel();
|
||||
this.button = Mouse.getEventButton();
|
||||
this.buttonstate = Mouse.getEventButtonState();
|
||||
this.nanoseconds = Mouse.getEventNanoseconds();
|
||||
}
|
||||
|
||||
public int getX() { return x; }
|
||||
public int getY() { return y; }
|
||||
public int getDx() { return dx; }
|
||||
public int getDy() { return dy; }
|
||||
public int getDwheel() { return dwheel; }
|
||||
public int getButton() { return button; }
|
||||
public boolean isButtonstate() { return buttonstate; }
|
||||
public long getNanoseconds() { return nanoseconds; }
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* This event is called before the pushOutOfBlocks calls in EntityPlayerSP.
|
||||
*
|
||||
* Cancelling the event will prevent pushOutOfBlocks from being called.
|
||||
*/
|
||||
@Cancelable
|
||||
public class PlayerSPPushOutOfBlocksEvent extends PlayerEvent
|
||||
{
|
||||
private AxisAlignedBB entityBoundingBox;
|
||||
|
||||
public PlayerSPPushOutOfBlocksEvent(EntityPlayer player, AxisAlignedBB entityBoundingBox)
|
||||
{
|
||||
super(player);
|
||||
this.entityBoundingBox = entityBoundingBox;
|
||||
}
|
||||
|
||||
public AxisAlignedBB getEntityBoundingBox() { return entityBoundingBox; }
|
||||
public void setEntityBoundingBox(@Nonnull AxisAlignedBB entityBoundingBox) { this.entityBoundingBox = entityBoundingBox; }
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Called when a block's texture is going to be overlaid on the player's HUD. Cancel this event to prevent the overlay.
|
||||
*/
|
||||
@Cancelable
|
||||
public class RenderBlockOverlayEvent extends Event {
|
||||
|
||||
public static enum OverlayType {
|
||||
FIRE, BLOCK, WATER
|
||||
}
|
||||
|
||||
private final EntityPlayer player;
|
||||
private final float renderPartialTicks;
|
||||
private final OverlayType overlayType;
|
||||
private final IBlockState blockForOverlay;
|
||||
private final BlockPos blockPos;
|
||||
|
||||
@Deprecated
|
||||
public RenderBlockOverlayEvent(EntityPlayer player, float renderPartialTicks, OverlayType type, Block block, int x, int y, int z)
|
||||
{
|
||||
this(player, renderPartialTicks, type, block.getDefaultState(), new BlockPos(x, y, z));
|
||||
}
|
||||
|
||||
public RenderBlockOverlayEvent(EntityPlayer player, float renderPartialTicks, OverlayType type, IBlockState block, BlockPos blockPos)
|
||||
{
|
||||
this.player = player;
|
||||
this.renderPartialTicks = renderPartialTicks;
|
||||
this.overlayType = type;
|
||||
this.blockForOverlay = block;
|
||||
this.blockPos = blockPos;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The player which the overlay will apply to
|
||||
*/
|
||||
public EntityPlayer getPlayer() { return player; }
|
||||
public float getRenderPartialTicks() { return renderPartialTicks; }
|
||||
/**
|
||||
* The type of overlay to occur
|
||||
*/
|
||||
public OverlayType getOverlayType() { return overlayType; }
|
||||
/**
|
||||
* If the overlay type is BLOCK, then this is the block which the overlay is getting it's icon from
|
||||
*/
|
||||
public IBlockState getBlockForOverlay() { return blockForOverlay; }
|
||||
public BlockPos getBlockPos() { return blockPos; }
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.gui.BossInfoClient;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
|
||||
@Cancelable
|
||||
public class RenderGameOverlayEvent extends Event
|
||||
{
|
||||
public float getPartialTicks()
|
||||
{
|
||||
return partialTicks;
|
||||
}
|
||||
|
||||
public ScaledResolution getResolution()
|
||||
{
|
||||
return resolution;
|
||||
}
|
||||
|
||||
public ElementType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public static enum ElementType
|
||||
{
|
||||
ALL,
|
||||
HELMET,
|
||||
PORTAL,
|
||||
CROSSHAIRS,
|
||||
BOSSHEALTH, // All boss bars
|
||||
BOSSINFO, // Individual boss bar
|
||||
ARMOR,
|
||||
HEALTH,
|
||||
FOOD,
|
||||
AIR,
|
||||
HOTBAR,
|
||||
EXPERIENCE,
|
||||
TEXT,
|
||||
HEALTHMOUNT,
|
||||
JUMPBAR,
|
||||
CHAT,
|
||||
PLAYER_LIST,
|
||||
DEBUG,
|
||||
POTION_ICONS,
|
||||
SUBTITLES,
|
||||
FPS_GRAPH,
|
||||
VIGNETTE
|
||||
}
|
||||
|
||||
private final float partialTicks;
|
||||
private final ScaledResolution resolution;
|
||||
private final ElementType type;
|
||||
|
||||
public RenderGameOverlayEvent(float partialTicks, ScaledResolution resolution)
|
||||
{
|
||||
this.partialTicks = partialTicks;
|
||||
this.resolution = resolution;
|
||||
this.type = null;
|
||||
}
|
||||
|
||||
private RenderGameOverlayEvent(RenderGameOverlayEvent parent, ElementType type)
|
||||
{
|
||||
this.partialTicks = parent.getPartialTicks();
|
||||
this.resolution = parent.getResolution();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static class Pre extends RenderGameOverlayEvent
|
||||
{
|
||||
public Pre(RenderGameOverlayEvent parent, ElementType type)
|
||||
{
|
||||
super(parent, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Post extends RenderGameOverlayEvent
|
||||
{
|
||||
public Post(RenderGameOverlayEvent parent, ElementType type)
|
||||
{
|
||||
super(parent, type);
|
||||
}
|
||||
@Override public boolean isCancelable(){ return false; }
|
||||
}
|
||||
|
||||
public static class BossInfo extends Pre
|
||||
{
|
||||
private final BossInfoClient bossInfo;
|
||||
private final int x;
|
||||
private final int y;
|
||||
private int increment;
|
||||
public BossInfo(RenderGameOverlayEvent parent, ElementType type, BossInfoClient bossInfo, int x, int y, int increment)
|
||||
{
|
||||
super(parent, type);
|
||||
this.bossInfo = bossInfo;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.increment = increment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link BossInfoClient} currently being rendered
|
||||
*/
|
||||
public BossInfoClient getBossInfo()
|
||||
{
|
||||
return bossInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current x position we are rendering at
|
||||
*/
|
||||
public int getX()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current y position we are rendering at
|
||||
*/
|
||||
public int getY()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How much to move down before rendering the next bar
|
||||
*/
|
||||
public int getIncrement()
|
||||
{
|
||||
return increment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount to move down before rendering the next bar
|
||||
* @param increment The increment to set
|
||||
*/
|
||||
public void setIncrement(int increment)
|
||||
{
|
||||
this.increment = increment;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Text extends Pre
|
||||
{
|
||||
private final ArrayList<String> left;
|
||||
private final ArrayList<String> right;
|
||||
public Text(RenderGameOverlayEvent parent, ArrayList<String> left, ArrayList<String> right)
|
||||
{
|
||||
super(parent, ElementType.TEXT);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public ArrayList<String> getLeft()
|
||||
{
|
||||
return left;
|
||||
}
|
||||
|
||||
public ArrayList<String> getRight()
|
||||
{
|
||||
return right;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Chat extends Pre
|
||||
{
|
||||
private int posX;
|
||||
private int posY;
|
||||
|
||||
public Chat(RenderGameOverlayEvent parent, int posX, int posY)
|
||||
{
|
||||
super(parent, ElementType.CHAT);
|
||||
this.setPosX(posX);
|
||||
this.setPosY(posY);
|
||||
}
|
||||
|
||||
public int getPosX()
|
||||
{
|
||||
return posX;
|
||||
}
|
||||
|
||||
public void setPosX(int posX)
|
||||
{
|
||||
this.posX = posX;
|
||||
}
|
||||
|
||||
public int getPosY()
|
||||
{
|
||||
return posY;
|
||||
}
|
||||
|
||||
public void setPosY(int posY)
|
||||
{
|
||||
this.posY = posY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
|
||||
/**
|
||||
* This event is fired on {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}
|
||||
* before both hands are rendered.
|
||||
* Canceling this event prevents either hand from being rendered,
|
||||
* and prevents {@link RenderSpecificHandEvent} from firing.
|
||||
* TODO This may get merged in 11 with RenderSpecificHandEvent to make a generic hand rendering
|
||||
*/
|
||||
@Cancelable
|
||||
public class RenderHandEvent extends Event
|
||||
{
|
||||
private final RenderGlobal context;
|
||||
private final float partialTicks;
|
||||
private final int renderPass;
|
||||
public RenderHandEvent(RenderGlobal context, float partialTicks, int renderPass)
|
||||
{
|
||||
this.context = context;
|
||||
this.partialTicks = partialTicks;
|
||||
this.renderPass = renderPass;
|
||||
}
|
||||
|
||||
public RenderGlobal getContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
public float getPartialTicks()
|
||||
{
|
||||
return partialTicks;
|
||||
}
|
||||
|
||||
public int getRenderPass()
|
||||
{
|
||||
return renderPass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.client.renderer.entity.RenderItemFrame;
|
||||
import net.minecraft.entity.item.EntityItemFrame;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* This event is called when an item is rendered in an item frame.
|
||||
*
|
||||
* You can set canceled to do no further vanilla processing.
|
||||
*/
|
||||
@Cancelable
|
||||
public class RenderItemInFrameEvent extends Event
|
||||
{
|
||||
private final ItemStack item;
|
||||
private final EntityItemFrame entityItemFrame;
|
||||
private final RenderItemFrame renderer;
|
||||
|
||||
public RenderItemInFrameEvent(EntityItemFrame itemFrame, RenderItemFrame renderItemFrame)
|
||||
{
|
||||
item = itemFrame.getDisplayedItem();
|
||||
entityItemFrame = itemFrame;
|
||||
renderer = renderItemFrame;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ItemStack getItem()
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
public EntityItemFrame getEntityItemFrame()
|
||||
{
|
||||
return entityItemFrame;
|
||||
}
|
||||
|
||||
public RenderItemFrame getRenderer()
|
||||
{
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
|
||||
public abstract class RenderLivingEvent<T extends EntityLivingBase> extends Event
|
||||
{
|
||||
private final EntityLivingBase entity;
|
||||
private final RenderLivingBase<T> renderer;
|
||||
private final float partialRenderTick;
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double z;
|
||||
|
||||
@Deprecated
|
||||
public RenderLivingEvent(EntityLivingBase entity, RenderLivingBase<T> renderer, double x, double y, double z)
|
||||
{
|
||||
this(entity, renderer, 1, x, y, z);
|
||||
}
|
||||
|
||||
public RenderLivingEvent(EntityLivingBase entity, RenderLivingBase<T> renderer, float partialRenderTick, double x, double y, double z)
|
||||
{
|
||||
this.entity = entity;
|
||||
this.renderer = renderer;
|
||||
this.partialRenderTick = partialRenderTick;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public EntityLivingBase getEntity() { return entity; }
|
||||
public RenderLivingBase<T> getRenderer() { return renderer; }
|
||||
public float getPartialRenderTick() { return partialRenderTick; }
|
||||
public double getX() { return x; }
|
||||
public double getY() { return y; }
|
||||
public double getZ() { return z; }
|
||||
|
||||
@Cancelable
|
||||
public static class Pre<T extends EntityLivingBase> extends RenderLivingEvent<T>
|
||||
{
|
||||
@Deprecated
|
||||
public Pre(EntityLivingBase entity, RenderLivingBase<T> renderer, double x, double y, double z){ super(entity, renderer, x, y, z); }
|
||||
public Pre(EntityLivingBase entity, RenderLivingBase<T> renderer, float partialRenderTick, double x, double y, double z){ super(entity, renderer, partialRenderTick, x, y, z); }
|
||||
}
|
||||
public static class Post<T extends EntityLivingBase> extends RenderLivingEvent<T>
|
||||
{
|
||||
@Deprecated
|
||||
public Post(EntityLivingBase entity, RenderLivingBase<T> renderer, double x, double y, double z){ super(entity, renderer, x, y, z); }
|
||||
public Post(EntityLivingBase entity, RenderLivingBase<T> renderer, float partialRenderTick, double x, double y, double z){ super(entity, renderer, partialRenderTick, x, y, z); }
|
||||
}
|
||||
|
||||
public abstract static class Specials<T extends EntityLivingBase> extends RenderLivingEvent<T>
|
||||
{
|
||||
public Specials(EntityLivingBase entity, RenderLivingBase<T> renderer, double x, double y, double z){ super(entity, renderer, 0, x, y, z); }
|
||||
|
||||
@Cancelable
|
||||
public static class Pre<T extends EntityLivingBase> extends Specials<T>
|
||||
{
|
||||
public Pre(EntityLivingBase entity, RenderLivingBase<T> renderer, double x, double y, double z){ super(entity, renderer, x, y, z); }
|
||||
}
|
||||
public static class Post<T extends EntityLivingBase> extends Specials<T>
|
||||
{
|
||||
public Post(EntityLivingBase entity, RenderLivingBase<T> renderer, double x, double y, double z){ super(entity, renderer, x, y, z); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraft.client.renderer.entity.RenderPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public abstract class RenderPlayerEvent extends PlayerEvent
|
||||
{
|
||||
private final RenderPlayer renderer;
|
||||
private final float partialRenderTick;
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double z;
|
||||
|
||||
public RenderPlayerEvent(EntityPlayer player, RenderPlayer renderer, float partialRenderTick, double x, double y, double z)
|
||||
{
|
||||
super(player);
|
||||
this.renderer = renderer;
|
||||
this.partialRenderTick = partialRenderTick;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public RenderPlayer getRenderer() { return renderer; }
|
||||
public float getPartialRenderTick() { return partialRenderTick; }
|
||||
public double getX() { return x; }
|
||||
public double getY() { return y; }
|
||||
public double getZ() { return z; }
|
||||
|
||||
@Cancelable
|
||||
public static class Pre extends RenderPlayerEvent
|
||||
{
|
||||
public Pre(EntityPlayer player, RenderPlayer renderer, float tick, double x, double y, double z){ super(player, renderer, tick, x, y, z); }
|
||||
@Deprecated
|
||||
public Pre(EntityPlayer player, RenderPlayer renderer, float tick){ this(player, renderer, tick, 0D, 0D, 0D); }
|
||||
}
|
||||
|
||||
public static class Post extends RenderPlayerEvent
|
||||
{
|
||||
public Post(EntityPlayer player, RenderPlayer renderer, float tick, double x, double y, double z){ super(player, renderer, tick, x, y, z); }
|
||||
@Deprecated
|
||||
public Post(EntityPlayer player, RenderPlayer renderer, float tick){ this(player, renderer, tick, 0D, 0D, 0D); }
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public abstract static class Specials extends RenderPlayerEvent
|
||||
{
|
||||
public Specials(EntityPlayer player, RenderPlayer renderer, float partialTicks)
|
||||
{
|
||||
super(player, renderer, partialTicks, 0D, 0D, 0D);
|
||||
}
|
||||
|
||||
@Cancelable
|
||||
public static class Pre extends Specials
|
||||
{
|
||||
private boolean renderHelmet = true;
|
||||
private boolean renderCape = true;
|
||||
private boolean renderItem = true;
|
||||
public Pre(EntityPlayer player, RenderPlayer renderer, float partialTicks){ super(player, renderer, partialTicks); }
|
||||
|
||||
public boolean shouldRenderHelmet() { return renderHelmet; }
|
||||
public void setRenderHelmet(boolean renderHelmet) { this.renderHelmet = renderHelmet; }
|
||||
public boolean shouldRenderCape() { return renderCape; }
|
||||
public void setRenderCape(boolean renderCape) { this.renderCape = renderCape; }
|
||||
public boolean shouldRenderItem() { return renderItem; }
|
||||
public void setRenderItem(boolean renderItem) { this.renderItem = renderItem; }
|
||||
}
|
||||
|
||||
public static class Post extends Specials
|
||||
{
|
||||
public Post(EntityPlayer player, RenderPlayer renderer, float partialTicks){ super(player, renderer, partialTicks); }
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class SetArmorModel extends RenderPlayerEvent
|
||||
{
|
||||
private int result = -1;
|
||||
private final int slot;
|
||||
@Nonnull
|
||||
private final ItemStack stack;
|
||||
public SetArmorModel(EntityPlayer player, RenderPlayer renderer, int slot, float partialTick, @Nonnull ItemStack stack)
|
||||
{
|
||||
super(player, renderer, partialTick, 0D, 0D, 0D);
|
||||
this.slot = slot;
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting this to any value besides -1 will result in the function being
|
||||
* Immediately exited with the return value specified.
|
||||
*/
|
||||
public int getResultValue()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(int result)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public int getSlot()
|
||||
{
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ItemStack getStack()
|
||||
{
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* This event is fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}
|
||||
* whenever a hand is rendered in first person.
|
||||
* Canceling the event causes the hand to not render.
|
||||
* TODO This may get merged in 11 with RenderHandEvent to make a generic hand rendering
|
||||
*/
|
||||
@Cancelable
|
||||
public class RenderSpecificHandEvent extends Event
|
||||
{
|
||||
private final EnumHand hand;
|
||||
private final float partialTicks;
|
||||
private final float interpolatedPitch;
|
||||
private final float swingProgress;
|
||||
private final float equipProgress;
|
||||
@Nonnull
|
||||
private final ItemStack stack;
|
||||
|
||||
public RenderSpecificHandEvent(EnumHand hand, float partialTicks, float interpolatedPitch, float swingProgress, float equipProgress, @Nonnull ItemStack stack)
|
||||
{
|
||||
this.hand = hand;
|
||||
this.partialTicks = partialTicks;
|
||||
this.interpolatedPitch = interpolatedPitch;
|
||||
this.swingProgress = swingProgress;
|
||||
this.equipProgress = equipProgress;
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
public EnumHand getHand()
|
||||
{
|
||||
return hand;
|
||||
}
|
||||
|
||||
public float getPartialTicks()
|
||||
{
|
||||
return partialTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The interpolated pitch of the player entity
|
||||
*/
|
||||
public float getInterpolatedPitch()
|
||||
{
|
||||
return interpolatedPitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The swing progress of the hand being rendered
|
||||
*/
|
||||
public float getSwingProgress()
|
||||
{
|
||||
return swingProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The progress of the equip animation. 1.0 is fully equipped.
|
||||
*/
|
||||
public float getEquipProgress()
|
||||
{
|
||||
return equipProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ItemStack to be rendered, or null.
|
||||
*/
|
||||
@Nonnull
|
||||
public ItemStack getItemStack()
|
||||
{
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* A set of events which are fired at various points during tooltip rendering.
|
||||
* <p>
|
||||
* Can be used to change the rendering parameters, draw something extra, etc.
|
||||
* <p>
|
||||
* Do not use this event directly, use one of the subclasses:
|
||||
* <ul>
|
||||
* <li>{@link RenderTooltipEvent.Pre}</li>
|
||||
* <li>{@link RenderTooltipEvent.PostBackground}</li>
|
||||
* <li>{@link RenderTooltipEvent.PostText}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public abstract class RenderTooltipEvent extends Event
|
||||
{
|
||||
@Nonnull
|
||||
protected final ItemStack stack;
|
||||
protected final List<String> lines;
|
||||
protected int x;
|
||||
protected int y;
|
||||
protected FontRenderer fr;
|
||||
|
||||
public RenderTooltipEvent(@Nonnull ItemStack stack, @Nonnull List<String> lines, int x, int y, @Nonnull FontRenderer fr)
|
||||
{
|
||||
this.stack = stack;
|
||||
this.lines = Collections.unmodifiableList(lines); // Leave editing to ItemTooltipEvent
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.fr = fr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The stack which the tooltip is being rendered for. As tooltips can be drawn without itemstacks, this stack may be empty.
|
||||
*/
|
||||
@Nonnull
|
||||
public ItemStack getStack()
|
||||
{
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lines to be drawn. May change between {@link RenderTooltipEvent.Pre} and {@link RenderTooltipEvent.Post}.
|
||||
*
|
||||
* @return An <i>unmodifiable</i> list of strings. Use {@link ItemTooltipEvent} to modify tooltip text.
|
||||
*/
|
||||
@Nonnull
|
||||
public List<String> getLines()
|
||||
{
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The X position of the tooltip box. By default, the mouse X position.
|
||||
*/
|
||||
public int getX()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Y position of the tooltip box. By default, the mouse Y position.
|
||||
*/
|
||||
public int getY()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link FontRenderer} instance the current render is using.
|
||||
*/
|
||||
@Nonnull
|
||||
public FontRenderer getFontRenderer()
|
||||
{
|
||||
return fr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is fired before any tooltip calculations are done. It provides setters for all aspects of the tooltip, so the final render can be modified.
|
||||
* <p>
|
||||
* This event is {@link Cancelable}.
|
||||
*/
|
||||
@Cancelable
|
||||
public static class Pre extends RenderTooltipEvent
|
||||
{
|
||||
private int screenWidth;
|
||||
private int screenHeight;
|
||||
private int maxWidth;
|
||||
|
||||
public Pre(@Nonnull ItemStack stack, @Nonnull List<String> lines, int x, int y, int screenWidth, int screenHeight, int maxWidth, @Nonnull FontRenderer fr)
|
||||
{
|
||||
super(stack, lines, x, y, fr);
|
||||
this.screenWidth = screenWidth;
|
||||
this.screenHeight = screenHeight;
|
||||
this.maxWidth = maxWidth;
|
||||
}
|
||||
|
||||
public int getScreenWidth()
|
||||
{
|
||||
return screenWidth;
|
||||
}
|
||||
|
||||
public void setScreenWidth(int screenWidth)
|
||||
{
|
||||
this.screenWidth = screenWidth;
|
||||
}
|
||||
|
||||
public int getScreenHeight()
|
||||
{
|
||||
return screenHeight;
|
||||
}
|
||||
|
||||
public void setScreenHeight(int screenHeight)
|
||||
{
|
||||
this.screenHeight = screenHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The max width the tooltip can be. Defaults to -1 (unlimited).
|
||||
*/
|
||||
public int getMaxWidth()
|
||||
{
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max width of the tooltip. Use -1 for unlimited.
|
||||
*/
|
||||
public void setMaxWidth(int maxWidth)
|
||||
{
|
||||
this.maxWidth = maxWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link FontRenderer} to be used to render text.
|
||||
*/
|
||||
public void setFontRenderer(@Nonnull FontRenderer fr)
|
||||
{
|
||||
this.fr = fr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the X origin of the tooltip.
|
||||
*/
|
||||
public void setX(int x)
|
||||
{
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Y origin of the tooltip.
|
||||
*/
|
||||
public void setY(int y)
|
||||
{
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Events inheriting from this class are fired at different stages during the tooltip rendering.
|
||||
* <p>
|
||||
* Do not use this event directly, use one of its subclasses:
|
||||
* <ul>
|
||||
* <li>{@link RenderTooltipEvent.PostBackground}</li>
|
||||
* <li>{@link RenderTooltipEvent.PostText}</li>
|
||||
* </ul>
|
||||
*/
|
||||
protected static abstract class Post extends RenderTooltipEvent
|
||||
{
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public Post(@Nonnull ItemStack stack, @Nonnull List<String> textLines, int x, int y, @Nonnull FontRenderer fr, int width, int height)
|
||||
{
|
||||
super(stack, textLines, x, y, fr);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The width of the tooltip box. This is the width of the <i>inner</i> box, not including the border.
|
||||
*/
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the tooltip box. This is the height of the <i>inner</i> box, not including the border.
|
||||
*/
|
||||
public int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is fired directly after the tooltip background is drawn, but before any text is drawn.
|
||||
*/
|
||||
public static class PostBackground extends Post
|
||||
{
|
||||
public PostBackground(@Nonnull ItemStack stack, @Nonnull List<String> textLines, int x, int y, @Nonnull FontRenderer fr, int width, int height)
|
||||
{ super(stack, textLines, x, y, fr, width, height); }
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is fired directly after the tooltip text is drawn, but before the GL state is reset.
|
||||
*/
|
||||
public static class PostText extends Post
|
||||
{
|
||||
public PostText(@Nonnull ItemStack stack, @Nonnull List<String> textLines, int x, int y, @Nonnull FontRenderer fr, int width, int height)
|
||||
{ super(stack, textLines, x, y, fr, width, height); }
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is fired when the colours for the tooltip background are determined.
|
||||
*/
|
||||
public static class Color extends RenderTooltipEvent
|
||||
{
|
||||
private final int originalBackground;
|
||||
private final int originalBorderStart;
|
||||
private final int originalBorderEnd;
|
||||
private int background;
|
||||
private int borderStart;
|
||||
private int borderEnd;
|
||||
|
||||
public Color(@Nonnull ItemStack stack, @Nonnull List<String> textLines, int x, int y, @Nonnull FontRenderer fr, int background, int borderStart,
|
||||
int borderEnd)
|
||||
{
|
||||
super(stack, textLines, x, y, fr);
|
||||
this.originalBackground = background;
|
||||
this.originalBorderStart = borderStart;
|
||||
this.originalBorderEnd = borderEnd;
|
||||
this.background = background;
|
||||
this.borderStart = borderStart;
|
||||
this.borderEnd = borderEnd;
|
||||
}
|
||||
|
||||
public int getBackground()
|
||||
{
|
||||
return background;
|
||||
}
|
||||
|
||||
public void setBackground(int background)
|
||||
{
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
public int getBorderStart()
|
||||
{
|
||||
return borderStart;
|
||||
}
|
||||
|
||||
public void setBorderStart(int borderStart)
|
||||
{
|
||||
this.borderStart = borderStart;
|
||||
}
|
||||
|
||||
public int getBorderEnd()
|
||||
{
|
||||
return borderEnd;
|
||||
}
|
||||
|
||||
public void setBorderEnd(int borderEnd)
|
||||
{
|
||||
this.borderEnd = borderEnd;
|
||||
}
|
||||
|
||||
public int getOriginalBackground()
|
||||
{
|
||||
return originalBackground;
|
||||
}
|
||||
|
||||
public int getOriginalBorderStart()
|
||||
{
|
||||
return originalBorderStart;
|
||||
}
|
||||
|
||||
public int getOriginalBorderEnd()
|
||||
{
|
||||
return originalBorderEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
|
||||
public class RenderWorldLastEvent extends Event
|
||||
{
|
||||
private final RenderGlobal context;
|
||||
private final float partialTicks;
|
||||
public RenderWorldLastEvent(RenderGlobal context, float partialTicks)
|
||||
{
|
||||
this.context = context;
|
||||
this.partialTicks = partialTicks;
|
||||
}
|
||||
|
||||
public RenderGlobal getContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
public float getPartialTicks()
|
||||
{
|
||||
return partialTicks;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This event is fired before and after a screenshot is taken
|
||||
* This event is fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}
|
||||
* This event is {@link Cancelable}
|
||||
*
|
||||
* {@link #screenshotFile} contains the file the screenshot will be/was saved to
|
||||
* {@link #image} contains the {@link BufferedImage} that will be saved
|
||||
* {@link #resultMessage} contains the {@link ITextComponent} to be returned. If {@code null}, the default vanilla message will be used instead
|
||||
*/
|
||||
@Cancelable
|
||||
public class ScreenshotEvent extends Event
|
||||
{
|
||||
|
||||
public static final ITextComponent DEFAULT_CANCEL_REASON = new TextComponentString("Screenshot canceled");
|
||||
|
||||
private BufferedImage image;
|
||||
private File screenshotFile;
|
||||
|
||||
private ITextComponent resultMessage = null;
|
||||
|
||||
public ScreenshotEvent(BufferedImage image, File screenshotFile)
|
||||
{
|
||||
this.image = image;
|
||||
this.screenshotFile = screenshotFile;
|
||||
}
|
||||
|
||||
public BufferedImage getImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
public File getScreenshotFile()
|
||||
{
|
||||
return screenshotFile;
|
||||
}
|
||||
|
||||
public void setScreenshotFile(File screenshotFile)
|
||||
{
|
||||
this.screenshotFile = screenshotFile;
|
||||
}
|
||||
|
||||
public ITextComponent getResultMessage()
|
||||
{
|
||||
return resultMessage;
|
||||
}
|
||||
|
||||
public void setResultMessage(ITextComponent resultMessage)
|
||||
{
|
||||
this.resultMessage = resultMessage;
|
||||
}
|
||||
|
||||
public ITextComponent getCancelMessage()
|
||||
{
|
||||
return getResultMessage() != null ? getResultMessage() : DEFAULT_CANCEL_REASON;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
|
||||
|
||||
public class TextureStitchEvent extends Event
|
||||
{
|
||||
private final TextureMap map;
|
||||
|
||||
public TextureStitchEvent(TextureMap map)
|
||||
{
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public TextureMap getMap()
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the TextureMap is told to refresh it's stitched texture.
|
||||
* Called after the Stitched list is cleared, but before any blocks or items
|
||||
* add themselves to the list.
|
||||
*/
|
||||
public static class Pre extends TextureStitchEvent
|
||||
{
|
||||
public Pre(TextureMap map){ super(map); }
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is fired once the texture map has loaded all textures and
|
||||
* stitched them together. All Icons should have there locations defined
|
||||
* by the time this is fired.
|
||||
*/
|
||||
public static class Post extends TextureStitchEvent
|
||||
{
|
||||
public Post(TextureMap map){ super(map); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event.sound;
|
||||
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
|
||||
/***
|
||||
* Raised when the SoundManager tries to play a normal sound.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*/
|
||||
public class PlaySoundEvent extends SoundEvent
|
||||
{
|
||||
private final String name;
|
||||
private final ISound sound;
|
||||
private ISound result;
|
||||
|
||||
public PlaySoundEvent(SoundManager manager, ISound sound)
|
||||
{
|
||||
super(manager);
|
||||
this.sound = sound;
|
||||
this.name = sound.getSoundLocation().getResourcePath();
|
||||
this.setResultSound(sound);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public ISound getSound()
|
||||
{
|
||||
return sound;
|
||||
}
|
||||
|
||||
public ISound getResultSound()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResultSound(ISound result)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event.sound;
|
||||
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
import net.minecraftforge.client.event.sound.SoundEvent.SoundSourceEvent;
|
||||
|
||||
public class PlaySoundSourceEvent extends SoundSourceEvent
|
||||
{
|
||||
public PlaySoundSourceEvent(SoundManager manager, ISound sound, String uuid)
|
||||
{
|
||||
super(manager, sound, uuid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event.sound;
|
||||
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
import net.minecraftforge.client.event.sound.SoundEvent.SoundSourceEvent;
|
||||
|
||||
public class PlayStreamingSourceEvent extends SoundSourceEvent
|
||||
{
|
||||
public PlayStreamingSourceEvent(SoundManager manager, ISound sound, String uuid)
|
||||
{
|
||||
super(manager, sound, uuid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event.sound;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
|
||||
public class SoundEvent extends Event
|
||||
{
|
||||
private final SoundManager manager;
|
||||
public SoundEvent(SoundManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public SoundManager getManager()
|
||||
{
|
||||
return manager;
|
||||
}
|
||||
|
||||
public static class SoundSourceEvent extends SoundEvent
|
||||
{
|
||||
private final ISound sound;
|
||||
private final String uuid;
|
||||
private final String name;
|
||||
|
||||
public SoundSourceEvent(SoundManager manager, ISound sound, String uuid)
|
||||
{
|
||||
super(manager);
|
||||
this.name = sound.getSoundLocation().getResourcePath();
|
||||
this.sound = sound;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public ISound getSound()
|
||||
{
|
||||
return sound;
|
||||
}
|
||||
|
||||
public String getUuid()
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event.sound;
|
||||
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
|
||||
/**
|
||||
* Raised by the SoundManager.loadSoundSettings, this would be a good place for
|
||||
* adding your custom sounds to the SoundPool.
|
||||
*/
|
||||
public class SoundLoadEvent extends SoundEvent
|
||||
{
|
||||
public SoundLoadEvent(SoundManager manager)
|
||||
{
|
||||
super(manager);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.event.sound;
|
||||
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
|
||||
/**
|
||||
* This event is raised by the SoundManager when it does its first setup of the
|
||||
* SoundSystemConfig's codecs, use this function to add your own codecs.
|
||||
*/
|
||||
public class SoundSetupEvent extends SoundEvent
|
||||
{
|
||||
public SoundSetupEvent(SoundManager manager)
|
||||
{
|
||||
super(manager);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.common.ForgeChunkManager;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.config.ConfigCategory;
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
import net.minecraftforge.fml.client.IModGuiFactory;
|
||||
import net.minecraftforge.fml.client.config.ConfigGuiType;
|
||||
import net.minecraftforge.fml.client.config.DummyConfigElement;
|
||||
import net.minecraftforge.fml.client.config.DummyConfigElement.DummyCategoryElement;
|
||||
import net.minecraftforge.fml.client.config.GuiConfig;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.CategoryEntry;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.IConfigEntry;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.SelectValueEntry;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.BooleanEntry;
|
||||
import net.minecraftforge.fml.client.config.IConfigElement;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import static net.minecraftforge.common.ForgeModContainer.VERSION_CHECK_CAT;
|
||||
|
||||
import net.minecraftforge.fml.client.IModGuiFactory.RuntimeOptionCategoryElement;
|
||||
|
||||
/**
|
||||
* This is the base GuiConfig screen class that all the other Forge-specific config screens will be called from.
|
||||
* Since Forge has multiple config files I thought I would use that opportunity to show some of the ways
|
||||
* that the config GUI system can be extended to create custom config GUIs that have additional features
|
||||
* over the base functionality of just displaying Properties and ConfigCategories.
|
||||
*
|
||||
* The concepts implemented here are:
|
||||
* - using custom IConfigEntry objects to define child-screens that have specific Properties listed
|
||||
* - using custom IConfigEntry objects to define a dummy property that can be used to generate new ConfigCategory objects
|
||||
* - defining the configID string for a GuiConfig object so that the config changed events will be posted when that GuiConfig screen is closed
|
||||
* (the configID string is optional; if it is not defined the config changed events will be posted when the top-most GuiConfig screen
|
||||
* is closed, eg when the parent is null or is not an instance of GuiConfig)
|
||||
* - overriding the IConfigEntry.enabled() method to control the enabled state of one list entry based on the value of another entry
|
||||
* - overriding the IConfigEntry.onGuiClosed() method to perform custom actions when the screen that owns the entry is closed (in this
|
||||
* case a new ConfigCategory is added to the Configuration object)
|
||||
*
|
||||
* The config file structure looks like this:
|
||||
* forge.cfg (general settings all in one category)
|
||||
* forgeChunkLoading.cfg
|
||||
* - Forge (category)
|
||||
* - defaults (category)
|
||||
* - [optional mod override categories]...
|
||||
*
|
||||
* The GUI structure is this:
|
||||
* Base Screen
|
||||
* - General Settings (from forge.cfg)
|
||||
* - Chunk Loader Settings (from forgeChunkLoading.cfg)
|
||||
* - Defaults (these elements are listed directly on this screen)
|
||||
* - Mod Overrides
|
||||
* - Add New Mod Override
|
||||
* - Mod1
|
||||
* - Mod2
|
||||
* - etc.
|
||||
*
|
||||
* Other things to check out:
|
||||
* ForgeModContainer.syncConfig()
|
||||
* ForgeModContainer.onConfigChanged()
|
||||
* ForgeChunkManager.syncConfigDefaults()
|
||||
* ForgeChunkManager.loadConfiguration()
|
||||
*/
|
||||
public class ForgeGuiFactory implements IModGuiFactory
|
||||
{
|
||||
@Override
|
||||
public void initialize(Minecraft minecraftInstance) {}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasConfigGui() { return true; }
|
||||
|
||||
@Override
|
||||
public GuiScreen createConfigGui(GuiScreen parent) { return new ForgeConfigGui(parent); }
|
||||
|
||||
@Override
|
||||
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() { return null; }
|
||||
|
||||
public static class ForgeConfigGui extends GuiConfig
|
||||
{
|
||||
public ForgeConfigGui(GuiScreen parentScreen)
|
||||
{
|
||||
super(parentScreen, getConfigElements(), ForgeVersion.MOD_ID, false, false, I18n.format("forge.configgui.forgeConfigTitle"));
|
||||
}
|
||||
|
||||
private static List<IConfigElement> getConfigElements()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides the General 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 GeneralEntry extends CategoryEntry
|
||||
{
|
||||
public GeneralEntry(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_GENERAL))).getChildElements(),
|
||||
this.owningScreen.modID, Configuration.CATEGORY_GENERAL, this.configElement.requiresWorldRestart() || this.owningScreen.allRequireWorldRestart,
|
||||
this.configElement.requiresMcRestart() || this.owningScreen.allRequireMcRestart,
|
||||
GuiConfig.getAbridgedConfigPath(ForgeModContainer.getConfig().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static class ChunkLoaderEntry extends CategoryEntry
|
||||
{
|
||||
public ChunkLoaderEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
|
||||
{
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiScreen buildChildScreen()
|
||||
{
|
||||
List<IConfigElement> list = new ArrayList<IConfigElement>();
|
||||
|
||||
list.add(new DummyCategoryElement("forgeChunkLoadingModCfg", "forge.configgui.ctgy.forgeChunkLoadingModConfig",
|
||||
ModOverridesEntry.class));
|
||||
list.addAll((new ConfigElement(ForgeChunkManager.getDefaultsCategory())).getChildElements());
|
||||
|
||||
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed. The parent
|
||||
// GuiConfig object's propertyList will also be refreshed to reflect the changes.
|
||||
return new GuiConfig(this.owningScreen, list, this.owningScreen.modID, "chunkLoader",
|
||||
this.configElement.requiresWorldRestart() || this.owningScreen.allRequireWorldRestart,
|
||||
this.configElement.requiresMcRestart() || this.owningScreen.allRequireMcRestart,
|
||||
GuiConfig.getAbridgedConfigPath(ForgeChunkManager.getConfig().toString()),
|
||||
I18n.format("forge.configgui.ctgy.forgeChunkLoadingConfig"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides the Forge Version Checking 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.
|
||||
*/
|
||||
public static class VersionCheckEntry extends CategoryEntry
|
||||
{
|
||||
public VersionCheckEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
|
||||
{
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiScreen buildChildScreen()
|
||||
{
|
||||
ConfigCategory cfg = ForgeModContainer.getConfig().getCategory(VERSION_CHECK_CAT);
|
||||
Map<String, Property> values = new HashMap<String, Property>(cfg.getValues());
|
||||
values.remove("Global");
|
||||
|
||||
Property global = ForgeModContainer.getConfig().get(VERSION_CHECK_CAT, "Global", true);
|
||||
|
||||
List<Property> props = new ArrayList<Property>();
|
||||
|
||||
for (ModContainer mod : ForgeVersion.gatherMods().keySet())
|
||||
{
|
||||
values.remove(mod.getModId());
|
||||
props.add(ForgeModContainer.getConfig().get(VERSION_CHECK_CAT, mod.getModId(), true)); //Get or make the value in the config
|
||||
}
|
||||
props.addAll(values.values()); // Add any left overs from the config
|
||||
props.sort(Comparator.comparing(Property::getName));
|
||||
|
||||
List<IConfigElement> list = new ArrayList<IConfigElement>();
|
||||
list.add(new ConfigElement(global));
|
||||
for (Property prop : props)
|
||||
{
|
||||
list.add(new ConfigElement(prop));
|
||||
}
|
||||
|
||||
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed. The parent
|
||||
// GuiConfig object's propertyList will also be refreshed to reflect the changes.
|
||||
return new GuiConfig(this.owningScreen,
|
||||
list,
|
||||
this.owningScreen.modID, VERSION_CHECK_CAT, true, true,
|
||||
GuiConfig.getAbridgedConfigPath(ForgeModContainer.getConfig().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides the Mod Overrides entry on the Forge Chunk Loading config screen.
|
||||
* It extends the base Category entry class and defines the IConfigElement objects that will be used to build the child screen.
|
||||
* In this case it adds the custom entry for adding a new mod override and lists the existing mod overrides.
|
||||
*/
|
||||
public static class ModOverridesEntry extends CategoryEntry
|
||||
{
|
||||
public ModOverridesEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
|
||||
{
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called in the constructor and is used to set the childScreen field.
|
||||
*/
|
||||
@Override
|
||||
protected GuiScreen buildChildScreen()
|
||||
{
|
||||
List<IConfigElement> list = new ArrayList<IConfigElement>();
|
||||
|
||||
list.add(new DummyCategoryElement("addForgeChunkLoadingModCfg", "forge.configgui.ctgy.forgeChunkLoadingAddModConfig",
|
||||
AddModOverrideEntry.class));
|
||||
for (ConfigCategory cc : ForgeChunkManager.getModCategories())
|
||||
list.add(new ConfigElement(cc));
|
||||
|
||||
return new GuiConfig(this.owningScreen, list, this.owningScreen.modID,
|
||||
this.configElement.requiresWorldRestart() || this.owningScreen.allRequireWorldRestart,
|
||||
this.configElement.requiresMcRestart() || this.owningScreen.allRequireMcRestart, this.owningScreen.title,
|
||||
I18n.format("forge.configgui.ctgy.forgeChunkLoadingModConfig"));
|
||||
}
|
||||
|
||||
/**
|
||||
* By overriding the enabled() method and checking the value of the "enabled" entry this entry is enabled/disabled based on the value of
|
||||
* the other entry.
|
||||
*/
|
||||
@Override
|
||||
public boolean enabled()
|
||||
{
|
||||
for (IConfigEntry entry : this.owningEntryList.listEntries)
|
||||
{
|
||||
if (entry.getName().equals("enabled") && entry instanceof BooleanEntry)
|
||||
{
|
||||
return Boolean.valueOf(entry.getCurrentValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the child screen's entry list has changed.
|
||||
*/
|
||||
@Override
|
||||
public boolean isChanged()
|
||||
{
|
||||
if (childScreen instanceof GuiConfig)
|
||||
{
|
||||
GuiConfig child = (GuiConfig) childScreen;
|
||||
return child.entryList.listEntries.size() != child.initEntries.size() || child.entryList.hasChangedEntry(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since adding a new entry to the child screen is what constitutes a change here, reset the child
|
||||
* screen listEntries to the saved list.
|
||||
*/
|
||||
@Override
|
||||
public void undoChanges()
|
||||
{
|
||||
if (childScreen instanceof GuiConfig)
|
||||
{
|
||||
GuiConfig child = (GuiConfig) childScreen;
|
||||
for (IConfigEntry ice : child.entryList.listEntries)
|
||||
if (!child.initEntries.contains(ice) && ForgeChunkManager.getConfig().hasCategory(ice.getName()))
|
||||
ForgeChunkManager.getConfig().removeCategory(ForgeChunkManager.getConfig().getCategory(ice.getName()));
|
||||
|
||||
child.entryList.listEntries = new ArrayList<IConfigEntry>(child.initEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides a button that will open to a screen that will allow a user to define a new mod override.
|
||||
*/
|
||||
public static class AddModOverrideEntry extends CategoryEntry
|
||||
{
|
||||
public AddModOverrideEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
|
||||
{
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiScreen buildChildScreen()
|
||||
{
|
||||
List<IConfigElement> list = new ArrayList<IConfigElement>();
|
||||
|
||||
list.add(new DummyConfigElement("modID", "", ConfigGuiType.STRING, "forge.configgui.modID").setCustomListEntryClass(ModIDEntry.class));
|
||||
list.add(new ConfigElement(new Property("maximumTicketCount", "200", Property.Type.INTEGER, "forge.configgui.maximumTicketCount")));
|
||||
list.add(new ConfigElement(new Property("maximumChunksPerTicket", "25", Property.Type.INTEGER, "forge.configgui.maximumChunksPerTicket")));
|
||||
|
||||
return new GuiConfig(this.owningScreen, list, this.owningScreen.modID,
|
||||
this.configElement.requiresWorldRestart() || this.owningScreen.allRequireWorldRestart,
|
||||
this.configElement.requiresMcRestart() || this.owningScreen.allRequireMcRestart, this.owningScreen.title,
|
||||
I18n.format("forge.configgui.ctgy.forgeChunkLoadingAddModConfig"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom list entry provides a Mod ID selector. The control is a button that opens a list of values to select from.
|
||||
* This entry also overrides onGuiClosed() to run code to save the data to a new ConfigCategory when the user is done.
|
||||
*/
|
||||
public static class ModIDEntry extends SelectValueEntry
|
||||
{
|
||||
public ModIDEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
|
||||
{
|
||||
super(owningScreen, owningEntryList, prop, getSelectableValues());
|
||||
if (this.selectableValues.size() == 0)
|
||||
this.btnValue.enabled = false;
|
||||
}
|
||||
|
||||
private static Map<Object, String> getSelectableValues()
|
||||
{
|
||||
Map<Object, String> selectableValues = new TreeMap<Object, String>();
|
||||
|
||||
for (ModContainer mod : Loader.instance().getActiveModList())
|
||||
// only add mods to the list that have a non-immutable ModContainer
|
||||
if (!mod.isImmutable() && mod.getMod() != null)
|
||||
selectableValues.put(mod.getModId(), mod.getName());
|
||||
|
||||
return selectableValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* By overriding onGuiClosed() for this entry we can perform additional actions when the user is done such as saving
|
||||
* a new ConfigCategory object to the Configuration object.
|
||||
*/
|
||||
@Override
|
||||
public void onGuiClosed()
|
||||
{
|
||||
Object modObject = Loader.instance().getModObjectList().get(Loader.instance().getIndexedModList().get(currentValue));
|
||||
int maxTickets = 200;
|
||||
int maxChunks = 25;
|
||||
if (modObject != null)
|
||||
{
|
||||
this.owningEntryList.saveConfigElements();
|
||||
for(IConfigElement ice : this.owningScreen.configElements)
|
||||
if ("maximumTicketCount".equals(ice.getName()))
|
||||
maxTickets = Integer.valueOf(ice.get().toString());
|
||||
else if ("maximumChunksPerTicket".equals(ice.getName()))
|
||||
maxChunks = Integer.valueOf(ice.get().toString());
|
||||
|
||||
ForgeChunkManager.addConfigProperty(modObject, "maximumTicketCount", String.valueOf(maxTickets), Property.Type.INTEGER);
|
||||
ForgeChunkManager.addConfigProperty(modObject, "maximumChunksPerTicket", String.valueOf(maxChunks), Property.Type.INTEGER);
|
||||
|
||||
if (this.owningScreen.parentScreen instanceof GuiConfig)
|
||||
{
|
||||
GuiConfig superParent = (GuiConfig) this.owningScreen.parentScreen;
|
||||
ConfigCategory modCtgy = ForgeChunkManager.getConfigFor(modObject);
|
||||
modCtgy.setPropertyOrder(ForgeChunkManager.MOD_PROP_ORDER);
|
||||
ConfigElement modConfig = new ConfigElement(modCtgy);
|
||||
|
||||
boolean found = false;
|
||||
for (IConfigElement ice : superParent.configElements)
|
||||
if (ice.getName().equals(currentValue))
|
||||
found = true;
|
||||
|
||||
if (!found)
|
||||
superParent.configElements.add(modConfig);
|
||||
|
||||
superParent.needsRefresh = true;
|
||||
superParent.initGui();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.ForgeVersion.Status;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class NotificationModUpdateScreen extends GuiScreen
|
||||
{
|
||||
|
||||
private static final ResourceLocation VERSION_CHECK_ICONS = new ResourceLocation(ForgeVersion.MOD_ID, "textures/gui/version_check_icons.png");
|
||||
|
||||
private final GuiButton modButton;
|
||||
private Status showNotification = null;
|
||||
private boolean hasCheckedForUpdates = false;
|
||||
|
||||
public NotificationModUpdateScreen(GuiButton modButton)
|
||||
{
|
||||
this.modButton = modButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the buttons (and other controls) to the screen in question. Called when the GUI is displayed and when the
|
||||
* window resizes, the buttonList is cleared beforehand.
|
||||
*/
|
||||
@Override
|
||||
public void initGui()
|
||||
{
|
||||
if (!hasCheckedForUpdates)
|
||||
{
|
||||
if (modButton != null)
|
||||
{
|
||||
for (ModContainer mod : Loader.instance().getModList())
|
||||
{
|
||||
Status status = ForgeVersion.getResult(mod).status;
|
||||
if (status == Status.OUTDATED || status == Status.BETA_OUTDATED)
|
||||
{
|
||||
// TODO: Needs better visualization, maybe stacked icons
|
||||
// drawn in a terrace-like pattern?
|
||||
showNotification = Status.OUTDATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
hasCheckedForUpdates = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it.
|
||||
*/
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks)
|
||||
{
|
||||
if (showNotification == null || !showNotification.shouldDraw() || ForgeModContainer.disableVersionCheck)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(VERSION_CHECK_ICONS);
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
int x = modButton.x;
|
||||
int y = modButton.y;
|
||||
int w = modButton.width;
|
||||
int h = modButton.height;
|
||||
|
||||
drawModalRectWithCustomSizedTexture(x + w - (h / 2 + 4), y + (h / 2 - 4), showNotification.getSheetOffset() * 8, (showNotification.isAnimated() && ((System.currentTimeMillis() / 800 & 1) == 1)) ? 8 : 0, 8, 8, 64, 16);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
public static NotificationModUpdateScreen init(GuiMainMenu guiMainMenu, GuiButton modButton)
|
||||
{
|
||||
NotificationModUpdateScreen notificationModUpdateScreen = new NotificationModUpdateScreen(modButton);
|
||||
notificationModUpdateScreen.setGuiSize(guiMainMenu.width, guiMainMenu.height);
|
||||
notificationModUpdateScreen.initGui();
|
||||
return notificationModUpdateScreen;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumType;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
|
||||
|
||||
public class Attributes
|
||||
{
|
||||
/*
|
||||
* Default format of the data in IBakedModel
|
||||
*/
|
||||
public static final VertexFormat DEFAULT_BAKED_FORMAT;
|
||||
|
||||
static
|
||||
{
|
||||
DEFAULT_BAKED_FORMAT = new VertexFormat();
|
||||
DEFAULT_BAKED_FORMAT.addElement(new VertexFormatElement(0, EnumType.FLOAT, EnumUsage.POSITION, 3));
|
||||
DEFAULT_BAKED_FORMAT.addElement(new VertexFormatElement(0, EnumType.UBYTE, EnumUsage.COLOR, 4));
|
||||
DEFAULT_BAKED_FORMAT.addElement(new VertexFormatElement(0, EnumType.FLOAT, EnumUsage.UV, 2));
|
||||
DEFAULT_BAKED_FORMAT.addElement(new VertexFormatElement(0, EnumType.BYTE, EnumUsage.PADDING, 4));
|
||||
}
|
||||
|
||||
/*
|
||||
* Can first format be used where second is expected
|
||||
*/
|
||||
public static boolean moreSpecific(VertexFormat first, VertexFormat second)
|
||||
{
|
||||
int size = first.getNextOffset();
|
||||
if(size != second.getNextOffset()) return false;
|
||||
|
||||
int padding = 0;
|
||||
int j = 0;
|
||||
for(VertexFormatElement firstAttr : first.getElements())
|
||||
{
|
||||
while(j < second.getElementCount() && second.getElement(j).getUsage() == EnumUsage.PADDING)
|
||||
{
|
||||
padding += second.getElement(j++).getSize();
|
||||
}
|
||||
if(j >= second.getElementCount() && padding == 0)
|
||||
{
|
||||
// if no padding is left, but there are still elements in first (we're processing one) - it doesn't fit
|
||||
return false;
|
||||
}
|
||||
if(padding == 0)
|
||||
{
|
||||
// no padding - attributes have to match
|
||||
VertexFormatElement secondAttr = second.getElement(j++);
|
||||
if(
|
||||
firstAttr.getIndex() != secondAttr.getIndex() ||
|
||||
firstAttr.getElementCount() != secondAttr.getElementCount() ||
|
||||
firstAttr.getType() != secondAttr.getType() ||
|
||||
firstAttr.getUsage() != secondAttr.getUsage())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// padding - attribute should fit in it
|
||||
padding -= firstAttr.getSize();
|
||||
if(padding < 0) return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(padding != 0 || j != second.getElementCount()) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
public class BakedItemModel implements IBakedModel
|
||||
{
|
||||
protected final ImmutableList<BakedQuad> quads;
|
||||
protected final TextureAtlasSprite particle;
|
||||
protected final ImmutableMap<TransformType, TRSRTransformation> transforms;
|
||||
protected final ItemOverrideList overrides;
|
||||
protected final IBakedModel guiModel;
|
||||
|
||||
public BakedItemModel(ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, ImmutableMap<TransformType, TRSRTransformation> transforms, ItemOverrideList overrides)
|
||||
{
|
||||
this.quads = quads;
|
||||
this.particle = particle;
|
||||
this.transforms = transforms;
|
||||
this.overrides = overrides;
|
||||
this.guiModel = hasGuiIdentity(transforms) ? new BakedGuiItemModel<>(this) : null;
|
||||
}
|
||||
|
||||
private static boolean hasGuiIdentity(ImmutableMap<TransformType, TRSRTransformation> transforms)
|
||||
{
|
||||
TRSRTransformation guiTransform = transforms.get(TransformType.GUI);
|
||||
return guiTransform == null || guiTransform.isIdentity();
|
||||
}
|
||||
|
||||
@Override public boolean isAmbientOcclusion() { return true; }
|
||||
@Override public boolean isGui3d() { return false; }
|
||||
@Override public boolean isBuiltInRenderer() { return false; }
|
||||
@Override public TextureAtlasSprite getParticleTexture() { return particle; }
|
||||
@Override public ItemOverrideList getOverrides() { return overrides; }
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
if (side == null)
|
||||
{
|
||||
return quads;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType type)
|
||||
{
|
||||
if (type == TransformType.GUI && this.guiModel != null)
|
||||
{
|
||||
return this.guiModel.handlePerspective(type);
|
||||
}
|
||||
return PerspectiveMapWrapper.handlePerspective(this, transforms, type);
|
||||
}
|
||||
|
||||
public static class BakedGuiItemModel<T extends BakedItemModel> extends BakedModelWrapper<T>
|
||||
{
|
||||
private final ImmutableList<BakedQuad> quads;
|
||||
|
||||
public BakedGuiItemModel(T originalModel)
|
||||
{
|
||||
super(originalModel);
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
for (BakedQuad quad : originalModel.quads)
|
||||
{
|
||||
if (quad.getFace() == EnumFacing.SOUTH)
|
||||
{
|
||||
builder.add(quad);
|
||||
}
|
||||
}
|
||||
this.quads = builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
if(side == null)
|
||||
{
|
||||
return quads;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType type)
|
||||
{
|
||||
if (type == TransformType.GUI)
|
||||
{
|
||||
return PerspectiveMapWrapper.handlePerspective(this, originalModel.transforms, type);
|
||||
}
|
||||
return this.originalModel.handlePerspective(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
public abstract class BakedModelWrapper<T extends IBakedModel> implements IBakedModel
|
||||
{
|
||||
protected final T originalModel;
|
||||
|
||||
public BakedModelWrapper(T originalModel)
|
||||
{
|
||||
this.originalModel = originalModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
return originalModel.getQuads(state, side, rand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return originalModel.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion(IBlockState state)
|
||||
{
|
||||
return originalModel.isAmbientOcclusion(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return originalModel.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return originalModel.isBuiltInRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return originalModel.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCameraTransforms getItemCameraTransforms()
|
||||
{
|
||||
return originalModel.getItemCameraTransforms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return originalModel.getOverrides();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType)
|
||||
{
|
||||
return originalModel.handlePerspective(cameraTransformType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.ModelBlockDefinition;
|
||||
import net.minecraft.client.renderer.block.model.ModelRotation;
|
||||
import net.minecraft.client.renderer.block.model.Variant;
|
||||
import net.minecraft.client.renderer.block.model.VariantList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BlockStateLoader
|
||||
{
|
||||
private static final Gson GSON = (new GsonBuilder())
|
||||
.registerTypeAdapter(ForgeBlockStateV1.class, ForgeBlockStateV1.Deserializer.INSTANCE)
|
||||
.registerTypeAdapter(ForgeBlockStateV1.Variant.class, ForgeBlockStateV1.Variant.Deserializer.INSTANCE)
|
||||
.registerTypeAdapter(TRSRTransformation.class, ForgeBlockStateV1.TRSRDeserializer.INSTANCE)
|
||||
.create();
|
||||
/**
|
||||
* Loads a BlockStates json file.
|
||||
* Will attempt to parse it as a Forge Enhanced version if possible.
|
||||
* Will fall back to standard loading if marker is not present.
|
||||
*
|
||||
* Note: This method is NOT thread safe
|
||||
*
|
||||
* @param reader json read
|
||||
* @param location blockstate location
|
||||
* @param vanillaGSON ModelBlockDefinition's GSON reader.
|
||||
*
|
||||
* @return Model definition including variants for all known combinations.
|
||||
*/
|
||||
public static ModelBlockDefinition load(Reader reader, ResourceLocation location, final Gson vanillaGSON)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] data = IOUtils.toByteArray(reader, StandardCharsets.UTF_8);
|
||||
reader = new InputStreamReader(new ByteArrayInputStream(data), StandardCharsets.UTF_8);
|
||||
|
||||
Marker marker = GSON.fromJson(new String(data, StandardCharsets.UTF_8), Marker.class); // Read "forge_marker" to determine what to load.
|
||||
|
||||
switch (marker.forge_marker)
|
||||
{
|
||||
case 1: // Version 1
|
||||
ForgeBlockStateV1 v1 = GSON.fromJson(reader, ForgeBlockStateV1.class);
|
||||
Map<String, VariantList> variants = Maps.newLinkedHashMap();
|
||||
|
||||
for (Entry<String, Collection<ForgeBlockStateV1.Variant>> entry : v1.variants.asMap().entrySet())
|
||||
{ // Convert Version1 variants into vanilla variants for the ModelBlockDefinition.
|
||||
List<Variant> mcVars = Lists.newArrayList();
|
||||
for (ForgeBlockStateV1.Variant var : entry.getValue())
|
||||
{
|
||||
boolean uvLock = var.getUvLock().orElse(false);
|
||||
boolean smooth = var.getSmooth().orElse(true);
|
||||
boolean gui3d = var.getGui3d().orElse(true);
|
||||
int weight = var.getWeight().orElse(1);
|
||||
|
||||
if (var.getModel() != null && var.getSubmodels().size() == 0 && var.getTextures().size() == 0 && var.getCustomData().size() == 0 && var.getState().orElse(ModelRotation.X0_Y0) instanceof ModelRotation)
|
||||
mcVars.add(new Variant(var.getModel(), (ModelRotation)var.getState().orElse(ModelRotation.X0_Y0), uvLock, weight));
|
||||
else
|
||||
mcVars.add(new ForgeVariant(location, var.getModel(), var.getState().orElse(TRSRTransformation.identity()), uvLock, smooth, gui3d, weight, var.getTextures(), var.getOnlyPartsVariant(), var.getCustomData()));
|
||||
}
|
||||
variants.put(entry.getKey(), new VariantList(mcVars));
|
||||
}
|
||||
|
||||
return new ModelBlockDefinition(variants, null);
|
||||
|
||||
default: //Unknown version.. try loading it as normal.
|
||||
return vanillaGSON.fromJson(reader, ModelBlockDefinition.class);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Marker
|
||||
{
|
||||
public int forge_marker = -1;
|
||||
}
|
||||
|
||||
//This is here specifically so that we do not have a hard reference to ForgeBlockStateV1.Variant in ForgeVariant
|
||||
public static class SubModel
|
||||
{
|
||||
private final IModelState state;
|
||||
private final boolean uvLock;
|
||||
private final boolean smooth;
|
||||
private final boolean gui3d;
|
||||
private final ImmutableMap<String, String> textures;
|
||||
@Nullable
|
||||
private final ResourceLocation model;
|
||||
private final ImmutableMap<String, String> customData;
|
||||
|
||||
public SubModel(IModelState state, boolean uvLock, boolean smooth, boolean gui3d, ImmutableMap<String, String> textures, @Nullable ResourceLocation model, ImmutableMap<String, String> customData)
|
||||
{
|
||||
this.state = state;
|
||||
this.uvLock = uvLock;
|
||||
this.smooth = smooth;
|
||||
this.gui3d = gui3d;
|
||||
this.textures = textures;
|
||||
this.model = model;
|
||||
this.customData = customData;
|
||||
}
|
||||
|
||||
public IModelState getState() { return state; }
|
||||
public boolean isUVLock() { return uvLock; }
|
||||
public ImmutableMap<String, String> getTextures() { return textures; }
|
||||
@Nullable
|
||||
public ResourceLocation getModelLocation() { return model; }
|
||||
public ImmutableMap<String, String> getCustomData() { return customData; }
|
||||
}
|
||||
|
||||
private static class ForgeVariant extends Variant implements ISmartVariant
|
||||
{
|
||||
private final ResourceLocation blockstateLocation;
|
||||
private final ImmutableMap<String, String> textures;
|
||||
private final ImmutableMap<String, SubModel> parts;
|
||||
private final ImmutableMap<String, String> customData;
|
||||
private final boolean smooth;
|
||||
private final boolean gui3d;
|
||||
private final IModelState state;
|
||||
|
||||
public ForgeVariant(ResourceLocation blockstateLocation, @Nullable ResourceLocation model, IModelState state, boolean uvLock, boolean smooth, boolean gui3d, int weight, ImmutableMap<String, String> textures, ImmutableMap<String, SubModel> parts, ImmutableMap<String, String> customData)
|
||||
{
|
||||
super(model == null ? new ResourceLocation("builtin/missing") : model, state instanceof ModelRotation ? (ModelRotation)state : ModelRotation.X0_Y0, uvLock, weight);
|
||||
this.blockstateLocation = blockstateLocation;
|
||||
this.textures = textures;
|
||||
this.parts = parts;
|
||||
this.customData = customData;
|
||||
this.state = state;
|
||||
this.smooth = smooth;
|
||||
this.gui3d = gui3d;
|
||||
}
|
||||
|
||||
private IModel runModelHooks(IModel base, boolean smooth, boolean gui3d, boolean uvlock, ImmutableMap<String, String> textureMap, ImmutableMap<String, String> customData)
|
||||
{
|
||||
base = base.process(customData);
|
||||
base = base.retexture(textureMap);
|
||||
base = base.smoothLighting(smooth);
|
||||
base = base.gui3d(gui3d);
|
||||
base = base.uvlock(uvlock);
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to replace the base model with a re-textured model containing sub-models.
|
||||
*/
|
||||
@Override
|
||||
public IModel process(IModel base)
|
||||
{
|
||||
int size = parts.size();
|
||||
// FIXME: should missing base be handled this way?
|
||||
boolean hasBase = base != ModelLoaderRegistry.getMissingModel();
|
||||
|
||||
if (hasBase)
|
||||
{
|
||||
base = runModelHooks(base, smooth, gui3d, this.isUvLock(), textures, customData);
|
||||
|
||||
if (size <= 0)
|
||||
return base;
|
||||
}
|
||||
|
||||
ImmutableMap.Builder<String, Pair<IModel, IModelState>> models = ImmutableMap.builder();
|
||||
for (Entry<String, SubModel> entry : parts.entrySet())
|
||||
{
|
||||
SubModel part = entry.getValue();
|
||||
|
||||
final ResourceLocation modelLocation = part.getModelLocation();
|
||||
final IModel model;
|
||||
if (modelLocation == null)
|
||||
{
|
||||
FMLLog.log.error("model not found for variant {} for blockstate {}", entry.getKey(), blockstateLocation);
|
||||
model = ModelLoaderRegistry.getMissingModel(blockstateLocation, new Throwable());
|
||||
}
|
||||
else
|
||||
{
|
||||
model = ModelLoaderRegistry.getModelOrLogError(modelLocation, "Unable to load block sub-model: \'" + modelLocation);
|
||||
}
|
||||
|
||||
models.put(entry.getKey(), Pair.of(runModelHooks(model, part.smooth, part.gui3d, part.uvLock, part.getTextures(), part.getCustomData()), part.getState()));
|
||||
}
|
||||
|
||||
return new MultiModel(getModelLocation(), hasBase ? base : null, models.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelState getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("TexturedVariant:");
|
||||
for (Entry<String, String> e: this.textures.entrySet())
|
||||
buf.append(" ").append(e.getKey()).append(" = ").append(e.getValue());
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.Optional;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Quat4f;
|
||||
import javax.vecmath.Vector3f;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
final class FancyMissingModel implements IModel
|
||||
{
|
||||
private static final ResourceLocation font = new ResourceLocation("minecraft", "textures/font/ascii.png");
|
||||
private static final ResourceLocation font2 = new ResourceLocation("minecraft", "font/ascii");
|
||||
private static final TRSRTransformation smallTransformation = TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, null, new Vector3f(.25f, .25f, .25f), null));
|
||||
private static final LoadingCache<VertexFormat, SimpleModelFontRenderer> fontCache = CacheBuilder.newBuilder().maximumSize(3).build(new CacheLoader<VertexFormat, SimpleModelFontRenderer>()
|
||||
{
|
||||
@Override
|
||||
public SimpleModelFontRenderer load(VertexFormat format) throws Exception
|
||||
{
|
||||
Matrix4f m = new Matrix4f();
|
||||
m.m20 = 1f / 128f;
|
||||
m.m01 = m.m12 = -m.m20;
|
||||
m.m33 = 1;
|
||||
m.setTranslation(new Vector3f(1, 1 + 1f / 0x100, 0));
|
||||
return new SimpleModelFontRenderer(
|
||||
Minecraft.getMinecraft().gameSettings,
|
||||
font,
|
||||
Minecraft.getMinecraft().getTextureManager(),
|
||||
false,
|
||||
m,
|
||||
format
|
||||
) {
|
||||
/**
|
||||
* Render a single Unicode character at current (posX,posY) location using one of the /font/glyph_XX.png
|
||||
* files...
|
||||
*/
|
||||
@Override
|
||||
protected float renderUnicodeChar(char c, boolean italic)
|
||||
{
|
||||
return super.renderDefaultChar(126, italic);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
private final IModel missingModel;
|
||||
private final String message;
|
||||
|
||||
public FancyMissingModel(IModel missingModel, String message)
|
||||
{
|
||||
this.missingModel = missingModel;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
return ImmutableList.of(font2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
IBakedModel bigMissing = missingModel.bake(state, format, bakedTextureGetter);
|
||||
IModelState smallState = new ModelStateComposition(state, smallTransformation);
|
||||
IBakedModel smallMissing = missingModel.bake(smallState, format, bakedTextureGetter);
|
||||
return new BakedModel(bigMissing, smallMissing, fontCache.getUnchecked(format), message, bakedTextureGetter.apply(font2));
|
||||
}
|
||||
|
||||
static final class BakedModel implements IBakedModel
|
||||
{
|
||||
private final SimpleModelFontRenderer fontRenderer;
|
||||
private final String message;
|
||||
private final TextureAtlasSprite fontTexture;
|
||||
private final IBakedModel missingModel;
|
||||
private final IBakedModel otherModel;
|
||||
private final boolean big;
|
||||
private ImmutableList<BakedQuad> quads;
|
||||
|
||||
public BakedModel(IBakedModel bigMissing, IBakedModel smallMissing, SimpleModelFontRenderer fontRenderer, String message, TextureAtlasSprite fontTexture)
|
||||
{
|
||||
this.missingModel = bigMissing;
|
||||
otherModel = new BakedModel(smallMissing, fontRenderer, message, fontTexture, this);
|
||||
this.big = true;
|
||||
this.fontRenderer = fontRenderer;
|
||||
this.message = message;
|
||||
this.fontTexture = fontTexture;
|
||||
}
|
||||
|
||||
public BakedModel(IBakedModel smallMissing, SimpleModelFontRenderer fontRenderer, String message, TextureAtlasSprite fontTexture, BakedModel big)
|
||||
{
|
||||
this.missingModel = smallMissing;
|
||||
otherModel = big;
|
||||
this.big = false;
|
||||
this.fontRenderer = fontRenderer;
|
||||
this.message = message;
|
||||
this.fontTexture = fontTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
if (side == null)
|
||||
{
|
||||
if (quads == null)
|
||||
{
|
||||
fontRenderer.setSprite(fontTexture);
|
||||
fontRenderer.setFillBlanks(true);
|
||||
String[] lines = message.split("\\r?\\n");
|
||||
List<String> splitLines = Lists.newArrayList();
|
||||
for (int y = 0; y < lines.length; y++)
|
||||
{
|
||||
splitLines.addAll(fontRenderer.listFormattedStringToWidth(lines[y], 0x80));
|
||||
}
|
||||
for (int y = 0; y < splitLines.size(); y++)
|
||||
{
|
||||
fontRenderer.drawString(splitLines.get(y), 0, (int)((y - splitLines.size() / 2f) * fontRenderer.FONT_HEIGHT) + 0x40, 0xFF00FFFF);
|
||||
}
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
builder.addAll(missingModel.getQuads(state, side, rand));
|
||||
builder.addAll(fontRenderer.build());
|
||||
quads = builder.build();
|
||||
}
|
||||
return quads;
|
||||
}
|
||||
return missingModel.getQuads(state, side, rand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion() { return true; }
|
||||
|
||||
@Override
|
||||
public boolean isGui3d() { return false; }
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer() { return false; }
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture() { return fontTexture; }
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides() { return ItemOverrideList.NONE; }
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType)
|
||||
{
|
||||
TRSRTransformation transform = TRSRTransformation.identity();
|
||||
boolean big = true;
|
||||
switch (cameraTransformType)
|
||||
{
|
||||
|
||||
case THIRD_PERSON_LEFT_HAND:
|
||||
break;
|
||||
case THIRD_PERSON_RIGHT_HAND:
|
||||
break;
|
||||
case FIRST_PERSON_LEFT_HAND:
|
||||
transform = new TRSRTransformation(new Vector3f(-0.62f, 0.5f, -.5f), new Quat4f(1, -1, -1, 1), null, null);
|
||||
big = false;
|
||||
break;
|
||||
case FIRST_PERSON_RIGHT_HAND:
|
||||
transform = new TRSRTransformation(new Vector3f(-0.5f, 0.5f, -.5f), new Quat4f(1, 1, 1, 1), null, null);
|
||||
big = false;
|
||||
break;
|
||||
case HEAD:
|
||||
break;
|
||||
case GUI:
|
||||
if (ForgeModContainer.zoomInMissingModelTextInGui)
|
||||
{
|
||||
transform = new TRSRTransformation(null, new Quat4f(1, 1, 1, 1), new Vector3f(4, 4, 4), null);
|
||||
big = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform = new TRSRTransformation(null, new Quat4f(1, 1, 1, 1), null, null);
|
||||
big = true;
|
||||
}
|
||||
break;
|
||||
case FIXED:
|
||||
transform = new TRSRTransformation(null, new Quat4f(-1, -1, 1, 1), null, null);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (big != this.big)
|
||||
{
|
||||
return Pair.of(otherModel, transform.getMatrix());
|
||||
}
|
||||
return Pair.of(this, transform.getMatrix());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,965 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.AxisAngle4d;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Quat4f;
|
||||
import javax.vecmath.Vector3f;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ModelRotation;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.BlockStateLoader.Marker;
|
||||
import net.minecraftforge.client.model.BlockStateLoader.SubModel;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
public class ForgeBlockStateV1 extends Marker
|
||||
{
|
||||
ForgeBlockStateV1.Variant defaults;
|
||||
Multimap<String, ForgeBlockStateV1.Variant> variants = LinkedHashMultimap.create();
|
||||
|
||||
public static class Deserializer implements JsonDeserializer<ForgeBlockStateV1>
|
||||
{
|
||||
static ForgeBlockStateV1.Deserializer INSTANCE = new Deserializer();
|
||||
@Override
|
||||
public ForgeBlockStateV1 deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
JsonObject json = element.getAsJsonObject();
|
||||
ForgeBlockStateV1 ret = new ForgeBlockStateV1();
|
||||
ret.forge_marker = JsonUtils.getInt(json, "forge_marker");
|
||||
|
||||
if (json.has("defaults")) // Load defaults Variant.
|
||||
{
|
||||
ret.defaults = context.deserialize(json.get("defaults"), ForgeBlockStateV1.Variant.class);
|
||||
|
||||
if (ret.defaults.simpleSubmodels.size() > 0)
|
||||
throw new RuntimeException("\"defaults\" variant cannot contain a simple \"submodel\" definition.");
|
||||
}
|
||||
|
||||
Map<String, Map<String, ForgeBlockStateV1.Variant>> condensed = Maps.newLinkedHashMap(); // map(property name -> map(property value -> variant))
|
||||
Multimap<String, ForgeBlockStateV1.Variant> specified = LinkedHashMultimap.create(); // Multimap containing all the states specified with "property=value".
|
||||
|
||||
for (Entry<String, JsonElement> e : JsonUtils.getJsonObject(json, "variants").entrySet())
|
||||
{
|
||||
if (e.getValue().isJsonArray())
|
||||
{
|
||||
// array of fully-defined variants
|
||||
for (JsonElement a : e.getValue().getAsJsonArray())
|
||||
{
|
||||
Variant.Deserializer.INSTANCE.simpleSubmodelKey = e.getKey();
|
||||
specified.put(e.getKey(), context.deserialize(a, Variant.class));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonObject obj = e.getValue().getAsJsonObject();
|
||||
if(obj.entrySet().iterator().next().getValue().isJsonObject())
|
||||
{
|
||||
// first value is a json object, so we know it's not a fully-defined variant
|
||||
Map<String, ForgeBlockStateV1.Variant> subs = Maps.newLinkedHashMap();
|
||||
condensed.put(e.getKey(), subs);
|
||||
for (Entry<String, JsonElement> se : e.getValue().getAsJsonObject().entrySet())
|
||||
{
|
||||
Variant.Deserializer.INSTANCE.simpleSubmodelKey = e.getKey() + "=" + se.getKey();
|
||||
subs.put(se.getKey(), context.deserialize(se.getValue(), Variant.class));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fully-defined variant
|
||||
Variant.Deserializer.INSTANCE.simpleSubmodelKey = e.getKey();
|
||||
specified.put(e.getKey(), context.deserialize(e.getValue(), Variant.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Multimap<String, ForgeBlockStateV1.Variant> permutations = getPermutations(condensed); // Get permutations of Forge-style states.
|
||||
|
||||
for (Entry<String, Collection<ForgeBlockStateV1.Variant>> e : specified.asMap().entrySet())
|
||||
{ // Make fully-specified variants override Forge variant permutations, inheriting the permutations' values.
|
||||
Collection<ForgeBlockStateV1.Variant> baseVars = permutations.get(e.getKey());
|
||||
List<ForgeBlockStateV1.Variant> addVars = Lists.newArrayList();
|
||||
|
||||
for (ForgeBlockStateV1.Variant specVar : e.getValue())
|
||||
{
|
||||
if (!baseVars.isEmpty())
|
||||
{
|
||||
for (ForgeBlockStateV1.Variant baseVar : baseVars)
|
||||
addVars.add(new Variant(specVar).sync(baseVar));
|
||||
}
|
||||
else
|
||||
addVars.add(specVar);
|
||||
}
|
||||
|
||||
baseVars.clear();
|
||||
baseVars.addAll(addVars);
|
||||
}
|
||||
|
||||
for (Entry<String, ForgeBlockStateV1.Variant> e : permutations.entries()) // Create the output map(state -> Variant).
|
||||
{
|
||||
ForgeBlockStateV1.Variant v = e.getValue();
|
||||
|
||||
if (ret.defaults != null)
|
||||
{
|
||||
v.sync(ret.defaults); // Sync defaults into all permutation variants
|
||||
|
||||
for (Entry<String, Object> partKey : v.simpleSubmodels.entrySet())
|
||||
{ // Sync variant values (including defaults) into simple submodel declarations.
|
||||
if (partKey.getValue() == null)
|
||||
continue;
|
||||
|
||||
if (!v.submodels.containsKey(partKey.getKey()))
|
||||
throw new RuntimeException("This should never happen! Simple submodel is not contained in the submodel map!");
|
||||
List<ForgeBlockStateV1.Variant> partList = v.submodels.get(partKey.getKey());
|
||||
if (partList.size() > 1)
|
||||
throw new RuntimeException("This should never happen! Simple submodel has multiple variants!");
|
||||
|
||||
ForgeBlockStateV1.Variant part = partList.get(0);
|
||||
// Must keep old rotation for the part, because the base variant's rotation is applied to the parts already.
|
||||
Optional<IModelState> state = part.state;
|
||||
part.sync(v);
|
||||
part.simpleSubmodels.clear();
|
||||
part.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
v.submodels.values().removeIf(Objects::isNull);
|
||||
|
||||
if (v.textures != null)
|
||||
{
|
||||
for (Entry<String, String> tex : v.textures.entrySet())
|
||||
{
|
||||
if (tex.getValue() != null && tex.getValue().charAt(0) == '#')
|
||||
{
|
||||
String value = v.textures.get(tex.getValue().substring(1));
|
||||
if (value == null)
|
||||
{
|
||||
FMLLog.log.fatal("Could not resolve texture name \"{}\" for permutation \"{}\"", tex.getValue(), e.getKey());
|
||||
for (Entry<String, String> t: v.textures.entrySet())
|
||||
FMLLog.log.fatal("{}={}", t.getKey(), t.getValue());
|
||||
throw new JsonParseException("Could not resolve texture name \"" + tex.getValue() + "\" for permutation \"" + e.getKey() + "\"");
|
||||
}
|
||||
v.textures.put(tex.getKey(), value);
|
||||
}
|
||||
}
|
||||
|
||||
for (List<ForgeBlockStateV1.Variant> part : v.submodels.values()) // Sync base variant's textures (including defaults) into all submodels.
|
||||
{
|
||||
for (ForgeBlockStateV1.Variant partVar : part)
|
||||
{
|
||||
for (Entry<String, String> texEntry : v.textures.entrySet())
|
||||
{
|
||||
if (!partVar.textures.containsKey(texEntry.getKey()))
|
||||
partVar.textures.put(texEntry.getKey(), texEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!v.submodels.isEmpty())
|
||||
ret.variants.putAll(e.getKey(), getSubmodelPermutations(v, v.submodels)); // Do permutations of submodel variants.
|
||||
else
|
||||
ret.variants.put(e.getKey(), v);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private Multimap<String, ForgeBlockStateV1.Variant> getPermutations(List<String> sorted, Map<String, Map<String, ForgeBlockStateV1.Variant>> base, int depth, String prefix, Multimap<String, ForgeBlockStateV1.Variant> ret, @Nullable ForgeBlockStateV1.Variant parent)
|
||||
{
|
||||
if (depth == sorted.size())
|
||||
{
|
||||
if(parent != null)
|
||||
ret.put(prefix, parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
String name = sorted.get(depth);
|
||||
for (Entry<String, ForgeBlockStateV1.Variant> e : base.get(name).entrySet())
|
||||
{
|
||||
ForgeBlockStateV1.Variant newHead = parent == null ? new Variant(e.getValue()) : new Variant(parent).sync(e.getValue());
|
||||
|
||||
getPermutations(sorted, base, depth + 1, prefix + (depth == 0 ? "" : ",") + name + "=" + e.getKey(), ret, newHead);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private Multimap<String, ForgeBlockStateV1.Variant> getPermutations(Map<String, Map<String, ForgeBlockStateV1.Variant>> base)
|
||||
{
|
||||
List<String> sorted = Lists.newArrayList(base.keySet());
|
||||
Collections.sort(sorted); // Sort to get consistent results.
|
||||
return getPermutations(sorted, base, 0, "", LinkedHashMultimap.create(), null);
|
||||
}
|
||||
|
||||
private List<ForgeBlockStateV1.Variant> getSubmodelPermutations(ForgeBlockStateV1.Variant baseVar, List<String> sorted, Map<String, List<ForgeBlockStateV1.Variant>> map, int depth, Map<String, ForgeBlockStateV1.Variant> parts, List<ForgeBlockStateV1.Variant> ret)
|
||||
{
|
||||
if (depth >= sorted.size())
|
||||
{
|
||||
ForgeBlockStateV1.Variant add = new Variant(baseVar); // Create a duplicate variant object so modifying it doesn't modify baseVar.
|
||||
for (Entry<String, ForgeBlockStateV1.Variant> part : parts.entrySet()) // Put all the parts with single variants for this permutation.
|
||||
add.submodels.put(part.getKey(), Collections.singletonList(part.getValue()));
|
||||
ret.add(add);
|
||||
return ret;
|
||||
}
|
||||
|
||||
String name = sorted.get(depth);
|
||||
List<ForgeBlockStateV1.Variant> vars = map.get(sorted.get(depth));
|
||||
|
||||
if (vars != null)
|
||||
{
|
||||
for (ForgeBlockStateV1.Variant v : vars)
|
||||
{
|
||||
if (v != null)
|
||||
{ // We put this part variant in the permutation's map to add further in recursion, and then remove it afterward just in case.
|
||||
parts.put(name, v);
|
||||
getSubmodelPermutations(baseVar, sorted, map, depth + 1, parts, ret);
|
||||
parts.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
getSubmodelPermutations(baseVar, sorted, map, depth + 1, parts, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<ForgeBlockStateV1.Variant> getSubmodelPermutations(ForgeBlockStateV1.Variant baseVar, Map<String, List<ForgeBlockStateV1.Variant>> variants)
|
||||
{
|
||||
List<String> sorted = Lists.newArrayList(variants.keySet());
|
||||
Collections.sort(sorted); // Sort to get consistent results.
|
||||
return getSubmodelPermutations(baseVar, sorted, variants, 0, new LinkedHashMap<>(), new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Variant
|
||||
{
|
||||
public static final Object SET_VALUE = new Object();
|
||||
|
||||
@Nullable
|
||||
private ResourceLocation model = null;
|
||||
private boolean modelSet = false;
|
||||
private Optional<IModelState> state = Optional.empty();
|
||||
private Optional<Boolean> uvLock = Optional.empty();
|
||||
private Optional<Boolean> smooth = Optional.empty();
|
||||
private Optional<Boolean> gui3d = Optional.empty();
|
||||
private Optional<Integer> weight = Optional.empty();
|
||||
private Map<String, String> textures = Maps.newHashMap();
|
||||
private Map<String, List<ForgeBlockStateV1.Variant>> submodels = Maps.newHashMap();
|
||||
private Map<String, Object> simpleSubmodels = Maps.newHashMap(); // Makeshift Set to allow us to "remove" (replace value with null) singleParts when needed.
|
||||
private Map<String, String> customData = Maps.newHashMap();
|
||||
|
||||
private Variant(){}
|
||||
/**
|
||||
* Clone a variant.
|
||||
* @param other Variant to clone.
|
||||
*/
|
||||
private Variant(ForgeBlockStateV1.Variant other)
|
||||
{
|
||||
this.model = other.model;
|
||||
this.modelSet = other.modelSet;
|
||||
this.state = other.state;
|
||||
this.uvLock = other.uvLock;
|
||||
this.smooth = other.smooth;
|
||||
this.gui3d = other.gui3d;
|
||||
this.weight = other.weight;
|
||||
this.textures.putAll(other.textures);
|
||||
this.mergeModelPartVariants(this.submodels, other.submodels);
|
||||
this.simpleSubmodels.putAll(other.simpleSubmodels);
|
||||
this.customData.putAll(other.customData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets values in this variant to the input's values only if they haven't been set already. Essentially inherits values from o.
|
||||
*/
|
||||
ForgeBlockStateV1.Variant sync(ForgeBlockStateV1.Variant parent)
|
||||
{
|
||||
if (!this.modelSet)
|
||||
{
|
||||
this.model = parent.model;
|
||||
this.modelSet = parent.modelSet;
|
||||
}
|
||||
if (!this.state.isPresent()) this.state = parent.state;
|
||||
if (!this.uvLock.isPresent()) this.uvLock = parent.uvLock;
|
||||
if (!this.smooth.isPresent()) this.smooth = parent.smooth;
|
||||
if (!this.gui3d.isPresent()) this.gui3d = parent.gui3d;
|
||||
if (!this.weight.isPresent()) this.weight = parent.weight;
|
||||
|
||||
for (Entry<String, String> e : parent.textures.entrySet())
|
||||
{
|
||||
if (!this.textures.containsKey(e.getKey()))
|
||||
this.textures.put(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
mergeModelPartVariants(this.submodels, parent.submodels);
|
||||
|
||||
for (Entry<String, Object> e : parent.simpleSubmodels.entrySet())
|
||||
{
|
||||
if (!this.simpleSubmodels.containsKey(e.getKey()))
|
||||
this.simpleSubmodels.put(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
for (Entry<String, String> e : parent.customData.entrySet())
|
||||
{
|
||||
if (!this.customData.containsKey(e.getKey()))
|
||||
this.customData.put(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits model parts from a parent, creating deep clones of all Variants.
|
||||
*/
|
||||
Map<String, List<ForgeBlockStateV1.Variant>> mergeModelPartVariants(Map<String, List<ForgeBlockStateV1.Variant>> output, Map<String, List<ForgeBlockStateV1.Variant>> input)
|
||||
{
|
||||
for (Entry<String, List<ForgeBlockStateV1.Variant>> e : input.entrySet())
|
||||
{
|
||||
String key = e.getKey();
|
||||
if (!output.containsKey(key))
|
||||
{
|
||||
List<ForgeBlockStateV1.Variant> variants = e.getValue();
|
||||
|
||||
if (variants != null)
|
||||
{
|
||||
List<ForgeBlockStateV1.Variant> newVariants = Lists.newArrayListWithCapacity(variants.size());
|
||||
|
||||
for (ForgeBlockStateV1.Variant v : variants)
|
||||
newVariants.add(new Variant(v));
|
||||
|
||||
output.put(key, newVariants);
|
||||
}
|
||||
else
|
||||
output.put(key, variants);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
protected SubModel asGenericSubModel()
|
||||
{
|
||||
return new SubModel(state.orElse(TRSRTransformation.identity()), uvLock.orElse(false), smooth.orElse(true), gui3d.orElse(true), getTextures(), model, getCustomData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list containing the single variant of each part.
|
||||
* Will throw an error if this Variant has multiple variants for a submodel.
|
||||
*/
|
||||
public ImmutableMap<String, SubModel> getOnlyPartsVariant()
|
||||
{
|
||||
if (submodels.size() > 0)
|
||||
{
|
||||
ImmutableMap.Builder<String, SubModel> builder = ImmutableMap.builder();
|
||||
|
||||
for (Entry<String, List<ForgeBlockStateV1.Variant>> entry : submodels.entrySet())
|
||||
{
|
||||
List<ForgeBlockStateV1.Variant> part = entry.getValue();
|
||||
|
||||
if (part != null)
|
||||
{
|
||||
if (part.size() == 1)
|
||||
builder.put(entry.getKey(), part.get(0).asGenericSubModel());
|
||||
else
|
||||
throw new RuntimeException("Something attempted to get the list of submodels "
|
||||
+ "for a variant with model \"" + model + "\", when this variant "
|
||||
+ "contains multiple variants for submodel " + entry.getKey());
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
else {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Boolean> getSmooth()
|
||||
{
|
||||
return smooth;
|
||||
}
|
||||
|
||||
public Optional<Boolean> getGui3d()
|
||||
{
|
||||
return gui3d;
|
||||
}
|
||||
|
||||
public static class Deserializer implements JsonDeserializer<ForgeBlockStateV1.Variant>
|
||||
{
|
||||
static Variant.Deserializer INSTANCE = new Deserializer();
|
||||
|
||||
/** Used <i>once</i> (then set null) for the key to put a simple submodel declaration under in the submodel map. */
|
||||
public String simpleSubmodelKey = null;
|
||||
|
||||
protected ResourceLocation getBlockLocation(String location)
|
||||
{
|
||||
ResourceLocation tmp = new ResourceLocation(location);
|
||||
return new ResourceLocation(tmp.getResourceDomain(), "block/" + tmp.getResourcePath());
|
||||
}
|
||||
|
||||
/** Throws an error if there are submodels in this submodel. */
|
||||
private void throwIfNestedSubmodels(ForgeBlockStateV1.Variant submodel)
|
||||
{
|
||||
if (submodel.submodels.size() > 0)
|
||||
throw new UnsupportedOperationException("Forge BlockStateLoader V1 does not support nested submodels.");
|
||||
}
|
||||
|
||||
private static TRSRTransformation get(float tx, float ty, float tz, float ax, float ay, float az, float s)
|
||||
{
|
||||
return TRSRTransformation.blockCenterToCorner(new TRSRTransformation(
|
||||
new Vector3f(tx / 16, ty / 16, tz / 16),
|
||||
TRSRTransformation.quatFromXYZDegrees(new Vector3f(ax, ay, az)),
|
||||
new Vector3f(s, s, s),
|
||||
null));
|
||||
}
|
||||
|
||||
private static final TRSRTransformation flipX = new TRSRTransformation(null, null, new Vector3f(-1, 1, 1), null);
|
||||
|
||||
private static TRSRTransformation leftify(TRSRTransformation transform)
|
||||
{
|
||||
return TRSRTransformation.blockCenterToCorner(flipX.compose(TRSRTransformation.blockCornerToCenter(transform)).compose(flipX));
|
||||
}
|
||||
|
||||
// Note: these strings might change to a full-blown resource locations in the future, and move from here to some json somewhere
|
||||
// TODO: vanilla now includes from parent, deprecate?
|
||||
private static final ImmutableMap<String, IModelState> transforms;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<String, IModelState> builder = ImmutableMap.builder();
|
||||
|
||||
builder.put("identity", TRSRTransformation.identity());
|
||||
|
||||
// block/block
|
||||
{
|
||||
EnumMap<TransformType, TRSRTransformation> map = new EnumMap<>(TransformType.class);
|
||||
TRSRTransformation thirdperson = get(0, 2.5f, 0, 75, 45, 0, 0.375f);
|
||||
map.put(TransformType.GUI, get(0, 0, 0, 30, 225, 0, 0.625f));
|
||||
map.put(TransformType.GROUND, get(0, 3, 0, 0, 0, 0, 0.25f));
|
||||
map.put(TransformType.FIXED, get(0, 0, 0, 0, 0, 0, 0.5f));
|
||||
map.put(TransformType.THIRD_PERSON_RIGHT_HAND, thirdperson);
|
||||
map.put(TransformType.THIRD_PERSON_LEFT_HAND, leftify(thirdperson));
|
||||
map.put(TransformType.FIRST_PERSON_RIGHT_HAND, get(0, 0, 0, 0, 45, 0, 0.4f));
|
||||
map.put(TransformType.FIRST_PERSON_LEFT_HAND, get(0, 0, 0, 0, 225, 0, 0.4f));
|
||||
builder.put("forge:default-block", new SimpleModelState(ImmutableMap.copyOf(map)));
|
||||
}
|
||||
|
||||
// item/generated
|
||||
{
|
||||
EnumMap<TransformType, TRSRTransformation> map = new EnumMap<>(TransformType.class);
|
||||
TRSRTransformation thirdperson = get(0, 3, 1, 0, 0, 0, 0.55f);
|
||||
TRSRTransformation firstperson = get(1.13f, 3.2f, 1.13f, 0, -90, 25, 0.68f);
|
||||
map.put(TransformType.GROUND, get(0, 2, 0, 0, 0, 0, 0.5f));
|
||||
map.put(TransformType.HEAD, get(0, 13, 7, 0, 180, 0, 1));
|
||||
map.put(TransformType.THIRD_PERSON_RIGHT_HAND, thirdperson);
|
||||
map.put(TransformType.THIRD_PERSON_LEFT_HAND, leftify(thirdperson));
|
||||
map.put(TransformType.FIRST_PERSON_RIGHT_HAND, firstperson);
|
||||
map.put(TransformType.FIRST_PERSON_LEFT_HAND, leftify(firstperson));
|
||||
map.put(TransformType.FIXED, get(0, 0, 0, 0, 180, 0, 1));
|
||||
builder.put("forge:default-item", new SimpleModelState(ImmutableMap.copyOf(map)));
|
||||
}
|
||||
|
||||
// item/handheld
|
||||
{
|
||||
EnumMap<TransformType, TRSRTransformation> map = new EnumMap<>(TransformType.class);
|
||||
map.put(TransformType.GROUND, get(0, 2, 0, 0, 0, 0, 0.5f));
|
||||
map.put(TransformType.HEAD, get(0, 13, 7, 0, 180, 0, 1));
|
||||
map.put(TransformType.THIRD_PERSON_RIGHT_HAND, get(0, 4, 0.5f, 0, -90, 55, 0.85f));
|
||||
map.put(TransformType.THIRD_PERSON_LEFT_HAND, get(0, 4, 0.5f, 0, 90, -55, 0.85f));
|
||||
map.put(TransformType.FIRST_PERSON_RIGHT_HAND, get(1.13f, 3.2f, 1.13f, 0, -90, 25, 0.68f));
|
||||
map.put(TransformType.FIRST_PERSON_LEFT_HAND, get(1.13f, 3.2f, 1.13f, 0, 90, -25, 0.68f));
|
||||
map.put(TransformType.FIXED, get(0, 0, 0, 0, 180, 0, 1));
|
||||
builder.put("forge:default-tool", new SimpleModelState(ImmutableMap.copyOf(map)));
|
||||
}
|
||||
|
||||
transforms = builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForgeBlockStateV1.Variant deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
ForgeBlockStateV1.Variant ret = new Variant();
|
||||
JsonObject json = element.getAsJsonObject();
|
||||
|
||||
if (json.has("model"))
|
||||
{ // Load base model location.
|
||||
if (json.get("model").isJsonNull())
|
||||
ret.model = null; // Allow overriding base model to remove it from a state.
|
||||
else
|
||||
ret.model = getBlockLocation(JsonUtils.getString(json, "model"));
|
||||
ret.modelSet = true;
|
||||
}
|
||||
|
||||
if (json.has("textures"))
|
||||
{ // Load textures map.
|
||||
for (Entry<String, JsonElement> e : json.get("textures").getAsJsonObject().entrySet())
|
||||
{
|
||||
if (e.getValue().isJsonNull())
|
||||
ret.textures.put(e.getKey(), ""); // We have to use "" because ImmutableMaps don't allow nulls -.-
|
||||
else
|
||||
ret.textures.put(e.getKey(), e.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
|
||||
if (json.has("x") || json.has("y"))
|
||||
{ // Load rotation values.
|
||||
int x = JsonUtils.getInt(json, "x", 0);
|
||||
int y = JsonUtils.getInt(json, "y", 0);
|
||||
ret.state = Optional.ofNullable(ModelRotation.getModelRotation(x, y));
|
||||
if (!ret.state.isPresent())
|
||||
throw new JsonParseException("Invalid BlockModelRotation x: " + x + " y: " + y);
|
||||
}
|
||||
|
||||
if (json.has("transform"))
|
||||
{
|
||||
if (json.get("transform").isJsonPrimitive() && json.get("transform").getAsJsonPrimitive().isString())
|
||||
{
|
||||
String transform = json.get("transform").getAsString();
|
||||
ret.state = Optional.ofNullable(transforms.get(transform));
|
||||
if (!ret.state.isPresent())
|
||||
{
|
||||
throw new JsonParseException("transform: unknown default string: " + transform);
|
||||
}
|
||||
}
|
||||
else if (!json.get("transform").isJsonObject())
|
||||
{
|
||||
try
|
||||
{
|
||||
TRSRTransformation base = context.deserialize(json.get("transform"), TRSRTransformation.class);
|
||||
ret.state = Optional.of(TRSRTransformation.blockCenterToCorner(base));
|
||||
}
|
||||
catch (JsonParseException e)
|
||||
{
|
||||
throw new JsonParseException("transform: expected a string, object or valid base transformation, got: " + json.get("transform"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonObject transform = json.get("transform").getAsJsonObject();
|
||||
EnumMap<TransformType, TRSRTransformation> transforms = Maps.newEnumMap(TransformType.class);
|
||||
if(transform.has("thirdperson"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("thirdperson"), TRSRTransformation.class);
|
||||
transform.remove("thirdperson");
|
||||
transforms.put(TransformType.THIRD_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("thirdperson_righthand"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("thirdperson_righthand"), TRSRTransformation.class);
|
||||
transform.remove("thirdperson_righthand");
|
||||
transforms.put(TransformType.THIRD_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("thirdperson_lefthand"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("thirdperson_lefthand"), TRSRTransformation.class);
|
||||
transform.remove("thirdperson_lefthand");
|
||||
transforms.put(TransformType.THIRD_PERSON_LEFT_HAND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("firstperson"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("firstperson"), TRSRTransformation.class);
|
||||
transform.remove("firstperson");
|
||||
transforms.put(TransformType.FIRST_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("firstperson_righthand"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("firstperson_righthand"), TRSRTransformation.class);
|
||||
transform.remove("firstperson_righthand");
|
||||
transforms.put(TransformType.FIRST_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("firstperson_lefthand"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("firstperson_lefthand"), TRSRTransformation.class);
|
||||
transform.remove("firstperson_lefthand");
|
||||
transforms.put(TransformType.FIRST_PERSON_LEFT_HAND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("head"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("head"), TRSRTransformation.class);
|
||||
transform.remove("head");
|
||||
transforms.put(TransformType.HEAD, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("gui"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("gui"), TRSRTransformation.class);
|
||||
transform.remove("gui");
|
||||
transforms.put(TransformType.GUI, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("ground"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("ground"), TRSRTransformation.class);
|
||||
transform.remove("ground");
|
||||
transforms.put(TransformType.GROUND, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
if(transform.has("fixed"))
|
||||
{
|
||||
TRSRTransformation t = context.deserialize(transform.get("fixed"), TRSRTransformation.class);
|
||||
transform.remove("fixed");
|
||||
transforms.put(TransformType.FIXED, TRSRTransformation.blockCenterToCorner(t));
|
||||
}
|
||||
int k = transform.entrySet().size();
|
||||
if(transform.has("matrix")) k--;
|
||||
if(transform.has("translation")) k--;
|
||||
if(transform.has("rotation")) k--;
|
||||
if(transform.has("scale")) k--;
|
||||
if(transform.has("post-rotation")) k--;
|
||||
if(k > 0)
|
||||
{
|
||||
throw new JsonParseException("transform: allowed keys: 'thirdperson', 'firstperson', 'gui', 'head', 'matrix', 'translation', 'rotation', 'scale', 'post-rotation'");
|
||||
}
|
||||
TRSRTransformation base = TRSRTransformation.identity();
|
||||
if(!transform.entrySet().isEmpty())
|
||||
{
|
||||
base = context.deserialize(transform, TRSRTransformation.class);
|
||||
base = TRSRTransformation.blockCenterToCorner(base);
|
||||
}
|
||||
IModelState state;
|
||||
if(transforms.isEmpty())
|
||||
{
|
||||
state = base;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = new SimpleModelState(Maps.immutableEnumMap(transforms), Optional.of(base));
|
||||
}
|
||||
ret.state = Optional.of(state);
|
||||
}
|
||||
}
|
||||
|
||||
if (json.has("uvlock"))
|
||||
{ // Load uvlock.
|
||||
ret.uvLock = Optional.of(JsonUtils.getBoolean(json, "uvlock"));
|
||||
}
|
||||
|
||||
if (json.has("smooth_lighting"))
|
||||
{
|
||||
ret.smooth = Optional.of(JsonUtils.getBoolean(json, "smooth_lighting"));
|
||||
}
|
||||
|
||||
if (json.has("gui3d"))
|
||||
{
|
||||
ret.gui3d = Optional.of(JsonUtils.getBoolean(json, "gui3d"));
|
||||
}
|
||||
|
||||
if (json.has("weight"))
|
||||
{ // Load weight.
|
||||
ret.weight = Optional.of(JsonUtils.getInt(json, "weight"));
|
||||
}
|
||||
|
||||
if (json.has("submodel"))
|
||||
{ // Load submodels.
|
||||
JsonElement submodels = json.get("submodel");
|
||||
|
||||
if (submodels.isJsonPrimitive())
|
||||
{ // Load a simple submodel declaration.
|
||||
if (simpleSubmodelKey == null)
|
||||
throw new RuntimeException("Attempted to use a simple submodel declaration outside a valid state variant declaration.");
|
||||
String key = simpleSubmodelKey;
|
||||
simpleSubmodelKey = null;
|
||||
|
||||
ret.model = getBlockLocation(submodels.getAsString());
|
||||
ret.modelSet = true;
|
||||
ForgeBlockStateV1.Variant dummyVar = new Variant(); // Create a dummy Variant to use as the owner of the simple submodel.
|
||||
dummyVar.submodels.put(key, Collections.singletonList(ret));
|
||||
dummyVar.simpleSubmodels = Collections.singletonMap(key, Variant.SET_VALUE);
|
||||
return dummyVar;
|
||||
}
|
||||
else
|
||||
{ // Load full submodel declarations.
|
||||
// Clear the simple submodel key so that when deserializing submodels, the deserializer doesn't use the key.
|
||||
simpleSubmodelKey = null;
|
||||
|
||||
for (Entry<String, JsonElement> submodel : submodels.getAsJsonObject().entrySet())
|
||||
{
|
||||
JsonElement varEl = submodel.getValue();
|
||||
List<ForgeBlockStateV1.Variant> submodelVariants;
|
||||
|
||||
if (varEl.isJsonArray())
|
||||
{ // Multiple variants of the submodel.
|
||||
submodelVariants = Lists.newArrayList();
|
||||
for (JsonElement e : varEl.getAsJsonArray())
|
||||
submodelVariants.add(context.deserialize(e, Variant.class));
|
||||
}
|
||||
else if (varEl.isJsonNull())
|
||||
{
|
||||
submodelVariants = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
submodelVariants = Collections.singletonList(context.deserialize(varEl, Variant.class));
|
||||
}
|
||||
|
||||
if (submodelVariants != null) // Throw an error if there are submodels inside a submodel.
|
||||
for (ForgeBlockStateV1.Variant part : submodelVariants)
|
||||
throwIfNestedSubmodels(part);
|
||||
|
||||
ret.submodels.put(submodel.getKey(), submodelVariants);
|
||||
// Put null to remove this submodel from the list of simple submodels when something inherits this submodel.
|
||||
ret.simpleSubmodels.put(submodel.getKey(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.has("custom"))
|
||||
{
|
||||
for (Entry<String, JsonElement> e : json.get("custom").getAsJsonObject().entrySet())
|
||||
{
|
||||
if (e.getValue().isJsonNull())
|
||||
ret.customData.put(e.getKey(), null);
|
||||
else
|
||||
ret.customData.put(e.getKey(), e.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
simpleSubmodelKey = null;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getModel() { return model; }
|
||||
public boolean isModelSet() { return modelSet; }
|
||||
public Optional<IModelState> getState() { return state; }
|
||||
public Optional<Boolean> getUvLock() { return uvLock; }
|
||||
public Optional<Integer> getWeight() { return weight; }
|
||||
public ImmutableMap<String, String> getTextures() { return ImmutableMap.copyOf(textures); }
|
||||
public ImmutableMap<String, List<ForgeBlockStateV1.Variant>> getSubmodels() { return ImmutableMap.copyOf(submodels); }
|
||||
public ImmutableMap<String, String> getCustomData() { return ImmutableMap.copyOf(customData); }
|
||||
}
|
||||
|
||||
public static class TRSRDeserializer implements JsonDeserializer<TRSRTransformation>
|
||||
{
|
||||
public static final TRSRDeserializer INSTANCE = new TRSRDeserializer();
|
||||
|
||||
@Override
|
||||
public TRSRTransformation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString())
|
||||
{
|
||||
String transform = json.getAsString();
|
||||
if(transform.equals("identity"))
|
||||
{
|
||||
return TRSRTransformation.identity();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonParseException("TRSR: unknown default string: " + transform);
|
||||
}
|
||||
}
|
||||
if (json.isJsonArray())
|
||||
{
|
||||
// direct matrix array
|
||||
return new TRSRTransformation(parseMatrix(json));
|
||||
}
|
||||
if (!json.isJsonObject()) throw new JsonParseException("TRSR: expected array or object, got: " + json);
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
TRSRTransformation ret;
|
||||
if (obj.has("matrix"))
|
||||
{
|
||||
// matrix as a sole key
|
||||
ret = new TRSRTransformation(parseMatrix(obj.get("matrix")));
|
||||
obj.remove("matrix");
|
||||
if (obj.entrySet().size() != 0)
|
||||
{
|
||||
throw new JsonParseException("TRSR: can't combine matrix and other keys");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Vector3f translation = null;
|
||||
Quat4f leftRot = null;
|
||||
Vector3f scale = null;
|
||||
Quat4f rightRot = null;
|
||||
if (obj.has("translation"))
|
||||
{
|
||||
translation = new Vector3f(parseFloatArray(obj.get("translation"), 3, "Translation"));
|
||||
obj.remove("translation");
|
||||
}
|
||||
if (obj.has("rotation"))
|
||||
{
|
||||
leftRot = parseRotation(obj.get("rotation"));
|
||||
obj.remove("rotation");
|
||||
}
|
||||
if (obj.has("scale"))
|
||||
{
|
||||
if(!obj.get("scale").isJsonArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
float s = obj.get("scale").getAsNumber().floatValue();
|
||||
scale = new Vector3f(s, s, s);
|
||||
}
|
||||
catch (ClassCastException ex)
|
||||
{
|
||||
throw new JsonParseException("TRSR scale: expected number or array, got: " + obj.get("scale"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = new Vector3f(parseFloatArray(obj.get("scale"), 3, "Scale"));
|
||||
}
|
||||
obj.remove("scale");
|
||||
}
|
||||
if (obj.has("post-rotation"))
|
||||
{
|
||||
rightRot = parseRotation(obj.get("post-rotation"));
|
||||
obj.remove("post-rotation");
|
||||
}
|
||||
if (!obj.entrySet().isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation', 'scale', 'post-rotation'");
|
||||
return new TRSRTransformation(translation, leftRot, scale, rightRot);
|
||||
}
|
||||
|
||||
public static Matrix4f parseMatrix(JsonElement e)
|
||||
{
|
||||
if (!e.isJsonArray()) throw new JsonParseException("Matrix: expected an array, got: " + e);
|
||||
JsonArray m = e.getAsJsonArray();
|
||||
if (m.size() != 3) throw new JsonParseException("Matrix: expected an array of length 3, got: " + m.size());
|
||||
Matrix4f ret = new Matrix4f();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (!m.get(i).isJsonArray()) throw new JsonParseException("Matrix row: expected an array, got: " + m.get(i));
|
||||
JsonArray r = m.get(i).getAsJsonArray();
|
||||
if (r.size() != 4) throw new JsonParseException("Matrix row: expected an array of length 4, got: " + r.size());
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret.setElement(i, j, r.get(j).getAsNumber().floatValue());
|
||||
}
|
||||
catch (ClassCastException ex)
|
||||
{
|
||||
throw new JsonParseException("Matrix element: expected number, got: " + r.get(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static float[] parseFloatArray(JsonElement e, int length, String prefix)
|
||||
{
|
||||
if (!e.isJsonArray()) throw new JsonParseException(prefix + ": expected an array, got: " + e);
|
||||
JsonArray t = e.getAsJsonArray();
|
||||
if (t.size() != length) throw new JsonParseException(prefix + ": expected an array of length " + length + ", got: " + t.size());
|
||||
float[] ret = new float[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret[i] = t.get(i).getAsNumber().floatValue();
|
||||
}
|
||||
catch (ClassCastException ex)
|
||||
{
|
||||
throw new JsonParseException(prefix + " element: expected number, got: " + t.get(i));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Quat4f parseAxisRotation(JsonElement e)
|
||||
{
|
||||
if (!e.isJsonObject()) throw new JsonParseException("Axis rotation: object expected, got: " + e);
|
||||
JsonObject obj = e.getAsJsonObject();
|
||||
if (obj.entrySet().size() != 1) throw new JsonParseException("Axis rotation: expected single axis object, got: " + e);
|
||||
Map.Entry<String, JsonElement> entry = obj.entrySet().iterator().next();
|
||||
Quat4f ret = new Quat4f();
|
||||
try
|
||||
{
|
||||
if (entry.getKey().equals("x"))
|
||||
{
|
||||
ret.set(new AxisAngle4d(1, 0, 0, Math.toRadians(entry.getValue().getAsNumber().floatValue())));
|
||||
}
|
||||
else if (entry.getKey().equals("y"))
|
||||
{
|
||||
ret.set(new AxisAngle4d(0, 1, 0, Math.toRadians(entry.getValue().getAsNumber().floatValue())));
|
||||
}
|
||||
else if (entry.getKey().equals("z"))
|
||||
{
|
||||
ret.set(new AxisAngle4d(0, 0, 1, Math.toRadians(entry.getValue().getAsNumber().floatValue())));
|
||||
}
|
||||
else throw new JsonParseException("Axis rotation: expected single axis key, got: " + entry.getKey());
|
||||
}
|
||||
catch(ClassCastException ex)
|
||||
{
|
||||
throw new JsonParseException("Axis rotation value: expected number, got: " + entry.getValue());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Quat4f parseRotation(JsonElement e)
|
||||
{
|
||||
if (e.isJsonArray())
|
||||
{
|
||||
if (e.getAsJsonArray().get(0).isJsonObject())
|
||||
{
|
||||
Quat4f ret = new Quat4f(0, 0, 0, 1);
|
||||
for (JsonElement a : e.getAsJsonArray())
|
||||
{
|
||||
ret.mul(parseAxisRotation(a));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else if (e.isJsonArray())
|
||||
{
|
||||
JsonArray array = e.getAsJsonArray();
|
||||
if (array.size() == 3) //Vanilla rotation
|
||||
return TRSRTransformation.quatFromXYZDegrees(new Vector3f(parseFloatArray(e, 3, "Rotation")));
|
||||
else // quaternion
|
||||
return new Quat4f(parseFloatArray(e, 4, "Rotation"));
|
||||
}
|
||||
else throw new JsonParseException("Rotation: expected array or object, got: " + e);
|
||||
}
|
||||
else if (e.isJsonObject())
|
||||
{
|
||||
return parseAxisRotation(e);
|
||||
}
|
||||
else throw new JsonParseException("Rotation: expected array or object, got: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraftforge.client.resource.IResourceType;
|
||||
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
|
||||
import net.minecraftforge.client.resource.VanillaResourceType;
|
||||
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface ICustomModelLoader extends ISelectiveResourceReloadListener
|
||||
{
|
||||
@Override
|
||||
void onResourceManagerReload(IResourceManager resourceManager);
|
||||
|
||||
@Override
|
||||
default void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate)
|
||||
{
|
||||
if (resourcePredicate.test(VanillaResourceType.MODELS))
|
||||
{
|
||||
onResourceManagerReload(resourceManager);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if given model should be loaded by this loader.
|
||||
* Reading file contents is inadvisable, if possible decision should be made based on the location alone.
|
||||
*/
|
||||
boolean accepts(ResourceLocation modelLocation);
|
||||
|
||||
/*
|
||||
* loads (or reloads) specified model
|
||||
*/
|
||||
IModel loadModel(ResourceLocation modelLocation) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import java.util.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
|
||||
import java.util.function.Function;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.common.model.animation.IClip;
|
||||
|
||||
/*
|
||||
* Interface for models that can be baked
|
||||
* (possibly to different vertex formats and with different state).
|
||||
*/
|
||||
public interface IModel
|
||||
{
|
||||
/*
|
||||
* Returns all model locations that this model depends on.
|
||||
* Assume that returned collection is immutable.
|
||||
* See ModelLoaderRegistry.getModel for dependency loading.
|
||||
*/
|
||||
default Collection<ResourceLocation> getDependencies() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns all texture locations that this model depends on.
|
||||
* Assume that returned collection is immutable.
|
||||
*/
|
||||
default Collection<ResourceLocation> getTextures() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/*
|
||||
* All model texture coordinates should be resolved at this method.
|
||||
* Returned model should be in the simplest form possible, for performance
|
||||
* reasons (if it's not ISmartBlock/ItemModel - then it should be
|
||||
* represented by List<BakedQuad> internally).
|
||||
* Returned model's getFormat() can me less specific than the passed
|
||||
* format argument (some attributes can be replaced with padding),
|
||||
* if there's no such info in this model.
|
||||
*/
|
||||
IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter);
|
||||
|
||||
/*
|
||||
* Default state this model will be baked with.
|
||||
* See IModelState.
|
||||
*/
|
||||
default IModelState getDefaultState() {
|
||||
return TRSRTransformation.identity();
|
||||
}
|
||||
|
||||
default Optional<? extends IClip> getClip(String name) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the model to process custom data from the variant definition.
|
||||
* If unknown data is encountered it should be skipped.
|
||||
* @return a new model, with data applied.
|
||||
*/
|
||||
default IModel process(ImmutableMap<String, String> customData) {
|
||||
return this;
|
||||
}
|
||||
|
||||
default IModel smoothLighting(boolean value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
default IModel gui3d(boolean value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
default IModel uvlock(boolean value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies new textures to the model.
|
||||
* The returned model should be independent of the accessed one,
|
||||
* as a model should be able to be retextured multiple times producing
|
||||
* a separate model each time.
|
||||
*
|
||||
* The input map MAY map to an empty string "" which should be used
|
||||
* to indicate the texture was removed. Handling of that is up to
|
||||
* the model itself. Such as using default, missing texture, or
|
||||
* removing vertices.
|
||||
*
|
||||
* The input should be considered a DIFF of the old textures, not a
|
||||
* replacement as it may not contain everything.
|
||||
*
|
||||
* @param textures New
|
||||
* @return Model with textures applied.
|
||||
*/
|
||||
default IModel retexture(ImmutableMap<String, String> textures) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
|
||||
public interface ISmartVariant
|
||||
{
|
||||
IModel process(IModel base);
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import javax.vecmath.Vector4f;
|
||||
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.block.model.ModelBlock;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public final class ItemLayerModel implements IModel
|
||||
{
|
||||
public static final ItemLayerModel INSTANCE = new ItemLayerModel(ImmutableList.of());
|
||||
|
||||
private static final EnumFacing[] HORIZONTALS = {EnumFacing.UP, EnumFacing.DOWN};
|
||||
private static final EnumFacing[] VERTICALS = {EnumFacing.WEST, EnumFacing.EAST};
|
||||
|
||||
private final ImmutableList<ResourceLocation> textures;
|
||||
private final ItemOverrideList overrides;
|
||||
|
||||
public ItemLayerModel(ImmutableList<ResourceLocation> textures)
|
||||
{
|
||||
this(textures, ItemOverrideList.NONE);
|
||||
}
|
||||
|
||||
public ItemLayerModel(ImmutableList<ResourceLocation> textures, ItemOverrideList overrides)
|
||||
{
|
||||
this.textures = textures;
|
||||
this.overrides = overrides;
|
||||
}
|
||||
|
||||
public ItemLayerModel(ModelBlock model)
|
||||
{
|
||||
this(getTextures(model), model.createOverrides());
|
||||
}
|
||||
|
||||
private static ImmutableList<ResourceLocation> getTextures(ModelBlock model)
|
||||
{
|
||||
ImmutableList.Builder<ResourceLocation> builder = ImmutableList.builder();
|
||||
for(int i = 0; model.isTexturePresent("layer" + i); i++)
|
||||
{
|
||||
builder.add(new ResourceLocation(model.resolveTextureName("layer" + i)));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
return textures;
|
||||
}
|
||||
|
||||
public ItemLayerModel retexture(ImmutableMap<String, String> textures)
|
||||
{
|
||||
ImmutableList.Builder<ResourceLocation> builder = ImmutableList.builder();
|
||||
for(int i = 0; i < textures.size() + this.textures.size(); i++)
|
||||
{
|
||||
if(textures.containsKey("layer" + i))
|
||||
{
|
||||
builder.add(new ResourceLocation(textures.get("layer" + i)));
|
||||
}
|
||||
else if(i < this.textures.size())
|
||||
{
|
||||
builder.add(this.textures.get(i));
|
||||
}
|
||||
}
|
||||
return new ItemLayerModel(builder.build(), overrides);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, final VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
Optional<TRSRTransformation> transform = state.apply(Optional.empty());
|
||||
for(int i = 0; i < textures.size(); i++)
|
||||
{
|
||||
TextureAtlasSprite sprite = bakedTextureGetter.apply(textures.get(i));
|
||||
builder.addAll(getQuadsForSprite(i, sprite, format, transform));
|
||||
}
|
||||
TextureAtlasSprite particle = bakedTextureGetter.apply(textures.isEmpty() ? new ResourceLocation("missingno") : textures.get(0));
|
||||
ImmutableMap<TransformType, TRSRTransformation> map = PerspectiveMapWrapper.getTransforms(state);
|
||||
return new BakedItemModel(builder.build(), particle, map, overrides);
|
||||
}
|
||||
|
||||
public static ImmutableList<BakedQuad> getQuadsForSprite(int tint, TextureAtlasSprite sprite, VertexFormat format, Optional<TRSRTransformation> transform)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
int uMax = sprite.getIconWidth();
|
||||
int vMax = sprite.getIconHeight();
|
||||
|
||||
FaceData faceData = new FaceData(uMax, vMax);
|
||||
boolean translucent = false;
|
||||
|
||||
for(int f = 0; f < sprite.getFrameCount(); f++)
|
||||
{
|
||||
int[] pixels = sprite.getFrameTextureData(f)[0];
|
||||
boolean ptu;
|
||||
boolean[] ptv = new boolean[uMax];
|
||||
Arrays.fill(ptv, true);
|
||||
for(int v = 0; v < vMax; v++)
|
||||
{
|
||||
ptu = true;
|
||||
for(int u = 0; u < uMax; u++)
|
||||
{
|
||||
int alpha = getAlpha(pixels, uMax, vMax, u, v);
|
||||
boolean t = alpha / 255f <= 0.1f;
|
||||
|
||||
if (!t && alpha < 255)
|
||||
{
|
||||
translucent = true;
|
||||
}
|
||||
|
||||
if(ptu && !t) // left - transparent, right - opaque
|
||||
{
|
||||
faceData.set(EnumFacing.WEST, u, v);
|
||||
}
|
||||
if(!ptu && t) // left - opaque, right - transparent
|
||||
{
|
||||
faceData.set(EnumFacing.EAST, u-1, v);
|
||||
}
|
||||
if(ptv[u] && !t) // up - transparent, down - opaque
|
||||
{
|
||||
faceData.set(EnumFacing.UP, u, v);
|
||||
}
|
||||
if(!ptv[u] && t) // up - opaque, down - transparent
|
||||
{
|
||||
faceData.set(EnumFacing.DOWN, u, v-1);
|
||||
}
|
||||
|
||||
ptu = t;
|
||||
ptv[u] = t;
|
||||
}
|
||||
if(!ptu) // last - opaque
|
||||
{
|
||||
faceData.set(EnumFacing.EAST, uMax-1, v);
|
||||
}
|
||||
}
|
||||
// last line
|
||||
for(int u = 0; u < uMax; u++)
|
||||
{
|
||||
if(!ptv[u])
|
||||
{
|
||||
faceData.set(EnumFacing.DOWN, u, vMax-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// horizontal quads
|
||||
for (EnumFacing facing : HORIZONTALS)
|
||||
{
|
||||
for (int v = 0; v < vMax; v++)
|
||||
{
|
||||
int uStart = 0, uEnd = uMax;
|
||||
boolean building = false;
|
||||
for (int u = 0; u < uMax; u++)
|
||||
{
|
||||
boolean face = faceData.get(facing, u, v);
|
||||
if (!translucent)
|
||||
{
|
||||
if (face)
|
||||
{
|
||||
if (!building)
|
||||
{
|
||||
building = true;
|
||||
uStart = u;
|
||||
}
|
||||
uEnd = u + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (building && !face) // finish current quad
|
||||
{
|
||||
// make quad [uStart, u]
|
||||
int off = facing == EnumFacing.DOWN ? 1 : 0;
|
||||
builder.add(buildSideQuad(format, transform, facing, tint, sprite, uStart, v+off, u-uStart));
|
||||
building = false;
|
||||
}
|
||||
else if (!building && face) // start new quad
|
||||
{
|
||||
building = true;
|
||||
uStart = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (building) // build remaining quad
|
||||
{
|
||||
// make quad [uStart, uEnd]
|
||||
int off = facing == EnumFacing.DOWN ? 1 : 0;
|
||||
builder.add(buildSideQuad(format, transform, facing, tint, sprite, uStart, v+off, uEnd-uStart));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vertical quads
|
||||
for (EnumFacing facing : VERTICALS)
|
||||
{
|
||||
for (int u = 0; u < uMax; u++)
|
||||
{
|
||||
int vStart = 0, vEnd = vMax;
|
||||
boolean building = false;
|
||||
for (int v = 0; v < vMax; v++)
|
||||
{
|
||||
boolean face = faceData.get(facing, u, v);
|
||||
if (!translucent)
|
||||
{
|
||||
if (face)
|
||||
{
|
||||
if (!building)
|
||||
{
|
||||
building = true;
|
||||
vStart = v;
|
||||
}
|
||||
vEnd = v + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (building && !face) // finish current quad
|
||||
{
|
||||
// make quad [vStart, v]
|
||||
int off = facing == EnumFacing.EAST ? 1 : 0;
|
||||
builder.add(buildSideQuad(format, transform, facing, tint, sprite, u+off, vStart, v-vStart));
|
||||
building = false;
|
||||
}
|
||||
else if (!building && face) // start new quad
|
||||
{
|
||||
building = true;
|
||||
vStart = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (building) // build remaining quad
|
||||
{
|
||||
// make quad [vStart, vEnd]
|
||||
int off = facing == EnumFacing.EAST ? 1 : 0;
|
||||
builder.add(buildSideQuad(format, transform, facing, tint, sprite, u+off, vStart, vEnd-vStart));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// front
|
||||
builder.add(buildQuad(format, transform, EnumFacing.NORTH, sprite, tint,
|
||||
0, 0, 7.5f / 16f, sprite.getMinU(), sprite.getMaxV(),
|
||||
0, 1, 7.5f / 16f, sprite.getMinU(), sprite.getMinV(),
|
||||
1, 1, 7.5f / 16f, sprite.getMaxU(), sprite.getMinV(),
|
||||
1, 0, 7.5f / 16f, sprite.getMaxU(), sprite.getMaxV()
|
||||
));
|
||||
// back
|
||||
builder.add(buildQuad(format, transform, EnumFacing.SOUTH, sprite, tint,
|
||||
0, 0, 8.5f / 16f, sprite.getMinU(), sprite.getMaxV(),
|
||||
1, 0, 8.5f / 16f, sprite.getMaxU(), sprite.getMaxV(),
|
||||
1, 1, 8.5f / 16f, sprite.getMaxU(), sprite.getMinV(),
|
||||
0, 1, 8.5f / 16f, sprite.getMinU(), sprite.getMinV()
|
||||
));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static class FaceData
|
||||
{
|
||||
private final EnumMap<EnumFacing, BitSet> data = new EnumMap<>(EnumFacing.class);
|
||||
|
||||
private final int vMax;
|
||||
|
||||
FaceData(int uMax, int vMax)
|
||||
{
|
||||
this.vMax = vMax;
|
||||
|
||||
data.put(EnumFacing.WEST, new BitSet(uMax * vMax));
|
||||
data.put(EnumFacing.EAST, new BitSet(uMax * vMax));
|
||||
data.put(EnumFacing.UP, new BitSet(uMax * vMax));
|
||||
data.put(EnumFacing.DOWN, new BitSet(uMax * vMax));
|
||||
}
|
||||
|
||||
public void set(EnumFacing facing, int u, int v)
|
||||
{
|
||||
data.get(facing).set(getIndex(u, v));
|
||||
}
|
||||
|
||||
public boolean get(EnumFacing facing, int u, int v)
|
||||
{
|
||||
return data.get(facing).get(getIndex(u, v));
|
||||
}
|
||||
|
||||
private int getIndex(int u, int v)
|
||||
{
|
||||
return v * vMax + u;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getAlpha(int[] pixels, int uMax, int vMax, int u, int v)
|
||||
{
|
||||
return pixels[u + (vMax - 1 - v) * uMax] >> 24 & 0xFF;
|
||||
}
|
||||
|
||||
private static BakedQuad buildSideQuad(VertexFormat format, Optional<TRSRTransformation> transform, EnumFacing side, int tint, TextureAtlasSprite sprite, int u, int v, int size)
|
||||
{
|
||||
final float eps = 1e-2f;
|
||||
|
||||
int width = sprite.getIconWidth();
|
||||
int height = sprite.getIconHeight();
|
||||
|
||||
float x0 = (float) u / width;
|
||||
float y0 = (float) v / height;
|
||||
float x1 = x0, y1 = y0;
|
||||
float z0 = 7.5f / 16f, z1 = 8.5f / 16f;
|
||||
|
||||
switch(side)
|
||||
{
|
||||
case WEST:
|
||||
z0 = 8.5f / 16f;
|
||||
z1 = 7.5f / 16f;
|
||||
case EAST:
|
||||
y1 = (float) (v + size) / height;
|
||||
break;
|
||||
case DOWN:
|
||||
z0 = 8.5f / 16f;
|
||||
z1 = 7.5f / 16f;
|
||||
case UP:
|
||||
x1 = (float) (u + size) / width;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("can't handle z-oriented side");
|
||||
}
|
||||
|
||||
float dx = side.getDirectionVec().getX() * eps / width;
|
||||
float dy = side.getDirectionVec().getY() * eps / height;
|
||||
|
||||
float u0 = 16f * (x0 - dx);
|
||||
float u1 = 16f * (x1 - dx);
|
||||
float v0 = 16f * (1f - y0 - dy);
|
||||
float v1 = 16f * (1f - y1 - dy);
|
||||
|
||||
return buildQuad(
|
||||
format, transform, remap(side), sprite, tint,
|
||||
x0, y0, z0, sprite.getInterpolatedU(u0), sprite.getInterpolatedV(v0),
|
||||
x1, y1, z0, sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v1),
|
||||
x1, y1, z1, sprite.getInterpolatedU(u1), sprite.getInterpolatedV(v1),
|
||||
x0, y0, z1, sprite.getInterpolatedU(u0), sprite.getInterpolatedV(v0)
|
||||
);
|
||||
}
|
||||
|
||||
private static EnumFacing remap(EnumFacing side)
|
||||
{
|
||||
// getOpposite is related to the swapping of V direction
|
||||
return side.getAxis() == EnumFacing.Axis.Y ? side.getOpposite() : side;
|
||||
}
|
||||
|
||||
private static BakedQuad buildQuad(
|
||||
VertexFormat format, Optional<TRSRTransformation> transform, EnumFacing side, TextureAtlasSprite sprite, int tint,
|
||||
float x0, float y0, float z0, float u0, float v0,
|
||||
float x1, float y1, float z1, float u1, float v1,
|
||||
float x2, float y2, float z2, float u2, float v2,
|
||||
float x3, float y3, float z3, float u3, float v3)
|
||||
{
|
||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadTint(tint);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(sprite);
|
||||
putVertex(builder, format, transform, side, x0, y0, z0, u0, v0);
|
||||
putVertex(builder, format, transform, side, x1, y1, z1, u1, v1);
|
||||
putVertex(builder, format, transform, side, x2, y2, z2, u2, v2);
|
||||
putVertex(builder, format, transform, side, x3, y3, z3, u3, v3);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static void putVertex(UnpackedBakedQuad.Builder builder, VertexFormat format, Optional<TRSRTransformation> transform, EnumFacing side, float x, float y, float z, float u, float v)
|
||||
{
|
||||
Vector4f vec = new Vector4f();
|
||||
for(int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
switch(format.getElement(e).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
if(transform.isPresent())
|
||||
{
|
||||
vec.x = x;
|
||||
vec.y = y;
|
||||
vec.z = z;
|
||||
vec.w = 1;
|
||||
transform.get().getMatrix().transform(vec);
|
||||
builder.put(e, vec.x, vec.y, vec.z, vec.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.put(e, x, y, z, 1);
|
||||
}
|
||||
break;
|
||||
case COLOR:
|
||||
builder.put(e, 1f, 1f, 1f, 1f);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Loader implements ICustomModelLoader
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {}
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return modelLocation.getResourceDomain().equals(ForgeVersion.MOD_ID) && (
|
||||
modelLocation.getResourcePath().equals("item-layer") ||
|
||||
modelLocation.getResourcePath().equals("models/block/item-layer") ||
|
||||
modelLocation.getResourcePath().equals("models/item/item-layer"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation)
|
||||
{
|
||||
return ItemLayerModel.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.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 net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import javax.vecmath.Vector4f;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class ItemTextureQuadConverter
|
||||
{
|
||||
private ItemTextureQuadConverter()
|
||||
{
|
||||
// non-instantiable
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #convertTexture(VertexFormat, TRSRTransformation, TextureAtlasSprite, TextureAtlasSprite, float, EnumFacing, int, int)}*/
|
||||
@Deprecated // TODO: remove
|
||||
public static List<UnpackedBakedQuad> convertTexture(VertexFormat format, TRSRTransformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, EnumFacing facing, int color)
|
||||
{
|
||||
return convertTexture(format, transform, template, sprite, z, facing, color, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, int tint)
|
||||
{
|
||||
List<UnpackedBakedQuad> horizontal = convertTextureHorizontal(format, transform, template, sprite, z, facing, color, tint);
|
||||
List<UnpackedBakedQuad> vertical = convertTextureVertical(format, transform, template, sprite, z, facing, color, tint);
|
||||
|
||||
return horizontal.size() >= vertical.size() ? horizontal : vertical;
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #convertTextureHorizontal(VertexFormat, TRSRTransformation, TextureAtlasSprite, TextureAtlasSprite, float, EnumFacing, int, int)} */
|
||||
@Deprecated // TODO: remove
|
||||
public static List<UnpackedBakedQuad> convertTextureHorizontal(VertexFormat format, TRSRTransformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, EnumFacing facing, int color)
|
||||
{
|
||||
return convertTextureHorizontal(format, transform, template, sprite, z, facing, color, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tint)
|
||||
{
|
||||
int w = template.getIconWidth();
|
||||
int h = template.getIconHeight();
|
||||
float wScale = 16f / (float)w;
|
||||
float hScale = 16f / (float)h;
|
||||
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 && endY < h)
|
||||
{
|
||||
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,
|
||||
(float)start * wScale,
|
||||
(float)y * hScale,
|
||||
(float)x * wScale,
|
||||
(float)endY * hScale,
|
||||
z, sprite, facing, color, tint));
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #convertTextureVertical(VertexFormat, TRSRTransformation, TextureAtlasSprite, TextureAtlasSprite, float, EnumFacing, int, int)} */
|
||||
@Deprecated // TODO: remove
|
||||
public static List<UnpackedBakedQuad> convertTextureVertical(VertexFormat format, TRSRTransformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, EnumFacing facing, int color)
|
||||
{
|
||||
return convertTextureVertical(format, transform, template, sprite, z, facing, color, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tint)
|
||||
{
|
||||
int w = template.getIconWidth();
|
||||
int h = template.getIconHeight();
|
||||
float wScale = 16f / (float)w;
|
||||
float hScale = 16f / (float)h;
|
||||
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 && endX < w)
|
||||
{
|
||||
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,
|
||||
(float)x * wScale,
|
||||
(float)start * hScale,
|
||||
(float)endX * wScale,
|
||||
(float)y * hScale,
|
||||
z, sprite, facing, color, tint));
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
private static boolean isVisible(int color)
|
||||
{
|
||||
return (color >> 24 & 255) / 255f > 0.1f;
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #genQuad(VertexFormat, TRSRTransformation, float, float, float, float, float, TextureAtlasSprite, EnumFacing, int, int)} */
|
||||
@Deprecated // TODO: remove
|
||||
public static UnpackedBakedQuad genQuad(VertexFormat format, TRSRTransformation transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, EnumFacing facing, int color)
|
||||
{
|
||||
return genQuad(format, transform, x1, y1, x2, y2, z, sprite, facing, color, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Front/Back quad for an itemmodel. Therefore only supports facing NORTH and SOUTH.
|
||||
* Coordinates are [0,16] to match the usual coordinates used in TextureAtlasSprites
|
||||
*/
|
||||
public static UnpackedBakedQuad genQuad(VertexFormat format, TRSRTransformation transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, EnumFacing facing, int color, int tint)
|
||||
{
|
||||
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, sprite, color, tint, x1, y1, x2, y2, z, u1, v1, u2, v2);
|
||||
}
|
||||
|
||||
private static UnpackedBakedQuad putQuad(VertexFormat format, TRSRTransformation transform, EnumFacing side, TextureAtlasSprite sprite, int color, int tint,
|
||||
float x1, float y1, float x2, float y2, float z,
|
||||
float u1, float v1, float u2, float v2)
|
||||
{
|
||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||
|
||||
builder.setQuadTint(tint);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(sprite);
|
||||
|
||||
if (side == EnumFacing.SOUTH)
|
||||
{
|
||||
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.isIdentity())
|
||||
{
|
||||
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,104 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.common.model.IModelPart;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import java.util.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/*
|
||||
* Simple implementation of IModelState via a map and a default value. Provides a full state for each part.
|
||||
* You probably don't want to use this.
|
||||
*/
|
||||
public class MapModelState implements IModelState
|
||||
{
|
||||
private final ImmutableMap<Wrapper, IModelState> map;
|
||||
private final IModelState def;
|
||||
|
||||
public MapModelState(Map<Wrapper, IModelState> map)
|
||||
{
|
||||
this(map, TRSRTransformation.identity());
|
||||
}
|
||||
|
||||
public MapModelState(Map<Wrapper, IModelState> map, TRSRTransformation def)
|
||||
{
|
||||
this(map, (IModelState)def);
|
||||
}
|
||||
|
||||
public MapModelState(Map<Wrapper, IModelState> map, IModelState def)
|
||||
{
|
||||
this.map = ImmutableMap.copyOf(map);
|
||||
this.def = def;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
||||
{
|
||||
if(!part.isPresent() || !map.containsKey(part.get())) return def.apply(part);
|
||||
return map.get(part.get()).apply(Optional.empty());
|
||||
}
|
||||
|
||||
public IModelState getState(Object obj)
|
||||
{
|
||||
Wrapper w = wrap(obj);
|
||||
if(!map.containsKey(w)) return def;
|
||||
return map.get(w);
|
||||
}
|
||||
|
||||
public static class Wrapper implements IModelPart
|
||||
{
|
||||
private final Object obj;
|
||||
|
||||
public Wrapper(Object obj)
|
||||
{
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return obj.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Wrapper other = (Wrapper)obj;
|
||||
return Objects.equal(this.obj, other.obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static Wrapper wrap(Object obj)
|
||||
{
|
||||
return new Wrapper(obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Quat4f;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.Optional;
|
||||
|
||||
import static net.minecraftforge.client.model.ModelDynBucket.LoaderDynBucket.getResource;
|
||||
|
||||
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.minecraftforge.fml.common.FMLLog;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public final class ModelDynBucket implements IModel
|
||||
{
|
||||
public static final ModelResourceLocation LOCATION = new ModelResourceLocation(new ResourceLocation(ForgeVersion.MOD_ID, "dynbucket"), "inventory");
|
||||
|
||||
// minimal Z offset to prevent depth-fighting
|
||||
private static final float NORTH_Z_COVER = 7.496f / 16f;
|
||||
private static final float SOUTH_Z_COVER = 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();
|
||||
|
||||
@Nullable
|
||||
private final ResourceLocation baseLocation;
|
||||
@Nullable
|
||||
private final ResourceLocation liquidLocation;
|
||||
@Nullable
|
||||
private final ResourceLocation coverLocation;
|
||||
@Nullable
|
||||
private final Fluid fluid;
|
||||
|
||||
private final boolean flipGas;
|
||||
private final boolean tint;
|
||||
|
||||
public ModelDynBucket()
|
||||
{
|
||||
this(null, null, null, null, false, true);
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #ModelDynBucket(ResourceLocation, ResourceLocation, ResourceLocation, Fluid, boolean, boolean)} */
|
||||
@Deprecated // TODO: remove
|
||||
public ModelDynBucket(@Nullable ResourceLocation baseLocation, @Nullable ResourceLocation liquidLocation, @Nullable ResourceLocation coverLocation, @Nullable Fluid fluid, boolean flipGas)
|
||||
{
|
||||
this(baseLocation, liquidLocation, coverLocation, fluid, flipGas, true);
|
||||
}
|
||||
|
||||
public ModelDynBucket(@Nullable ResourceLocation baseLocation, @Nullable ResourceLocation liquidLocation, @Nullable ResourceLocation coverLocation, @Nullable Fluid fluid, boolean flipGas, boolean tint)
|
||||
{
|
||||
this.baseLocation = baseLocation;
|
||||
this.liquidLocation = liquidLocation;
|
||||
this.coverLocation = coverLocation;
|
||||
this.fluid = fluid;
|
||||
this.flipGas = flipGas;
|
||||
this.tint = tint;
|
||||
}
|
||||
|
||||
@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);
|
||||
if (fluid != null)
|
||||
builder.add(fluid.getStill());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format,
|
||||
Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
|
||||
ImmutableMap<TransformType, TRSRTransformation> transformMap = PerspectiveMapWrapper.getTransforms(state);
|
||||
|
||||
// if the fluid is lighter than air, will manipulate the initial state to be rotated 180° to turn it upside down
|
||||
if (flipGas && fluid != null && fluid.isLighterThanAir())
|
||||
{
|
||||
state = new ModelStateComposition(state, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, new Quat4f(0, 0, 1, 0), null, null)));
|
||||
}
|
||||
|
||||
TRSRTransformation transform = state.apply(Optional.empty()).orElse(TRSRTransformation.identity());
|
||||
TextureAtlasSprite fluidSprite = null;
|
||||
TextureAtlasSprite particleSprite = null;
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
if(fluid != null) {
|
||||
fluidSprite = bakedTextureGetter.apply(fluid.getStill());
|
||||
}
|
||||
|
||||
if (baseLocation != null)
|
||||
{
|
||||
// build base (insidest)
|
||||
IBakedModel model = (new ItemLayerModel(ImmutableList.of(baseLocation))).bake(state, format, bakedTextureGetter);
|
||||
builder.addAll(model.getQuads(null, null, 0));
|
||||
particleSprite = model.getParticleTexture();
|
||||
}
|
||||
if (liquidLocation != null && fluidSprite != null)
|
||||
{
|
||||
TextureAtlasSprite liquid = bakedTextureGetter.apply(liquidLocation);
|
||||
// build liquid layer (inside)
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, NORTH_Z_FLUID, EnumFacing.NORTH, tint ? fluid.getColor() : 0xFFFFFFFF, 1));
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, SOUTH_Z_FLUID, EnumFacing.SOUTH, tint ? fluid.getColor() : 0xFFFFFFFF, 1));
|
||||
particleSprite = fluidSprite;
|
||||
}
|
||||
if (coverLocation != null)
|
||||
{
|
||||
// cover (the actual item around the other two)
|
||||
TextureAtlasSprite cover = bakedTextureGetter.apply(coverLocation);
|
||||
builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, NORTH_Z_COVER, cover, EnumFacing.NORTH, 0xFFFFFFFF, 2));
|
||||
builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, SOUTH_Z_COVER, cover, EnumFacing.SOUTH, 0xFFFFFFFF, 2));
|
||||
if (particleSprite == null)
|
||||
{
|
||||
particleSprite = cover;
|
||||
}
|
||||
}
|
||||
|
||||
return new BakedDynBucket(this, builder.build(), particleSprite, format, Maps.immutableEnumMap(transformMap), Maps.newHashMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fluid in the model.
|
||||
* "fluid" - Name of the fluid in the fluid registry.
|
||||
* "flipGas" - If "true" the model will be flipped upside down if the fluid is lighter than air. If "false" it won't.
|
||||
* "applyTint" - If "true" the model will tint the fluid quads according to the fluid's base color.
|
||||
* <p/>
|
||||
* If the fluid can't be found, water is used.
|
||||
*/
|
||||
@Override
|
||||
public ModelDynBucket 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));
|
||||
}
|
||||
|
||||
boolean tint = this.tint;
|
||||
if (customData.containsKey("applyTint"))
|
||||
{
|
||||
String string = customData.get("applyTint");
|
||||
switch (string)
|
||||
{
|
||||
case "true": tint = true; break;
|
||||
case "false": tint = false; break;
|
||||
default: throw new IllegalArgumentException(String.format("DynBucket custom data \"applyTint\" must have value \'true\' or \'false\' (was \'%s\')", string));
|
||||
}
|
||||
}
|
||||
|
||||
// create new model with correct liquid
|
||||
return new ModelDynBucket(baseLocation, liquidLocation, coverLocation, fluid, flip, tint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ModelDynBucket 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, tint);
|
||||
}
|
||||
|
||||
public enum LoaderDynBucket implements ICustomModelLoader
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return modelLocation.getResourceDomain().equals(ForgeVersion.MOD_ID) && modelLocation.getResourcePath().contains("forgebucket");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation)
|
||||
{
|
||||
return MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager)
|
||||
{
|
||||
// no need to clear cache since we create a new model instance
|
||||
}
|
||||
|
||||
public void register(TextureMap map)
|
||||
{
|
||||
// only create these textures if they are not added by a resource pack
|
||||
|
||||
if (getResource(new ResourceLocation(ForgeVersion.MOD_ID, "textures/items/bucket_cover.png")) == null)
|
||||
{
|
||||
ResourceLocation bucketCover = new ResourceLocation(ForgeVersion.MOD_ID, "items/bucket_cover");
|
||||
BucketCoverSprite bucketCoverSprite = new BucketCoverSprite(bucketCover);
|
||||
map.setTextureEntry(bucketCoverSprite);
|
||||
}
|
||||
|
||||
if (getResource(new ResourceLocation(ForgeVersion.MOD_ID, "textures/items/bucket_base.png")) == null)
|
||||
{
|
||||
ResourceLocation bucketBase = new ResourceLocation(ForgeVersion.MOD_ID, "items/bucket_base");
|
||||
BucketBaseSprite bucketBaseSprite = new BucketBaseSprite(bucketBase);
|
||||
map.setTextureEntry(bucketBaseSprite);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static IResource getResource(ResourceLocation resourceLocation)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Minecraft.getMinecraft().getResourceManager().getResource(resourceLocation);
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BucketBaseSprite extends TextureAtlasSprite
|
||||
{
|
||||
private final ResourceLocation bucket = new ResourceLocation("items/bucket_empty");
|
||||
private final ImmutableList<ResourceLocation> dependencies = ImmutableList.of(bucket);
|
||||
|
||||
private BucketBaseSprite(ResourceLocation resourceLocation)
|
||||
{
|
||||
super(resourceLocation.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomLoader(@Nonnull IResourceManager manager, @Nonnull ResourceLocation location)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies()
|
||||
{
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load(@Nonnull IResourceManager manager, @Nonnull ResourceLocation location, @Nonnull Function<ResourceLocation, TextureAtlasSprite> textureGetter)
|
||||
{
|
||||
final TextureAtlasSprite sprite = textureGetter.apply(bucket);
|
||||
width = sprite.getIconWidth();
|
||||
height = sprite.getIconHeight();
|
||||
final int[][] pixels = sprite.getFrameTextureData(0);
|
||||
this.clearFramesTextureData();
|
||||
this.framesTextureData.add(pixels);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a bucket cover sprite from the vanilla resource.
|
||||
*/
|
||||
private static final class BucketCoverSprite extends TextureAtlasSprite
|
||||
{
|
||||
private final ResourceLocation bucket = new ResourceLocation("items/bucket_empty");
|
||||
private final ResourceLocation bucketCoverMask = new ResourceLocation(ForgeVersion.MOD_ID, "items/vanilla_bucket_cover_mask");
|
||||
private final ImmutableList<ResourceLocation> dependencies = ImmutableList.of(bucket, bucketCoverMask);
|
||||
|
||||
private BucketCoverSprite(ResourceLocation resourceLocation)
|
||||
{
|
||||
super(resourceLocation.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomLoader(@Nonnull IResourceManager manager, @Nonnull ResourceLocation location)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies()
|
||||
{
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load(@Nonnull IResourceManager manager, @Nonnull ResourceLocation location, @Nonnull Function<ResourceLocation, TextureAtlasSprite> textureGetter)
|
||||
{
|
||||
final TextureAtlasSprite sprite = textureGetter.apply(bucket);
|
||||
final TextureAtlasSprite alphaMask = textureGetter.apply(bucketCoverMask);
|
||||
width = sprite.getIconWidth();
|
||||
height = sprite.getIconHeight();
|
||||
final int[][] pixels = new int[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1][];
|
||||
pixels[0] = new int[width * height];
|
||||
|
||||
try (
|
||||
IResource empty = getResource(new ResourceLocation("textures/items/bucket_empty.png"));
|
||||
IResource mask = getResource(new ResourceLocation(ForgeVersion.MOD_ID, "textures/items/vanilla_bucket_cover_mask.png"))
|
||||
) {
|
||||
// use the alpha mask if it fits, otherwise leave the cover texture blank
|
||||
if (empty != null && mask != null && Objects.equals(empty.getResourcePackName(), mask.getResourcePackName()) &&
|
||||
alphaMask.getIconWidth() == width && alphaMask.getIconHeight() == height)
|
||||
{
|
||||
final int[][] oldPixels = sprite.getFrameTextureData(0);
|
||||
final int[][] alphaPixels = alphaMask.getFrameTextureData(0);
|
||||
|
||||
for (int p = 0; p < width * height; p++)
|
||||
{
|
||||
final int alphaMultiplier = alphaPixels[0][p] >>> 24;
|
||||
final int oldPixel = oldPixels[0][p];
|
||||
final int oldPixelAlpha = oldPixel >>> 24;
|
||||
final int newAlpha = oldPixelAlpha * alphaMultiplier / 0xFF;
|
||||
pixels[0][p] = (oldPixel & 0xFFFFFF) + (newAlpha << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log.error("Failed to close resource", e);
|
||||
}
|
||||
|
||||
this.clearFramesTextureData();
|
||||
this.framesTextureData.add(pixels);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BakedDynBucketOverrideHandler extends ItemOverrideList
|
||||
{
|
||||
public static final BakedDynBucketOverrideHandler INSTANCE = new BakedDynBucketOverrideHandler();
|
||||
private BakedDynBucketOverrideHandler()
|
||||
{
|
||||
super(ImmutableList.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity)
|
||||
{
|
||||
FluidStack fluidStack = FluidUtil.getFluidContained(stack);
|
||||
|
||||
// not a fluid item apparently
|
||||
if (fluidStack == null)
|
||||
{
|
||||
// empty bucket
|
||||
return originalModel;
|
||||
}
|
||||
|
||||
BakedDynBucket model = (BakedDynBucket)originalModel;
|
||||
|
||||
Fluid fluid = fluidStack.getFluid();
|
||||
String name = fluid.getName();
|
||||
|
||||
if (!model.cache.containsKey(name))
|
||||
{
|
||||
IModel parent = model.parent.process(ImmutableMap.of("fluid", name));
|
||||
Function<ResourceLocation, TextureAtlasSprite> textureGetter;
|
||||
textureGetter = location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString());
|
||||
|
||||
IBakedModel bakedModel = parent.bake(new SimpleModelState(model.transforms), model.format, textureGetter);
|
||||
model.cache.put(name, bakedModel);
|
||||
return bakedModel;
|
||||
}
|
||||
|
||||
return model.cache.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
// the dynamic bucket is based on the empty bucket
|
||||
private static final class BakedDynBucket extends BakedItemModel
|
||||
{
|
||||
private final ModelDynBucket parent;
|
||||
private final Map<String, IBakedModel> cache; // contains all the baked models since they'll never change
|
||||
private final VertexFormat format;
|
||||
|
||||
public BakedDynBucket(ModelDynBucket parent,
|
||||
ImmutableList<BakedQuad> quads,
|
||||
TextureAtlasSprite particle,
|
||||
VertexFormat format,
|
||||
ImmutableMap<TransformType, TRSRTransformation> transforms,
|
||||
Map<String, IBakedModel> cache)
|
||||
{
|
||||
super(quads, particle, transforms, BakedDynBucketOverrideHandler.INSTANCE);
|
||||
this.format = format;
|
||||
this.parent = parent;
|
||||
this.cache = cache;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Vector4f;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.minecraftforge.fluids.BlockFluidBase;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
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 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;
|
||||
|
||||
public final class ModelFluid implements IModel
|
||||
{
|
||||
public static final ModelFluid WATER = new ModelFluid(FluidRegistry.WATER);
|
||||
public static final ModelFluid LAVA = new ModelFluid(FluidRegistry.LAVA);
|
||||
|
||||
private final Fluid fluid;
|
||||
|
||||
public ModelFluid(Fluid fluid)
|
||||
{
|
||||
this.fluid = fluid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
return fluid.getOverlay() != null
|
||||
? ImmutableSet.of(fluid.getStill(), fluid.getFlowing(), fluid.getOverlay())
|
||||
: ImmutableSet.of(fluid.getStill(), fluid.getFlowing());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
return new CachingBakedFluid(
|
||||
state.apply(Optional.empty()),
|
||||
PerspectiveMapWrapper.getTransforms(state),
|
||||
format,
|
||||
fluid.getColor(),
|
||||
bakedTextureGetter.apply(fluid.getStill()),
|
||||
bakedTextureGetter.apply(fluid.getFlowing()),
|
||||
Optional.ofNullable(fluid.getOverlay()).map(bakedTextureGetter),
|
||||
fluid.isLighterThanAir(),
|
||||
Optional.empty()
|
||||
);
|
||||
}
|
||||
|
||||
public enum FluidLoader implements ICustomModelLoader
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {}
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return modelLocation.getResourceDomain().equals(ForgeVersion.MOD_ID) && (
|
||||
modelLocation.getResourcePath().equals("fluid") ||
|
||||
modelLocation.getResourcePath().equals("models/block/fluid") ||
|
||||
modelLocation.getResourcePath().equals("models/item/fluid"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation)
|
||||
{
|
||||
return WATER;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CachingBakedFluid extends BakedFluid
|
||||
{
|
||||
private final LoadingCache<Long, BakedFluid> modelCache = CacheBuilder.newBuilder().maximumSize(200).build(new CacheLoader<Long, BakedFluid>()
|
||||
{
|
||||
@Override
|
||||
public BakedFluid load(Long key)
|
||||
{
|
||||
boolean statePresent = (key & 1) != 0;
|
||||
key >>>= 1;
|
||||
int[] cornerRound = new int[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
cornerRound[i] = (int) (key & 0x3FF);
|
||||
key >>>= 10;
|
||||
}
|
||||
int flowRound = (int) (key & 0x7FF) - 1024;
|
||||
key >>>= 11;
|
||||
boolean[] overlaySides = new boolean[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
overlaySides[i] = (key & 1) != 0;
|
||||
key >>>= 1;
|
||||
}
|
||||
return new BakedFluid(transformation, transforms, format, color, still, flowing, overlay, gas, statePresent, cornerRound, flowRound, overlaySides);
|
||||
}
|
||||
});
|
||||
|
||||
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)
|
||||
{
|
||||
super(transformation, transforms, format, color, still, flowing, overlay, gas, stateOption.isPresent(), getCorners(stateOption), getFlow(stateOption), getOverlay(stateOption));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quantized fluid levels for each corner.
|
||||
*
|
||||
* Each value is packed into 10 bits of the model key, so max range is [0,1024).
|
||||
* The value is currently stored/interpreted as the closest multiple of 1/864.
|
||||
* The divisor is chosen here to allows likely flow values to be exactly representable
|
||||
* 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)
|
||||
{
|
||||
int[] cornerRound = {0, 0, 0, 0};
|
||||
if (stateOption.isPresent())
|
||||
{
|
||||
IExtendedBlockState state = stateOption.get();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Float level = state.getValue(BlockFluidBase.LEVEL_CORNERS[i]);
|
||||
cornerRound[i] = Math.round((level == null ? 8f / 9f : level) * 864);
|
||||
}
|
||||
}
|
||||
return cornerRound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quantized flow direction of the fluid.
|
||||
*
|
||||
* This value comprises 11 bits of the model key, and is signed, so the max range is [-1024,1024).
|
||||
* 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)
|
||||
{
|
||||
Float flow = -1000f;
|
||||
if (stateOption.isPresent())
|
||||
{
|
||||
flow = stateOption.get().getValue(BlockFluidBase.FLOW_DIRECTION);
|
||||
if (flow == null) flow = -1000f;
|
||||
}
|
||||
int flowRound = (int) Math.round(Math.toDegrees(flow));
|
||||
flowRound = MathHelper.clamp(flowRound, -1000, 1000);
|
||||
return flowRound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the overlay texture flag for each side.
|
||||
*
|
||||
* This value determines if the fluid "overlay" texture should be used for that side,
|
||||
* 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)
|
||||
{
|
||||
boolean[] overlaySides = new boolean[4];
|
||||
if (stateOption.isPresent())
|
||||
{
|
||||
IExtendedBlockState state = stateOption.get();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Boolean overlay = state.getValue(BlockFluidBase.SIDE_OVERLAYS[i]);
|
||||
if (overlay != null) overlaySides[i] = overlay;
|
||||
}
|
||||
}
|
||||
return overlaySides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
if (side != null && state instanceof IExtendedBlockState)
|
||||
{
|
||||
Optional<IExtendedBlockState> exState = Optional.of((IExtendedBlockState)state);
|
||||
|
||||
int[] cornerRound = getCorners(exState);
|
||||
int flowRound = getFlow(exState);
|
||||
boolean[] overlaySides = getOverlay(exState);
|
||||
|
||||
long key = 0L;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
key <<= 1;
|
||||
key |= overlaySides[i] ? 1 : 0;
|
||||
}
|
||||
key <<= 11;
|
||||
key |= flowRound + 1024;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
key <<= 10;
|
||||
key |= cornerRound[i];
|
||||
}
|
||||
key <<= 1;
|
||||
key |= 1;
|
||||
|
||||
return modelCache.getUnchecked(key).getQuads(state, side, rand);
|
||||
}
|
||||
|
||||
return super.getQuads(state, side, rand);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BakedFluid implements IBakedModel
|
||||
{
|
||||
private static final int x[] = { 0, 0, 1, 1 };
|
||||
private static final int z[] = { 0, 1, 1, 0 };
|
||||
private static final float eps = 1e-3f;
|
||||
|
||||
protected final Optional<TRSRTransformation> transformation;
|
||||
protected final ImmutableMap<TransformType, TRSRTransformation> transforms;
|
||||
protected final VertexFormat format;
|
||||
protected final int color;
|
||||
protected final TextureAtlasSprite still, flowing;
|
||||
protected final Optional<TextureAtlasSprite> overlay;
|
||||
protected final boolean gas;
|
||||
protected final ImmutableMap<EnumFacing, ImmutableList<BakedQuad>> faceQuads;
|
||||
|
||||
public BakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional<TextureAtlasSprite> overlay, boolean gas, boolean statePresent, int[] cornerRound, int flowRound, boolean[] sideOverlays)
|
||||
{
|
||||
this.transformation = transformation;
|
||||
this.transforms = transforms;
|
||||
this.format = format;
|
||||
this.color = color;
|
||||
this.still = still;
|
||||
this.flowing = flowing;
|
||||
this.overlay = overlay;
|
||||
this.gas = gas;
|
||||
this.faceQuads = buildQuads(statePresent, cornerRound, flowRound, sideOverlays);
|
||||
}
|
||||
|
||||
private ImmutableMap<EnumFacing, ImmutableList<BakedQuad>> buildQuads(boolean statePresent, int[] cornerRound, int flowRound, boolean[] sideOverlays)
|
||||
{
|
||||
EnumMap<EnumFacing, ImmutableList<BakedQuad>> faceQuads = new EnumMap<>(EnumFacing.class);
|
||||
for (EnumFacing side : EnumFacing.values())
|
||||
{
|
||||
faceQuads.put(side, ImmutableList.of());
|
||||
}
|
||||
|
||||
if (statePresent)
|
||||
{
|
||||
// y levels
|
||||
float[] y = new float[4];
|
||||
boolean fullVolume = true;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float value = cornerRound[i] / 864f;
|
||||
if (value < 1f) fullVolume = false;
|
||||
y[i] = gas ? 1f - value : value;
|
||||
}
|
||||
|
||||
// flow
|
||||
boolean isFlowing = flowRound > -1000;
|
||||
|
||||
float flow = isFlowing ? (float) Math.toRadians(flowRound) : 0f;
|
||||
TextureAtlasSprite topSprite = isFlowing ? flowing : still;
|
||||
float scale = isFlowing ? 4f : 8f;
|
||||
|
||||
float c = MathHelper.cos(flow) * scale;
|
||||
float s = MathHelper.sin(flow) * scale;
|
||||
|
||||
// top
|
||||
EnumFacing top = gas ? EnumFacing.DOWN : EnumFacing.UP;
|
||||
|
||||
// base uv offset for flow direction
|
||||
VertexParameter uv = i -> c * (x[i] * 2 - 1) + s * (z[i] * 2 - 1);
|
||||
|
||||
VertexParameter topX = i -> x[i];
|
||||
VertexParameter topY = i -> y[i];
|
||||
VertexParameter topZ = i -> z[i];
|
||||
VertexParameter topU = i -> 8 + uv.get(i);
|
||||
VertexParameter topV = i -> 8 + uv.get((i + 1) % 4);
|
||||
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
builder.add(buildQuad(top, topSprite, gas, false, topX, topY, topZ, topU, topV));
|
||||
if (!fullVolume) builder.add(buildQuad(top, topSprite, !gas, true, topX, topY, topZ, topU, topV));
|
||||
|
||||
faceQuads.put(top, builder.build());
|
||||
}
|
||||
|
||||
// bottom
|
||||
EnumFacing bottom = top.getOpposite();
|
||||
faceQuads.put(bottom, ImmutableList.of(
|
||||
buildQuad(bottom, still, gas, false,
|
||||
i -> z[i],
|
||||
i -> gas ? 1 : 0,
|
||||
i -> x[i],
|
||||
i -> z[i] * 16,
|
||||
i -> x[i] * 16
|
||||
)
|
||||
));
|
||||
|
||||
// sides
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
EnumFacing side = EnumFacing.getHorizontal((5 - i) % 4); // [W, S, E, N]
|
||||
boolean useOverlay = overlay.isPresent() && sideOverlays[side.getHorizontalIndex()];
|
||||
int si = i; // local var for lambda capture
|
||||
|
||||
VertexParameter sideX = j -> x[(si + x[j]) % 4];
|
||||
VertexParameter sideY = j -> z[j] == 0 ? (gas ? 1 : 0) : y[(si + x[j]) % 4];
|
||||
VertexParameter sideZ = j -> z[(si + x[j]) % 4];
|
||||
VertexParameter sideU = j -> x[j] * 8;
|
||||
VertexParameter sideV = j -> (gas ? sideY.get(j) : 1 - sideY.get(j)) * 8;
|
||||
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
if (!useOverlay) builder.add(buildQuad(side, flowing, gas, true, sideX, sideY, sideZ, sideU, sideV));
|
||||
builder.add(buildQuad(side, useOverlay ? overlay.get() : flowing, !gas, false, sideX, sideY, sideZ, sideU, sideV));
|
||||
|
||||
faceQuads.put(side, builder.build());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// inventory
|
||||
faceQuads.put(EnumFacing.SOUTH, ImmutableList.of(
|
||||
buildQuad(EnumFacing.UP, still, false, false,
|
||||
i -> z[i],
|
||||
i -> x[i],
|
||||
i -> 0,
|
||||
i -> z[i] * 16,
|
||||
i -> x[i] * 16
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
return ImmutableMap.copyOf(faceQuads);
|
||||
}
|
||||
|
||||
// maps vertex index to parameter value
|
||||
private interface VertexParameter
|
||||
{
|
||||
float get(int index);
|
||||
}
|
||||
|
||||
private BakedQuad buildQuad(EnumFacing side, TextureAtlasSprite texture, boolean flip, boolean offset, VertexParameter x, VertexParameter y, VertexParameter z, VertexParameter u, VertexParameter v)
|
||||
{
|
||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(texture);
|
||||
builder.setQuadTint(0);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int vertex = flip ? 3 - i : i;
|
||||
putVertex(
|
||||
builder, side, offset,
|
||||
x.get(vertex), y.get(vertex), z.get(vertex),
|
||||
texture.getInterpolatedU(u.get(vertex)),
|
||||
texture.getInterpolatedV(v.get(vertex))
|
||||
);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void putVertex(UnpackedBakedQuad.Builder builder, EnumFacing side, boolean offset, float x, float y, float z, float u, float v)
|
||||
{
|
||||
for(int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
switch(format.getElement(e).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
float dx = offset ? side.getDirectionVec().getX() * eps : 0f;
|
||||
float dy = offset ? side.getDirectionVec().getY() * eps : 0f;
|
||||
float dz = offset ? side.getDirectionVec().getZ() * eps : 0f;
|
||||
float[] data = { x - dx, y - dy, z - dz, 1f };
|
||||
if(transformation.isPresent() && !transformation.get().isIdentity())
|
||||
{
|
||||
Vector4f vec = new Vector4f(data);
|
||||
transformation.get().getMatrix().transform(vec);
|
||||
vec.get(data);
|
||||
}
|
||||
builder.put(e, data);
|
||||
break;
|
||||
case COLOR:
|
||||
builder.put(e,
|
||||
((color >> 16) & 0xFF) / 255f,
|
||||
((color >> 8) & 0xFF) / 255f,
|
||||
(color & 0xFF) / 255f,
|
||||
((color >> 24) & 0xFF) / 255f);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return still;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
return side == null ? ImmutableList.of() : faceQuads.get(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return ItemOverrideList.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType type)
|
||||
{
|
||||
return PerspectiveMapWrapper.handlePerspective(this, transforms, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelFluid process(ImmutableMap<String, String> customData)
|
||||
{
|
||||
if(!customData.containsKey("fluid")) return this;
|
||||
|
||||
String fluidStr = customData.get("fluid");
|
||||
JsonElement e = new JsonParser().parse(fluidStr);
|
||||
String fluid = e.getAsString();
|
||||
if(!FluidRegistry.isFluidRegistered(fluid))
|
||||
{
|
||||
FMLLog.log.fatal("fluid '{}' not found", fluid);
|
||||
return WATER;
|
||||
}
|
||||
return new ModelFluid(FluidRegistry.getFluid(fluid));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ModelLoader.VanillaLoader;
|
||||
import net.minecraftforge.client.model.ModelLoader.VariantLoader;
|
||||
import net.minecraftforge.client.model.b3d.B3DLoader;
|
||||
import net.minecraftforge.client.model.obj.OBJLoader;
|
||||
import net.minecraftforge.common.animation.ITimeValue;
|
||||
import net.minecraftforge.common.model.animation.AnimationStateMachine;
|
||||
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Queues;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/*
|
||||
* Central hub for custom model loaders.
|
||||
*/
|
||||
public class ModelLoaderRegistry
|
||||
{
|
||||
private static final Set<ICustomModelLoader> loaders = Sets.newHashSet();
|
||||
private static final Map<ResourceLocation, IModel> cache = Maps.newHashMap();
|
||||
private static final Deque<ResourceLocation> loadingModels = Queues.newArrayDeque();
|
||||
private static final Set<ResourceLocation> textures = Sets.newHashSet();
|
||||
private static IResourceManager manager;
|
||||
|
||||
// Forge built-in loaders
|
||||
static
|
||||
{
|
||||
registerLoader(B3DLoader.INSTANCE);
|
||||
registerLoader(OBJLoader.INSTANCE);
|
||||
registerLoader(ModelFluid.FluidLoader.INSTANCE);
|
||||
registerLoader(ItemLayerModel.Loader.INSTANCE);
|
||||
registerLoader(MultiLayerModel.Loader.INSTANCE);
|
||||
registerLoader(ModelDynBucket.LoaderDynBucket.INSTANCE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes system aware of your loader.
|
||||
*/
|
||||
public static void registerLoader(ICustomModelLoader loader)
|
||||
{
|
||||
loaders.add(loader);
|
||||
((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(loader);
|
||||
}
|
||||
|
||||
public static boolean loaded(ResourceLocation location)
|
||||
{
|
||||
return cache.containsKey(location);
|
||||
}
|
||||
|
||||
|
||||
public static ResourceLocation getActualLocation(ResourceLocation location)
|
||||
{
|
||||
if(location instanceof ModelResourceLocation) return location;
|
||||
if(location.getResourcePath().startsWith("builtin/")) return location;
|
||||
return new ResourceLocation(location.getResourceDomain(), "models/" + location.getResourcePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary method to get IModel instances.
|
||||
* ResourceLocation argument will be passed directly to the custom model loaders,
|
||||
* ModelResourceLocation argument will be loaded through the blockstate system.
|
||||
*/
|
||||
public static IModel getModel(ResourceLocation location) throws Exception
|
||||
{
|
||||
IModel model;
|
||||
if(cache.containsKey(location)) return cache.get(location);
|
||||
for(ResourceLocation loading : loadingModels)
|
||||
{
|
||||
if(location.getClass() == loading.getClass() && location.equals(loading))
|
||||
{
|
||||
throw new LoaderException("circular model dependencies, stack: [" + Joiner.on(", ").join(loadingModels) + "]");
|
||||
}
|
||||
}
|
||||
loadingModels.addLast(location);
|
||||
try
|
||||
{
|
||||
ResourceLocation actual = getActualLocation(location);
|
||||
ICustomModelLoader accepted = null;
|
||||
for(ICustomModelLoader loader : loaders)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(loader.accepts(actual))
|
||||
{
|
||||
if(accepted != null)
|
||||
{
|
||||
throw new LoaderException(String.format("2 loaders (%s and %s) want to load the same model %s", accepted, loader, location));
|
||||
}
|
||||
accepted = loader;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new LoaderException(String.format("Exception checking if model %s can be loaded with loader %s, skipping", location, loader), e);
|
||||
}
|
||||
}
|
||||
|
||||
// no custom loaders found, try vanilla ones
|
||||
if(accepted == null)
|
||||
{
|
||||
if(VariantLoader.INSTANCE.accepts(actual))
|
||||
{
|
||||
accepted = VariantLoader.INSTANCE;
|
||||
}
|
||||
else if(VanillaLoader.INSTANCE.accepts(actual))
|
||||
{
|
||||
accepted = VanillaLoader.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
if(accepted == null)
|
||||
{
|
||||
throw new LoaderException("no suitable loader found for the model " + location + ", skipping");
|
||||
}
|
||||
try
|
||||
{
|
||||
model = accepted.loadModel(actual);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new LoaderException(String.format("Exception loading model %s with loader %s, skipping", location, accepted), e);
|
||||
}
|
||||
if(model == getMissingModel())
|
||||
{
|
||||
throw new LoaderException(String.format("Loader %s returned missing model while loading model %s", accepted, location));
|
||||
}
|
||||
if(model == null)
|
||||
{
|
||||
throw new LoaderException(String.format("Loader %s returned null while loading model %s", accepted, location));
|
||||
}
|
||||
textures.addAll(model.getTextures());
|
||||
}
|
||||
finally
|
||||
{
|
||||
ResourceLocation popLoc = loadingModels.removeLast();
|
||||
if(popLoc != location)
|
||||
{
|
||||
throw new IllegalStateException("Corrupted loading model stack: " + popLoc + " != " + location);
|
||||
}
|
||||
}
|
||||
cache.put(location, model);
|
||||
for (ResourceLocation dep : model.getDependencies())
|
||||
{
|
||||
getModelOrMissing(dep);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this if you don't care about the exception and want some model anyway.
|
||||
*/
|
||||
public static IModel getModelOrMissing(ResourceLocation location)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getModel(location);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
return getMissingModel(location, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this if you want the model, but need to log the error.
|
||||
*/
|
||||
public static IModel getModelOrLogError(ResourceLocation location, String error)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getModel(location);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
FMLLog.log.error(error, e);
|
||||
return getMissingModel(location, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static IModel getMissingModel()
|
||||
{
|
||||
final ModelLoader loader = VanillaLoader.INSTANCE.getLoader();
|
||||
if(loader == null)
|
||||
{
|
||||
throw new IllegalStateException("Using ModelLoaderRegistry too early.");
|
||||
}
|
||||
return loader.getMissingModel();
|
||||
}
|
||||
|
||||
static IModel getMissingModel(ResourceLocation location, Throwable cause)
|
||||
{
|
||||
//IModel model = new FancyMissingModel(ExceptionUtils.getStackTrace(cause).replaceAll("\\t", " "));
|
||||
IModel model = new FancyMissingModel(getMissingModel(), location.toString());
|
||||
textures.addAll(model.getTextures());
|
||||
return model;
|
||||
}
|
||||
|
||||
public static void clearModelCache(IResourceManager manager)
|
||||
{
|
||||
ModelLoaderRegistry.manager = manager;
|
||||
cache.clear();
|
||||
// putting the builtin models in
|
||||
cache.put(new ResourceLocation("minecraft:builtin/generated"), ItemLayerModel.INSTANCE);
|
||||
cache.put(new ResourceLocation("minecraft:block/builtin/generated"), ItemLayerModel.INSTANCE);
|
||||
cache.put(new ResourceLocation("minecraft:item/builtin/generated"), ItemLayerModel.INSTANCE);
|
||||
}
|
||||
|
||||
static Iterable<ResourceLocation> getTextures()
|
||||
{
|
||||
return textures;
|
||||
}
|
||||
|
||||
public static class LoaderException extends Exception
|
||||
{
|
||||
public LoaderException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LoaderException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
public static IAnimationStateMachine loadASM(ResourceLocation location, ImmutableMap<String, ITimeValue> customParameters)
|
||||
{
|
||||
return AnimationStateMachine.load(manager, location, customParameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import net.minecraftforge.common.model.IModelPart;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ModelStateComposition implements IModelState
|
||||
{
|
||||
private final IModelState first;
|
||||
private final IModelState second;
|
||||
|
||||
public ModelStateComposition(IModelState first, IModelState second)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
||||
{
|
||||
Optional<TRSRTransformation> f = first.apply(part), s = second.apply(part);
|
||||
if(f.isPresent() && s.isPresent())
|
||||
{
|
||||
return Optional.of(f.get().compose(s.get()));
|
||||
}
|
||||
if (f.isPresent()) {
|
||||
return f;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ModelStateComposition that = (ModelStateComposition) o;
|
||||
return Objects.equal(first, that.first) && Objects.equal(second, that.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(first, second);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
public final class MultiLayerModel implements IModel
|
||||
{
|
||||
public static final MultiLayerModel INSTANCE = new MultiLayerModel(ImmutableMap.of());
|
||||
|
||||
private final ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models;
|
||||
|
||||
public MultiLayerModel(ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models)
|
||||
{
|
||||
this.models = models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies()
|
||||
{
|
||||
return ImmutableList.copyOf(models.values());
|
||||
}
|
||||
|
||||
private static ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> buildModels(ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
ImmutableMap.Builder<Optional<BlockRenderLayer>, IBakedModel> builder = ImmutableMap.builder();
|
||||
for(Optional<BlockRenderLayer> key : models.keySet())
|
||||
{
|
||||
IModel model = ModelLoaderRegistry.getModelOrLogError(models.get(key), "Couldn't load MultiLayerModel dependency: " + models.get(key));
|
||||
builder.put(key, model.bake(new ModelStateComposition(state, model.getDefaultState()), format, bakedTextureGetter));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
IModel missing = ModelLoaderRegistry.getMissingModel();
|
||||
return new MultiLayerBakedModel(
|
||||
buildModels(models, state, format, bakedTextureGetter),
|
||||
missing.bake(missing.getDefaultState(), format, bakedTextureGetter),
|
||||
PerspectiveMapWrapper.getTransforms(state)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiLayerModel process(ImmutableMap<String, String> customData)
|
||||
{
|
||||
ImmutableMap.Builder<Optional<BlockRenderLayer>, ModelResourceLocation> builder = ImmutableMap.builder();
|
||||
for(String key : customData.keySet())
|
||||
{
|
||||
if("base".equals(key))
|
||||
{
|
||||
builder.put(Optional.empty(), getLocation(customData.get(key)));
|
||||
}
|
||||
for(BlockRenderLayer layer : BlockRenderLayer.values())
|
||||
{
|
||||
if(layer.toString().equals(key))
|
||||
{
|
||||
builder.put(Optional.of(layer), getLocation(customData.get(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models = builder.build();
|
||||
if(models.isEmpty()) return INSTANCE;
|
||||
return new MultiLayerModel(models);
|
||||
}
|
||||
|
||||
private ModelResourceLocation getLocation(String json)
|
||||
{
|
||||
JsonElement e = new JsonParser().parse(json);
|
||||
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isString())
|
||||
{
|
||||
return new ModelResourceLocation(e.getAsString());
|
||||
}
|
||||
FMLLog.log.fatal("Expect ModelResourceLocation, got: {}", json);
|
||||
return new ModelResourceLocation("builtin/missing", "missing");
|
||||
}
|
||||
|
||||
private static final class MultiLayerBakedModel implements IBakedModel
|
||||
{
|
||||
private final ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models;
|
||||
private final ImmutableMap<TransformType, TRSRTransformation> cameraTransforms;
|
||||
private final IBakedModel base;
|
||||
private final IBakedModel missing;
|
||||
|
||||
public MultiLayerBakedModel(ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models, IBakedModel missing, ImmutableMap<TransformType, TRSRTransformation> cameraTransforms)
|
||||
{
|
||||
this.models = models;
|
||||
this.cameraTransforms = cameraTransforms;
|
||||
this.missing = missing;
|
||||
this.base = models.getOrDefault(Optional.empty(), missing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
BlockRenderLayer layer = MinecraftForgeClient.getRenderLayer();
|
||||
if (layer == null)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
for (IBakedModel model : models.values())
|
||||
{
|
||||
builder.addAll(model.getQuads(state, side, rand));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
// assumes that child model will handle this state properly. FIXME?
|
||||
return models.getOrDefault(Optional.of(layer), missing).getQuads(state, side, rand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return base.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion(IBlockState state)
|
||||
{
|
||||
return base.isAmbientOcclusion(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return base.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return base.isBuiltInRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return base.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
|
||||
{
|
||||
return PerspectiveMapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return ItemOverrideList.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Loader implements ICustomModelLoader
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {}
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return modelLocation.getResourceDomain().equals(ForgeVersion.MOD_ID) && (
|
||||
modelLocation.getResourcePath().equals("multi-layer") ||
|
||||
modelLocation.getResourcePath().equals("models/block/multi-layer") ||
|
||||
modelLocation.getResourcePath().equals("models/item/multi-layer"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation)
|
||||
{
|
||||
return MultiLayerModel.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.function.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
// TODO: Switch to vanilla class, or to something similar
|
||||
@Deprecated
|
||||
public final class MultiModel implements IModel
|
||||
{
|
||||
private static final class Baked implements IBakedModel
|
||||
{
|
||||
private final ResourceLocation location;
|
||||
@Nullable
|
||||
private final IBakedModel base;
|
||||
private final ImmutableMap<String, IBakedModel> parts;
|
||||
|
||||
private final IBakedModel internalBase;
|
||||
private final ImmutableMap<TransformType, Pair<Baked, TRSRTransformation>> transforms;
|
||||
private final ItemOverrideList overrides = new ItemOverrideList(Lists.newArrayList())
|
||||
{
|
||||
@Override
|
||||
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity)
|
||||
{
|
||||
if(originalModel != Baked.this)
|
||||
{
|
||||
return originalModel;
|
||||
}
|
||||
boolean dirty = false;
|
||||
IBakedModel newBase = null;
|
||||
|
||||
if(base != null)
|
||||
{
|
||||
newBase = base.getOverrides().handleItemState(base, stack, world, entity);
|
||||
if(base != newBase)
|
||||
{
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
ImmutableMap.Builder<String, IBakedModel> builder = ImmutableMap.builder();
|
||||
for(Map.Entry<String, IBakedModel> entry : parts.entrySet())
|
||||
{
|
||||
IBakedModel newPart = entry.getValue().getOverrides().handleItemState(entry.getValue(), stack, world, entity);
|
||||
builder.put(entry.getKey(), newPart);
|
||||
if(entry.getValue() != newPart)
|
||||
{
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
if(dirty)
|
||||
{
|
||||
// TODO: caching?
|
||||
return new Baked(location, true, newBase, builder.build());
|
||||
}
|
||||
return Baked.this;
|
||||
}
|
||||
};
|
||||
|
||||
public Baked(ResourceLocation location, boolean perspective, @Nullable IBakedModel base, ImmutableMap<String, IBakedModel> parts)
|
||||
{
|
||||
this.location = location;
|
||||
this.base = base;
|
||||
this.parts = parts;
|
||||
|
||||
if (base != null)
|
||||
internalBase = base;
|
||||
else
|
||||
{
|
||||
Iterator<IBakedModel> iter = parts.values().iterator();
|
||||
if (iter.hasNext())
|
||||
internalBase = iter.next();
|
||||
else
|
||||
throw new IllegalArgumentException("No base model or submodel provided for MultiModel.Baked " + location + ".");
|
||||
}
|
||||
|
||||
// Only changes the base model based on perspective, may recurse for parts in the future.
|
||||
if(base != null && perspective)
|
||||
{
|
||||
EnumMap<TransformType, Pair<Baked, TRSRTransformation>> map = new EnumMap<>(TransformType.class);
|
||||
for(TransformType type : TransformType.values())
|
||||
{
|
||||
Pair<? extends IBakedModel, Matrix4f> p = base.handlePerspective(type);
|
||||
IBakedModel newBase = p.getLeft();
|
||||
Matrix4f matrix = p.getRight();
|
||||
if (newBase != base || matrix != null)
|
||||
{
|
||||
map.put(type, Pair.of(new Baked(location, false, newBase, parts), new TRSRTransformation(matrix)));
|
||||
}
|
||||
}
|
||||
transforms = ImmutableMap.copyOf(map);
|
||||
}
|
||||
else
|
||||
{
|
||||
transforms = ImmutableMap.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return internalBase.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion(IBlockState state)
|
||||
{
|
||||
return internalBase.isAmbientOcclusion(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return internalBase.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return internalBase.isBuiltInRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return internalBase.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCameraTransforms getItemCameraTransforms()
|
||||
{
|
||||
return internalBase.getItemCameraTransforms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> quads = ImmutableList.builder();
|
||||
if (base != null)
|
||||
{
|
||||
quads.addAll(base.getQuads(state, side, rand));
|
||||
}
|
||||
for (IBakedModel bakedPart : parts.values())
|
||||
{
|
||||
quads.addAll(bakedPart.getQuads(state, side, rand));
|
||||
}
|
||||
return quads.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
|
||||
{
|
||||
Pair<Baked, TRSRTransformation> p = transforms.get(cameraTransformType);
|
||||
if (p == null) return Pair.of(this, null);
|
||||
return Pair.of(p.getLeft(), p.getRight().getMatrix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return overrides;
|
||||
}
|
||||
}
|
||||
|
||||
private final ResourceLocation location;
|
||||
@Nullable
|
||||
private final IModel base;
|
||||
private final Map<String, Pair<IModel, IModelState>> parts;
|
||||
|
||||
// TODO 1.13 remove, kept for binary compatibility
|
||||
@Deprecated
|
||||
public MultiModel(ResourceLocation location, @Nullable IModel base, IModelState baseState, ImmutableMap<String, Pair<IModel, IModelState>> parts)
|
||||
{
|
||||
this(location, base, parts);
|
||||
}
|
||||
|
||||
public MultiModel(ResourceLocation location, @Nullable IModel base, ImmutableMap<String, Pair<IModel, IModelState>> parts)
|
||||
{
|
||||
this.location = location;
|
||||
this.base = base;
|
||||
this.parts = parts;
|
||||
}
|
||||
|
||||
// TODO 1.13 remove, kept for binary compatibility
|
||||
@Deprecated
|
||||
public MultiModel(ResourceLocation location, IModel base, IModelState baseState, Map<String, Pair<IModel, IModelState>> parts)
|
||||
{
|
||||
this(location, base, parts);
|
||||
}
|
||||
|
||||
public MultiModel(ResourceLocation location, IModel base, Map<String, Pair<IModel, IModelState>> parts)
|
||||
{
|
||||
this(location, base, ImmutableMap.copyOf(parts));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies()
|
||||
{
|
||||
Set<ResourceLocation> deps = Sets.newHashSet();
|
||||
|
||||
if (base != null)
|
||||
deps.addAll(base.getDependencies());
|
||||
|
||||
for (Pair<IModel, IModelState> pair : parts.values())
|
||||
deps.addAll(pair.getLeft().getDependencies());
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
Set<ResourceLocation> deps = Sets.newHashSet();
|
||||
|
||||
if (base != null)
|
||||
deps.addAll(base.getTextures());
|
||||
|
||||
for (Pair<IModel, IModelState> pair : parts.values())
|
||||
deps.addAll(pair.getLeft().getTextures());
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
IBakedModel bakedBase = null;
|
||||
|
||||
if (base != null)
|
||||
bakedBase = base.bake(state, format, bakedTextureGetter);
|
||||
|
||||
ImmutableMap.Builder<String, IBakedModel> mapBuilder = ImmutableMap.builder();
|
||||
|
||||
for (Entry<String, Pair<IModel, IModelState>> entry : parts.entrySet())
|
||||
{
|
||||
Pair<IModel, IModelState> pair = entry.getValue();
|
||||
mapBuilder.put(entry.getKey(), pair.getLeft().bake(new ModelStateComposition(state, pair.getRight()), format, bakedTextureGetter));
|
||||
}
|
||||
|
||||
if(bakedBase == null && parts.isEmpty())
|
||||
{
|
||||
FMLLog.log.error("MultiModel {} is empty (no base model or parts were provided/resolved)", location);
|
||||
IModel missing = ModelLoaderRegistry.getMissingModel();
|
||||
return missing.bake(missing.getDefaultState(), format, bakedTextureGetter);
|
||||
}
|
||||
return new Baked(location, true, bakedBase, mapBuilder.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import net.minecraftforge.common.model.IModelPart;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import java.util.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public final class MultiModelState implements IModelState
|
||||
{
|
||||
private final ImmutableMap<MultiModelPart, ? extends IModelState> states;
|
||||
|
||||
public <M extends IModel, S extends IModelState> MultiModelState(ImmutableList<Pair<M, S>> states)
|
||||
{
|
||||
ImmutableMap.Builder<MultiModelPart, S> builder = ImmutableMap.builder();
|
||||
for(int i = 0; i < states.size(); i++)
|
||||
{
|
||||
Pair<M, S> pair = states.get(i);
|
||||
builder.put(new MultiModelPart(pair.getLeft(), i), pair.getRight());
|
||||
}
|
||||
this.states = builder.build();
|
||||
}
|
||||
|
||||
public static IModelState getPartState(IModelState state, IModel model, int index)
|
||||
{
|
||||
if(state.apply(Optional.of(new MultiModelPart(model, index))).isPresent())
|
||||
{
|
||||
return new PartState(state, model, index);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
||||
{
|
||||
if(part.isPresent())
|
||||
{
|
||||
if(part.get() instanceof MultiModelPart)
|
||||
{
|
||||
MultiModelPart key = (MultiModelPart)part.get();
|
||||
if(states.containsKey(key))
|
||||
{
|
||||
return Optional.of(states.get(key).apply(Optional.empty()).orElse(TRSRTransformation.identity()));
|
||||
}
|
||||
}
|
||||
else if(part.get() instanceof PartPart)
|
||||
{
|
||||
PartPart partPart = (PartPart)part.get();
|
||||
MultiModelPart key = new MultiModelPart(partPart.model, partPart.index);
|
||||
if(states.containsKey(key))
|
||||
{
|
||||
return states.get(key).apply(partPart.part);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static class PartState implements IModelState
|
||||
{
|
||||
private final IModelState state;
|
||||
private final IModel model;
|
||||
private final int index;
|
||||
|
||||
public PartState(IModelState state, IModel model, int index)
|
||||
{
|
||||
this.state = state;
|
||||
this.model = model;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
||||
{
|
||||
Optional<TRSRTransformation> normal = state.apply(part);
|
||||
Optional<TRSRTransformation> multi = state.apply(Optional.of(new PartPart(model, index, part)));
|
||||
if(normal.isPresent() && multi.isPresent())
|
||||
{
|
||||
return Optional.of(normal.get().compose(multi.get()));
|
||||
}
|
||||
if (normal.isPresent()) {
|
||||
return normal;
|
||||
}
|
||||
return multi;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MultiModelPart implements IModelPart
|
||||
{
|
||||
private final IModel model;
|
||||
private final int index;
|
||||
|
||||
public MultiModelPart(IModel model, int index)
|
||||
{
|
||||
this.model = model;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(model, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
MultiModelPart other = (MultiModelPart)obj;
|
||||
return Objects.equal(this.model, other.model) && this.index == other.index;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PartPart implements IModelPart
|
||||
{
|
||||
private final IModel model;
|
||||
private final int index;
|
||||
private final Optional<? extends IModelPart> part;
|
||||
|
||||
public PartPart(IModel model, int index, Optional<? extends IModelPart> part)
|
||||
{
|
||||
this.model = model;
|
||||
this.index = index;
|
||||
this.part = part;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import java.util.List;
|
||||
|
||||
public class PerspectiveMapWrapper implements IBakedModel
|
||||
{
|
||||
private final IBakedModel parent;
|
||||
private final ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms;
|
||||
|
||||
public PerspectiveMapWrapper(IBakedModel parent, ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.transforms = transforms;
|
||||
}
|
||||
|
||||
public PerspectiveMapWrapper(IBakedModel parent, IModelState state)
|
||||
{
|
||||
this(parent, getTransforms(state));
|
||||
}
|
||||
|
||||
public static ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> getTransforms(IModelState state)
|
||||
{
|
||||
EnumMap<ItemCameraTransforms.TransformType, TRSRTransformation> map = new EnumMap<>(ItemCameraTransforms.TransformType.class);
|
||||
for(ItemCameraTransforms.TransformType type : ItemCameraTransforms.TransformType.values())
|
||||
{
|
||||
Optional<TRSRTransformation> tr = state.apply(Optional.of(type));
|
||||
if(tr.isPresent())
|
||||
{
|
||||
map.put(type, tr.get());
|
||||
}
|
||||
}
|
||||
return ImmutableMap.copyOf(map);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> getTransforms(ItemCameraTransforms transforms)
|
||||
{
|
||||
EnumMap<ItemCameraTransforms.TransformType, TRSRTransformation> map = new EnumMap<>(ItemCameraTransforms.TransformType.class);
|
||||
for(ItemCameraTransforms.TransformType type : ItemCameraTransforms.TransformType.values())
|
||||
{
|
||||
if (transforms.hasCustomTransform(type))
|
||||
{
|
||||
map.put(type, TRSRTransformation.blockCenterToCorner(TRSRTransformation.from(transforms.getTransform(type))));
|
||||
}
|
||||
}
|
||||
return ImmutableMap.copyOf(map);
|
||||
}
|
||||
|
||||
public static Pair<? extends IBakedModel, Matrix4f> handlePerspective(IBakedModel model, ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms, ItemCameraTransforms.TransformType cameraTransformType)
|
||||
{
|
||||
TRSRTransformation tr = transforms.getOrDefault(cameraTransformType, TRSRTransformation.identity());
|
||||
if (!tr.isIdentity())
|
||||
{
|
||||
return Pair.of(model, TRSRTransformation.blockCornerToCenter(tr).getMatrix());
|
||||
}
|
||||
return Pair.of(model, null);
|
||||
}
|
||||
|
||||
public static Pair<? extends IBakedModel, Matrix4f> handlePerspective(IBakedModel model, IModelState state, ItemCameraTransforms.TransformType cameraTransformType)
|
||||
{
|
||||
TRSRTransformation tr = state.apply(Optional.of(cameraTransformType)).orElse(TRSRTransformation.identity());
|
||||
if (!tr.isIdentity())
|
||||
{
|
||||
return Pair.of(model, TRSRTransformation.blockCornerToCenter(tr).getMatrix());
|
||||
}
|
||||
return Pair.of(model, null);
|
||||
}
|
||||
|
||||
@Override public boolean isAmbientOcclusion() { return parent.isAmbientOcclusion(); }
|
||||
@Override public boolean isAmbientOcclusion(IBlockState state) { return parent.isAmbientOcclusion(state); }
|
||||
@Override public boolean isGui3d() { return parent.isGui3d(); }
|
||||
@Override public boolean isBuiltInRenderer() { return parent.isBuiltInRenderer(); }
|
||||
@Override public TextureAtlasSprite getParticleTexture() { return parent.getParticleTexture(); }
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override public ItemCameraTransforms getItemCameraTransforms() { return parent.getItemCameraTransforms(); }
|
||||
@Override public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) { return parent.getQuads(state, side, rand); }
|
||||
@Override public ItemOverrideList getOverrides() { return parent.getOverrides(); }
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType)
|
||||
{
|
||||
return handlePerspective(this, transforms, cameraTransformType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import javax.vecmath.Matrix3f;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Vector3f;
|
||||
import javax.vecmath.Vector4f;
|
||||
|
||||
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public abstract class SimpleModelFontRenderer extends FontRenderer {
|
||||
|
||||
private float r, g, b, a;
|
||||
private final Matrix4f matrix;
|
||||
private ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
private final VertexFormat format;
|
||||
private final Vector3f normal = new Vector3f(0, 0, 1);
|
||||
private final EnumFacing orientation;
|
||||
private boolean fillBlanks = false;
|
||||
|
||||
private TextureAtlasSprite sprite;
|
||||
|
||||
public SimpleModelFontRenderer(GameSettings settings, ResourceLocation font, TextureManager manager, boolean isUnicode, Matrix4f matrix, VertexFormat format)
|
||||
{
|
||||
super(settings, font, manager, isUnicode);
|
||||
this.matrix = new Matrix4f(matrix);
|
||||
Matrix3f nm = new Matrix3f();
|
||||
this.matrix.getRotationScale(nm);
|
||||
nm.invert();
|
||||
nm.transpose();
|
||||
this.format = format;
|
||||
nm.transform(normal);
|
||||
normal.normalize();
|
||||
orientation = EnumFacing.getFacingFromVector(normal.x, normal.y, normal.z);
|
||||
}
|
||||
|
||||
public void setSprite(TextureAtlasSprite sprite)
|
||||
{
|
||||
this.sprite = sprite;
|
||||
super.onResourceManagerReload(null);
|
||||
}
|
||||
|
||||
public void setFillBlanks(boolean fillBlanks)
|
||||
{
|
||||
this.fillBlanks = fillBlanks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single character with the default.png font at current (posX,posY) location...
|
||||
*/
|
||||
@Override
|
||||
protected float renderDefaultChar(int pos, boolean italic)
|
||||
{
|
||||
float x = (pos % 16) / 16f;
|
||||
float y = (pos / 16) / 16f;
|
||||
float sh = italic ? 1f : 0f;
|
||||
float w = charWidth[pos] - 1.01f;
|
||||
float h = FONT_HEIGHT - 1.01f;
|
||||
float wt = w / 128f;
|
||||
float ht = h / 128f;
|
||||
|
||||
UnpackedBakedQuad.Builder quadBuilder = new UnpackedBakedQuad.Builder(format);
|
||||
quadBuilder.setTexture(sprite);
|
||||
quadBuilder.setQuadOrientation(orientation);
|
||||
|
||||
addVertex(quadBuilder, posX + sh, posY, x, y);
|
||||
addVertex(quadBuilder, posX - sh, posY + h, x, y + ht);
|
||||
addVertex(quadBuilder, posX + w + sh, posY + h, x + wt, y + ht);
|
||||
addVertex(quadBuilder, posX + w - sh, posY, x + wt, y);
|
||||
builder.add(quadBuilder.build());
|
||||
|
||||
if(fillBlanks)
|
||||
{
|
||||
float cuv = 15f / 16f;
|
||||
|
||||
quadBuilder = new UnpackedBakedQuad.Builder(format);
|
||||
quadBuilder.setTexture(sprite);
|
||||
quadBuilder.setQuadOrientation(orientation);
|
||||
|
||||
addVertex(quadBuilder, posX + w + sh, posY, cuv, cuv);
|
||||
addVertex(quadBuilder, posX + w - sh, posY + h, cuv, cuv);
|
||||
addVertex(quadBuilder, posX + charWidth[pos] + sh, posY + h, cuv, cuv);
|
||||
addVertex(quadBuilder, posX + charWidth[pos] - sh, posY, cuv, cuv);
|
||||
builder.add(quadBuilder.build());
|
||||
|
||||
quadBuilder = new UnpackedBakedQuad.Builder(format);
|
||||
quadBuilder.setTexture(sprite);
|
||||
quadBuilder.setQuadOrientation(orientation);
|
||||
|
||||
addVertex(quadBuilder, posX + sh, posY + h, cuv, cuv);
|
||||
addVertex(quadBuilder, posX - sh, posY + FONT_HEIGHT, cuv, cuv);
|
||||
addVertex(quadBuilder, posX + charWidth[pos] + sh, posY + FONT_HEIGHT, cuv, cuv);
|
||||
addVertex(quadBuilder, posX + charWidth[pos] - sh, posY + h, cuv, cuv);
|
||||
builder.add(quadBuilder.build());
|
||||
}
|
||||
return charWidth[pos];
|
||||
}
|
||||
|
||||
private final Vector4f vec = new Vector4f();
|
||||
|
||||
private void addVertex(UnpackedBakedQuad.Builder quadBuilder, float x, float y, float u, float v)
|
||||
{
|
||||
vec.x = x;
|
||||
vec.y = y;
|
||||
vec.z = 0;
|
||||
vec.w = 1;
|
||||
matrix.transform(vec);
|
||||
for(int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
switch(format.getElement(e).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
quadBuilder.put(e, vec.x, vec.y, vec.z, vec.w);
|
||||
break;
|
||||
case UV:
|
||||
quadBuilder.put(e, sprite.getInterpolatedU(u * 16), sprite.getInterpolatedV(v * 16), 0, 1);
|
||||
break;
|
||||
case COLOR:
|
||||
quadBuilder.put(e, r, g, b, a);
|
||||
break;
|
||||
case NORMAL:
|
||||
//quadBuilder.put(e, normal.x, normal.y, normal.z, 1);
|
||||
quadBuilder.put(e, 0, 0, 1, 1);
|
||||
break;
|
||||
default:
|
||||
quadBuilder.put(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager)
|
||||
{
|
||||
super.onResourceManagerReload(resourceManager);
|
||||
String p = locationFontTexture.getResourcePath();
|
||||
if(p.startsWith("textures/")) p = p.substring("textures/".length(), p.length());
|
||||
if(p.endsWith(".png")) p = p.substring(0, p.length() - ".png".length());
|
||||
String f = locationFontTexture.getResourceDomain() + ":" + p;
|
||||
sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single Unicode character at current (posX,posY) location using one of the /font/glyph_XX.png files...
|
||||
*/
|
||||
@Override
|
||||
protected abstract float renderUnicodeChar(char c, boolean italic);
|
||||
|
||||
@Override
|
||||
protected void doDraw(float shift)
|
||||
{
|
||||
posX += (int)shift;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColor(float r, float g, float b, float a)
|
||||
{
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
@Override public void enableAlpha()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindTexture(ResourceLocation location)
|
||||
{
|
||||
}
|
||||
|
||||
public ImmutableList<BakedQuad> build()
|
||||
{
|
||||
ImmutableList<BakedQuad> ret = builder.build();
|
||||
builder = ImmutableList.builder();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model;
|
||||
|
||||
import net.minecraftforge.common.model.IModelPart;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import java.util.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/*
|
||||
* Simple implementation of IModelState via a map and a default value.
|
||||
*/
|
||||
public final class SimpleModelState implements IModelState
|
||||
{
|
||||
private final ImmutableMap<? extends IModelPart, TRSRTransformation> map;
|
||||
private final Optional<TRSRTransformation> def;
|
||||
|
||||
public SimpleModelState(ImmutableMap<? extends IModelPart, TRSRTransformation> map)
|
||||
{
|
||||
this(map, Optional.empty());
|
||||
}
|
||||
|
||||
public SimpleModelState(ImmutableMap<? extends IModelPart, TRSRTransformation> map, Optional<TRSRTransformation> def)
|
||||
{
|
||||
this.map = map;
|
||||
this.def = def;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
||||
{
|
||||
if(!part.isPresent())
|
||||
{
|
||||
return def;
|
||||
}
|
||||
if(!map.containsKey(part.get()))
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(map.get(part.get()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.animation;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public enum Animation
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
private float clientPartialTickTime;
|
||||
|
||||
private static long epochTime;
|
||||
private static WeakReference<World> worldRef;
|
||||
|
||||
/**
|
||||
* Get the global world time for the current tick, in seconds.
|
||||
*/
|
||||
public static float getWorldTime(World world)
|
||||
{
|
||||
return getWorldTime(world, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global world time for the current tick + partial tick progress, in seconds.
|
||||
*/
|
||||
public static float getWorldTime(World world, float tickProgress)
|
||||
{
|
||||
if (worldRef == null || worldRef.get() != world)
|
||||
{
|
||||
epochTime = world.getTotalWorldTime();
|
||||
worldRef = new WeakReference<>(world);
|
||||
}
|
||||
return (world.getTotalWorldTime() - epochTime + tickProgress) / 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current partialTickTime.
|
||||
*/
|
||||
public static float getPartialTickTime()
|
||||
{
|
||||
return INSTANCE.clientPartialTickTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal hook, do not use.
|
||||
*/
|
||||
public static void setClientPartialTickTime(float clientPartialTickTime) {
|
||||
Animation.INSTANCE.clientPartialTickTime = clientPartialTickTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.animation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverride;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelStateComposition;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.animation.CapabilityAnimation;
|
||||
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class AnimationItemOverrideList extends ItemOverrideList
|
||||
{
|
||||
private final IModel model;
|
||||
private final IModelState state;
|
||||
private final VertexFormat format;
|
||||
private final Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter;
|
||||
|
||||
public AnimationItemOverrideList(IModel model, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter, ItemOverrideList overrides)
|
||||
{
|
||||
this(model, state, format, bakedTextureGetter, overrides.getOverrides().reverse());
|
||||
}
|
||||
|
||||
public AnimationItemOverrideList(IModel model, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter, List<ItemOverride> overrides)
|
||||
{
|
||||
super(overrides);
|
||||
this.model = model;
|
||||
this.state = state;
|
||||
this.format = format;
|
||||
this.bakedTextureGetter = bakedTextureGetter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity)
|
||||
{
|
||||
IAnimationStateMachine asm = stack.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null);
|
||||
if (asm != null)
|
||||
{
|
||||
// TODO: caching?
|
||||
if(world == null && entity != null)
|
||||
{
|
||||
world = entity.world;
|
||||
}
|
||||
if(world == null)
|
||||
{
|
||||
world = Minecraft.getMinecraft().world;
|
||||
}
|
||||
IModelState state = asm.apply(Animation.getWorldTime(world, Animation.getPartialTickTime())).getLeft();
|
||||
return model.bake(new ModelStateComposition(state, this.state), format, bakedTextureGetter);
|
||||
}
|
||||
return super.handleItemState(originalModel, stack, world, entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.animation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.client.model.pipeline.VertexLighterFlat;
|
||||
import net.minecraftforge.client.model.pipeline.VertexBufferConsumer;
|
||||
import net.minecraftforge.common.animation.Event;
|
||||
import net.minecraftforge.common.animation.IEventHandler;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.animation.CapabilityAnimation;
|
||||
|
||||
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* ModelBase that works with the Forge model system and animations.
|
||||
* Some quirks are still left, deprecated for the moment.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AnimationModelBase<T extends Entity> extends ModelBase implements IEventHandler<T>
|
||||
{
|
||||
private final VertexLighterFlat lighter;
|
||||
private final ResourceLocation modelLocation;
|
||||
|
||||
public AnimationModelBase(ResourceLocation modelLocation, VertexLighterFlat lighter)
|
||||
{
|
||||
this.modelLocation = modelLocation;
|
||||
this.lighter = lighter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the models various rotation angles then renders the model.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void render(Entity entity, float limbSwing, float limbSwingSpeed, float timeAlive, float yawHead, float rotationPitch, float scale)
|
||||
{
|
||||
IAnimationStateMachine capability = entity.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null);
|
||||
if (capability == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Pair<IModelState, Iterable<Event>> pair = capability.apply(timeAlive / 20);
|
||||
handleEvents((T)entity, timeAlive / 20, pair.getRight());
|
||||
IModel model = ModelLoaderRegistry.getModelOrMissing(modelLocation);
|
||||
IBakedModel bakedModel = model.bake(pair.getLeft(), DefaultVertexFormats.ITEM, ModelLoader.defaultTextureGetter());
|
||||
|
||||
BlockPos pos = new BlockPos(entity.posX, entity.posY + entity.height, entity.posZ);
|
||||
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.rotate(180, 0, 0, 1);
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder builder = tessellator.getBuffer();
|
||||
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
builder.setTranslation(-0.5, -1.5, -0.5);
|
||||
|
||||
lighter.setParent(new VertexBufferConsumer(builder));
|
||||
lighter.setWorld(entity.world);
|
||||
lighter.setState(Blocks.AIR.getDefaultState());
|
||||
lighter.setBlockPos(pos);
|
||||
boolean empty = true;
|
||||
List<BakedQuad> quads = bakedModel.getQuads(null, null, 0);
|
||||
if(!quads.isEmpty())
|
||||
{
|
||||
lighter.updateBlockInfo();
|
||||
empty = false;
|
||||
for(BakedQuad quad : quads)
|
||||
{
|
||||
quad.pipe(lighter);
|
||||
}
|
||||
}
|
||||
for(EnumFacing side : EnumFacing.values())
|
||||
{
|
||||
quads = bakedModel.getQuads(null, side, 0);
|
||||
if(!quads.isEmpty())
|
||||
{
|
||||
if(empty) lighter.updateBlockInfo();
|
||||
empty = false;
|
||||
for(BakedQuad quad : quads)
|
||||
{
|
||||
quad.pipe(lighter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// debug quad
|
||||
/*VertexBuffer.pos(0, 1, 0).color(0xFF, 0xFF, 0xFF, 0xFF).tex(0, 0).lightmap(240, 0).endVertex();
|
||||
VertexBuffer.pos(0, 1, 1).color(0xFF, 0xFF, 0xFF, 0xFF).tex(0, 1).lightmap(240, 0).endVertex();
|
||||
VertexBuffer.pos(1, 1, 1).color(0xFF, 0xFF, 0xFF, 0xFF).tex(1, 1).lightmap(240, 0).endVertex();
|
||||
VertexBuffer.pos(1, 1, 0).color(0xFF, 0xFF, 0xFF, 0xFF).tex(1, 0).lightmap(240, 0).endVertex();*/
|
||||
|
||||
builder.setTranslation(0, 0, 0);
|
||||
|
||||
tessellator.draw();
|
||||
GlStateManager.popMatrix();
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvents(T instance, float time, Iterable<Event> pastEvents) {}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.animation;
|
||||
|
||||
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.block.model.IBakedModel;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import net.minecraftforge.common.animation.Event;
|
||||
import net.minecraftforge.common.animation.IEventHandler;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
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 org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
/**
|
||||
* Generic TileEntitySpecialRenderer that works with the Forge model system and animations.
|
||||
*/
|
||||
public class AnimationTESR<T extends TileEntity> extends FastTESR<T> implements IEventHandler<T>
|
||||
{
|
||||
protected static BlockRendererDispatcher blockRenderer;
|
||||
|
||||
@Override
|
||||
public void renderTileEntityFast(T te, double x, double y, double z, float partialTick, int breakStage, float partial, BufferBuilder renderer)
|
||||
{
|
||||
if(!te.hasCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(blockRenderer == null) blockRenderer = Minecraft.getMinecraft().getBlockRendererDispatcher();
|
||||
BlockPos pos = te.getPos();
|
||||
IBlockAccess world = MinecraftForgeClient.getRegionRenderCache(te.getWorld(), pos);
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
if(state.getPropertyKeys().contains(Properties.StaticProperty))
|
||||
{
|
||||
state = state.withProperty(Properties.StaticProperty, false);
|
||||
}
|
||||
if(state instanceof IExtendedBlockState)
|
||||
{
|
||||
IExtendedBlockState exState = (IExtendedBlockState)state;
|
||||
if(exState.getUnlistedNames().contains(Properties.AnimationProperty))
|
||||
{
|
||||
float time = Animation.getWorldTime(getWorld(), partialTick);
|
||||
IAnimationStateMachine capability = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null);
|
||||
if (capability != null)
|
||||
{
|
||||
Pair<IModelState, Iterable<Event>> pair = capability.apply(time);
|
||||
handleEvents(te, time, pair.getRight());
|
||||
|
||||
// TODO: caching?
|
||||
IBakedModel model = blockRenderer.getBlockModelShapes().getModelForState(exState.getClean());
|
||||
exState = exState.withProperty(Properties.AnimationProperty, pair.getLeft());
|
||||
|
||||
renderer.setTranslation(x - pos.getX(), y - pos.getY(), z - pos.getZ());
|
||||
|
||||
blockRenderer.getBlockModelRenderer().renderModel(world, model, exState, pos, renderer, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvents(T te, float time, Iterable<Event> pastEvents) {}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.animation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public abstract class FastTESR<T extends TileEntity> extends TileEntitySpecialRenderer<T>
|
||||
{
|
||||
@Override
|
||||
public final void render(T te, double x, double y, double z, float partialTicks, int destroyStage, float partial)
|
||||
{
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableCull();
|
||||
|
||||
if (Minecraft.isAmbientOcclusionEnabled())
|
||||
{
|
||||
GlStateManager.shadeModel(GL11.GL_SMOOTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
GlStateManager.shadeModel(GL11.GL_FLAT);
|
||||
}
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
|
||||
renderTileEntityFast(te, x, y, z, partialTicks, destroyStage, partial, buffer);
|
||||
buffer.setTranslation(0, 0, 0);
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void renderTileEntityFast(T te, double x, double y, double z, float partialTicks, int destroyStage, float partial, BufferBuilder buffer);
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.animation;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.AxisAngle4f;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Quat4f;
|
||||
import javax.vecmath.Vector3f;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BlockPart;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.client.model.animation.ModelBlockAnimation.Parameter.Interpolation;
|
||||
import net.minecraftforge.client.model.animation.ModelBlockAnimation.Parameter.Type;
|
||||
import net.minecraftforge.client.model.animation.ModelBlockAnimation.Parameter.Variable;
|
||||
import net.minecraftforge.common.animation.Event;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.common.model.animation.IClip;
|
||||
import net.minecraftforge.common.model.animation.IJoint;
|
||||
import net.minecraftforge.common.model.animation.IJointClip;
|
||||
import net.minecraftforge.common.model.animation.JointClips;
|
||||
import net.minecraftforge.common.util.JsonUtils;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class ModelBlockAnimation
|
||||
{
|
||||
private final ImmutableMap<String, ImmutableMap<String, float[]>> joints;
|
||||
private final ImmutableMap<String, MBClip> clips;
|
||||
private transient ImmutableMultimap<Integer, MBJointWeight> jointIndexMap;
|
||||
|
||||
public ModelBlockAnimation(ImmutableMap<String, ImmutableMap<String, float[]>> joints, ImmutableMap<String, MBClip> clips)
|
||||
{
|
||||
this.joints = joints;
|
||||
this.clips = clips;
|
||||
}
|
||||
|
||||
public ImmutableMap<String, ? extends IClip> getClips()
|
||||
{
|
||||
return clips;
|
||||
}
|
||||
|
||||
public ImmutableCollection<MBJointWeight> getJoint(int i)
|
||||
{
|
||||
if(jointIndexMap == null)
|
||||
{
|
||||
ImmutableMultimap.Builder<Integer, MBJointWeight> builder = ImmutableMultimap.builder();
|
||||
for(Map.Entry<String, ImmutableMap<String, float[]>> info : joints.entrySet())
|
||||
{
|
||||
ImmutableMap.Builder<Integer, float[]> weightBuilder = ImmutableMap.builder();
|
||||
for(Map.Entry<String, float[]> e : info.getValue().entrySet())
|
||||
{
|
||||
weightBuilder.put(Integer.parseInt(e.getKey()), e.getValue());
|
||||
}
|
||||
ImmutableMap<Integer, float[]> weightMap = weightBuilder.build();
|
||||
for(Map.Entry<Integer, float[]> e : weightMap.entrySet())
|
||||
{
|
||||
builder.put(e.getKey(), new MBJointWeight(info.getKey(), weightMap));
|
||||
}
|
||||
}
|
||||
jointIndexMap = builder.build();
|
||||
}
|
||||
return jointIndexMap.get(i);
|
||||
}
|
||||
|
||||
protected static class MBVariableClip
|
||||
{
|
||||
private final Variable variable;
|
||||
@SuppressWarnings("unused")
|
||||
private final Type type;
|
||||
private final Interpolation interpolation;
|
||||
private final float[] samples;
|
||||
|
||||
public MBVariableClip(Variable variable, Type type, Interpolation interpolation, float[] samples)
|
||||
{
|
||||
this.variable = variable;
|
||||
this.type = type;
|
||||
this.interpolation = interpolation;
|
||||
this.samples = samples;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MBClip implements IClip
|
||||
{
|
||||
private final boolean loop;
|
||||
@SerializedName("joint_clips")
|
||||
private final ImmutableMap<String, ImmutableList<MBVariableClip>> jointClipsFlat;
|
||||
private transient ImmutableMap<String, MBJointClip> jointClips;
|
||||
@SerializedName("events")
|
||||
private final ImmutableMap<String, String> eventsRaw;
|
||||
private transient TreeMap<Float, Event> events;
|
||||
|
||||
public MBClip(boolean loop, ImmutableMap<String, ImmutableList<MBVariableClip>> clips, ImmutableMap<String, String> events)
|
||||
{
|
||||
this.loop = loop;
|
||||
this.jointClipsFlat = clips;
|
||||
this.eventsRaw = events;
|
||||
}
|
||||
|
||||
private void initialize()
|
||||
{
|
||||
if(jointClips == null)
|
||||
{
|
||||
ImmutableMap.Builder<String, MBJointClip> builder = ImmutableMap.builder();
|
||||
for (Map.Entry<String, ImmutableList<MBVariableClip>> e : jointClipsFlat.entrySet())
|
||||
{
|
||||
builder.put(e.getKey(), new MBJointClip(loop, e.getValue()));
|
||||
}
|
||||
jointClips = builder.build();
|
||||
events = Maps.newTreeMap();
|
||||
if (!eventsRaw.isEmpty())
|
||||
{
|
||||
TreeMap<Float, String> times = Maps.newTreeMap();
|
||||
for (String time : eventsRaw.keySet())
|
||||
{
|
||||
times.put(Float.parseFloat(time), time);
|
||||
}
|
||||
float lastTime = Float.POSITIVE_INFINITY;
|
||||
if (loop)
|
||||
{
|
||||
lastTime = times.firstKey();
|
||||
}
|
||||
for (Map.Entry<Float, String> entry : times.descendingMap().entrySet())
|
||||
{
|
||||
float time = entry.getKey();
|
||||
float offset = lastTime - time;
|
||||
if (loop)
|
||||
{
|
||||
offset = 1 - (1 - offset) % 1;
|
||||
}
|
||||
events.put(time, new Event(eventsRaw.get(entry.getValue()), offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IJointClip apply(IJoint joint)
|
||||
{
|
||||
initialize();
|
||||
if(joint instanceof MBJoint)
|
||||
{
|
||||
MBJoint mbJoint = (MBJoint)joint;
|
||||
//MBJointInfo = jointInfos.
|
||||
MBJointClip clip = jointClips.get(mbJoint.getName());
|
||||
if(clip != null) return clip;
|
||||
}
|
||||
return JointClips.IdentityJointClip.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Event> pastEvents(final float lastPollTime, final float time)
|
||||
{
|
||||
initialize();
|
||||
return new Iterable<Event>()
|
||||
{
|
||||
@Override
|
||||
public Iterator<Event> iterator()
|
||||
{
|
||||
return new UnmodifiableIterator<Event>()
|
||||
{
|
||||
private Float curKey;
|
||||
private Event firstEvent;
|
||||
private float stopTime;
|
||||
{
|
||||
if(lastPollTime >= time)
|
||||
{
|
||||
curKey = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
float fractTime = time - (float)Math.floor(time);
|
||||
float fractLastTime = lastPollTime - (float)Math.floor(lastPollTime);
|
||||
// swap if not in order
|
||||
if(fractLastTime > fractTime)
|
||||
{
|
||||
float tmp = fractTime;
|
||||
fractTime = fractLastTime;
|
||||
fractLastTime = tmp;
|
||||
}
|
||||
// need to wrap around, swap again
|
||||
if(fractTime - fractLastTime > .5f)
|
||||
{
|
||||
float tmp = fractTime;
|
||||
fractTime = fractLastTime;
|
||||
fractLastTime = tmp;
|
||||
}
|
||||
|
||||
stopTime = fractLastTime;
|
||||
|
||||
curKey = events.floorKey(fractTime);
|
||||
if(curKey == null && loop && !events.isEmpty())
|
||||
{
|
||||
curKey = events.lastKey();
|
||||
}
|
||||
if(curKey != null)
|
||||
{
|
||||
float checkCurTime = curKey;
|
||||
float checkStopTime = stopTime;
|
||||
if(checkCurTime >= fractTime) checkCurTime--;
|
||||
if(checkStopTime >= fractTime) checkStopTime--;
|
||||
float offset = fractTime - checkCurTime;
|
||||
Event event = events.get(curKey);
|
||||
if(checkCurTime < checkStopTime)
|
||||
{
|
||||
curKey = null;
|
||||
}
|
||||
else if(offset != event.offset())
|
||||
{
|
||||
firstEvent = new Event(event.event(), offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return curKey != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event next()
|
||||
{
|
||||
if(curKey == null)
|
||||
{
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
Event event;
|
||||
if(firstEvent == null)
|
||||
{
|
||||
event = events.get(curKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
event = firstEvent;
|
||||
firstEvent = null;
|
||||
}
|
||||
curKey = events.lowerKey(curKey);
|
||||
if(curKey == null && loop)
|
||||
{
|
||||
curKey = events.lastKey();
|
||||
}
|
||||
if(curKey != null)
|
||||
{
|
||||
float checkStopTime = stopTime;
|
||||
while(curKey + events.get(curKey).offset() < checkStopTime) checkStopTime--;
|
||||
while(curKey + events.get(curKey).offset() >= checkStopTime + 1) checkStopTime++;
|
||||
if(curKey <= checkStopTime)
|
||||
{
|
||||
curKey = null;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected static class MBJointClip implements IJointClip
|
||||
{
|
||||
private final boolean loop;
|
||||
private final ImmutableList<MBVariableClip> variables;
|
||||
|
||||
public MBJointClip(boolean loop, ImmutableList<MBVariableClip> variables)
|
||||
{
|
||||
this.loop = loop;
|
||||
this.variables = variables;
|
||||
EnumSet<Variable> hadVar = Sets.newEnumSet(Collections.<Variable>emptyList(), Variable.class);
|
||||
for(MBVariableClip var : variables)
|
||||
{
|
||||
if(hadVar.contains(var.variable))
|
||||
{
|
||||
throw new IllegalArgumentException("duplicate variable: " + var);
|
||||
}
|
||||
hadVar.add(var.variable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TRSRTransformation apply(float time)
|
||||
{
|
||||
time -= Math.floor(time);
|
||||
Vector3f translation = new Vector3f(0, 0, 0);
|
||||
Vector3f scale = new Vector3f(1, 1, 1);
|
||||
Vector3f origin = new Vector3f(0, 0, 0);
|
||||
AxisAngle4f rotation = new AxisAngle4f(0, 0, 0, 0);
|
||||
for(MBVariableClip var : variables)
|
||||
{
|
||||
int length = loop ? var.samples.length : (var.samples.length - 1);
|
||||
float timeScaled = time * length;
|
||||
int s1 = MathHelper.clamp((int)Math.round(Math.floor(timeScaled)), 0, length - 1);
|
||||
float progress = timeScaled - s1;
|
||||
int s2 = s1 + 1;
|
||||
if(s2 == length && loop) s2 = 0;
|
||||
float value = 0;
|
||||
switch(var.interpolation)
|
||||
{
|
||||
case LINEAR:
|
||||
if(var.variable == Variable.ANGLE)
|
||||
{
|
||||
float v1 = var.samples[s1];
|
||||
float v2 = var.samples[s2];
|
||||
float diff = ((v2 - v1) % 360 + 540) % 360 - 180;
|
||||
value = v1 + diff * progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = var.samples[s1] * (1 - progress) + var.samples[s2] * progress;
|
||||
}
|
||||
break;
|
||||
case NEAREST:
|
||||
value = var.samples[progress < .5f ? s1 : s2];
|
||||
break;
|
||||
}
|
||||
switch(var.variable)
|
||||
{
|
||||
case X:
|
||||
translation.x = value;
|
||||
break;
|
||||
case Y:
|
||||
translation.y = value;
|
||||
break;
|
||||
case Z:
|
||||
translation.z = value;
|
||||
break;
|
||||
case XROT:
|
||||
rotation.x = value;
|
||||
break;
|
||||
case YROT:
|
||||
rotation.y = value;
|
||||
break;
|
||||
case ZROT:
|
||||
rotation.z = value;
|
||||
break;
|
||||
case ANGLE:
|
||||
rotation.angle = (float)Math.toRadians(value);
|
||||
break;
|
||||
case SCALE:
|
||||
scale.x = scale.y = scale.z = value;
|
||||
break;
|
||||
case XS:
|
||||
scale.x = value;
|
||||
break;
|
||||
case YS:
|
||||
scale.y = value;
|
||||
break;
|
||||
case ZS:
|
||||
scale.z = value;
|
||||
break;
|
||||
case XORIGIN:
|
||||
origin.x = value - 0.5F;
|
||||
break;
|
||||
case YORIGIN:
|
||||
origin.y = value - 0.5F;
|
||||
break;
|
||||
case ZORIGIN:
|
||||
origin.z = value - 0.5F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Quat4f rot = new Quat4f();
|
||||
rot.set(rotation);
|
||||
TRSRTransformation base = new TRSRTransformation(translation, rot, scale, null);
|
||||
Vector3f negOrigin = new Vector3f(origin);
|
||||
negOrigin.negate();
|
||||
base = new TRSRTransformation(origin, null, null, null).compose(base).compose(new TRSRTransformation(negOrigin, null, null, null));
|
||||
return TRSRTransformation.blockCenterToCorner(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MBJoint implements IJoint
|
||||
{
|
||||
private final String name;
|
||||
|
||||
public MBJoint(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TRSRTransformation getInvBindPose()
|
||||
{
|
||||
return TRSRTransformation.identity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<? extends IJoint> getParent()
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MBJointWeight
|
||||
{
|
||||
private final String name;
|
||||
private final ImmutableMap<Integer, float[]> weights;
|
||||
|
||||
public MBJointWeight(String name, ImmutableMap<Integer, float[]> weights)
|
||||
{
|
||||
this.name = name;
|
||||
this.weights = weights;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public ImmutableMap<Integer, float[]> getWeights()
|
||||
{
|
||||
return weights;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class Parameter
|
||||
{
|
||||
public static enum Variable
|
||||
{
|
||||
@SerializedName("offset_x")
|
||||
X,
|
||||
@SerializedName("offset_y")
|
||||
Y,
|
||||
@SerializedName("offset_z")
|
||||
Z,
|
||||
@SerializedName("axis_x")
|
||||
XROT,
|
||||
@SerializedName("axis_y")
|
||||
YROT,
|
||||
@SerializedName("axis_z")
|
||||
ZROT,
|
||||
@SerializedName("angle")
|
||||
ANGLE,
|
||||
@SerializedName("scale")
|
||||
SCALE,
|
||||
@SerializedName("scale_x")
|
||||
XS,
|
||||
@SerializedName("scale_y")
|
||||
YS,
|
||||
@SerializedName("scale_z")
|
||||
ZS,
|
||||
@SerializedName("origin_x")
|
||||
XORIGIN,
|
||||
@SerializedName("origin_y")
|
||||
YORIGIN,
|
||||
@SerializedName("origin_z")
|
||||
ZORIGIN;
|
||||
}
|
||||
|
||||
public static enum Type
|
||||
{
|
||||
@SerializedName("uniform")
|
||||
UNIFORM;
|
||||
}
|
||||
|
||||
public static enum Interpolation
|
||||
{
|
||||
@SerializedName("linear")
|
||||
LINEAR,
|
||||
@SerializedName("nearest")
|
||||
NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TRSRTransformation getPartTransform(IModelState state, BlockPart part, int i)
|
||||
{
|
||||
ImmutableCollection<MBJointWeight> infos = getJoint(i);
|
||||
if(!infos.isEmpty())
|
||||
{
|
||||
Matrix4f m = new Matrix4f(), tmp;
|
||||
float weight = 0;
|
||||
for(MBJointWeight info : infos)
|
||||
{
|
||||
if(info.getWeights().containsKey(i))
|
||||
{
|
||||
ModelBlockAnimation.MBJoint joint = new ModelBlockAnimation.MBJoint(info.getName());
|
||||
Optional<TRSRTransformation> trOp = state.apply(Optional.of(joint));
|
||||
if(trOp.isPresent() && !trOp.get().isIdentity())
|
||||
{
|
||||
float w = info.getWeights().get(i)[0];
|
||||
tmp = trOp.get().getMatrix();
|
||||
tmp.mul(w);
|
||||
m.add(tmp);
|
||||
weight += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(weight > 1e-5)
|
||||
{
|
||||
m.mul(1f / weight);
|
||||
return new TRSRTransformation(m);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load armature associated with a vanilla model.
|
||||
*/
|
||||
public static ModelBlockAnimation loadVanillaAnimation(IResourceManager manager, ResourceLocation armatureLocation)
|
||||
{
|
||||
try
|
||||
{
|
||||
try (IResource resource = manager.getResource(armatureLocation))
|
||||
{
|
||||
ModelBlockAnimation mba = mbaGson.fromJson(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8), ModelBlockAnimation.class);
|
||||
//String json = mbaGson.toJson(mba);
|
||||
return mba;
|
||||
}
|
||||
catch(FileNotFoundException e)
|
||||
{
|
||||
// this is normal. FIXME: error reporting?
|
||||
return defaultModelBlockAnimation;
|
||||
}
|
||||
}
|
||||
catch(IOException | JsonParseException e)
|
||||
{
|
||||
FMLLog.log.error("Exception loading vanilla model animation {}, skipping", armatureLocation, e);
|
||||
return defaultModelBlockAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Gson mbaGson = new GsonBuilder()
|
||||
.registerTypeAdapter(ImmutableList.class, JsonUtils.ImmutableListTypeAdapter.INSTANCE)
|
||||
.registerTypeAdapter(ImmutableMap.class, JsonUtils.ImmutableMapTypeAdapter.INSTANCE)
|
||||
.setPrettyPrinting()
|
||||
.enableComplexMapKeySerialization()
|
||||
.disableHtmlEscaping()
|
||||
.create();
|
||||
|
||||
private static final ModelBlockAnimation defaultModelBlockAnimation = new ModelBlockAnimation(ImmutableMap.<String, ImmutableMap<String, float[]>>of(), ImmutableMap.<String, ModelBlockAnimation.MBClip>of());
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraftforge.client.model.animation;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.b3d;
|
||||
|
||||
import net.minecraftforge.client.model.b3d.B3DLoader.NodeJoint;
|
||||
import net.minecraftforge.client.model.b3d.B3DModel.Key;
|
||||
import net.minecraftforge.client.model.b3d.B3DModel.Node;
|
||||
import net.minecraftforge.common.animation.Event;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.common.model.animation.IClip;
|
||||
import net.minecraftforge.common.model.animation.IJoint;
|
||||
import net.minecraftforge.common.model.animation.IJointClip;
|
||||
import net.minecraftforge.common.model.animation.JointClips;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
// FIXME: is this fast enough?
|
||||
public enum B3DClip implements IClip
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public IJointClip apply(final IJoint joint)
|
||||
{
|
||||
if(!(joint instanceof NodeJoint))
|
||||
{
|
||||
return JointClips.IdentityJointClip.INSTANCE;
|
||||
}
|
||||
return new NodeClip(((NodeJoint)joint).getNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Event> pastEvents(float lastPollTime, float time)
|
||||
{
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
protected static class NodeClip implements IJointClip
|
||||
{
|
||||
private final Node<?> node;
|
||||
|
||||
public NodeClip(Node<?> node)
|
||||
{
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TRSRTransformation apply(float time)
|
||||
{
|
||||
TRSRTransformation ret = TRSRTransformation.identity();
|
||||
if(node.getAnimation() == null)
|
||||
{
|
||||
return ret.compose(new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null));
|
||||
}
|
||||
int start = Math.max(1, (int)Math.round(Math.floor(time)));
|
||||
int end = Math.min(start + 1, (int)Math.round(Math.ceil(time)));
|
||||
float progress = time - (float)Math.floor(time);
|
||||
Key keyStart = node.getAnimation().getKeys().get(start, node);
|
||||
Key keyEnd = node.getAnimation().getKeys().get(end, node);
|
||||
TRSRTransformation startTr = keyStart == null ? null : new TRSRTransformation(keyStart.getPos(), keyStart.getRot(),keyStart.getScale(), null);
|
||||
TRSRTransformation endTr = keyEnd == null ? null : new TRSRTransformation(keyEnd.getPos(), keyEnd.getRot(),keyEnd.getScale(), null);
|
||||
if(keyStart == null)
|
||||
{
|
||||
if(keyEnd == null)
|
||||
{
|
||||
ret = ret.compose(new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null));
|
||||
}
|
||||
// TODO animated TRSRTransformation for speed?
|
||||
else
|
||||
{
|
||||
ret = ret.compose(endTr);
|
||||
}
|
||||
}
|
||||
else if(progress < 1e-5 || keyEnd == null)
|
||||
{
|
||||
ret = ret.compose(startTr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ret.compose(startTr.slerp(endTr, progress));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,830 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.b3d;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import javax.vecmath.Vector3f;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.client.model.ICustomModelLoader;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.client.model.ModelStateComposition;
|
||||
import net.minecraftforge.client.model.PerspectiveMapWrapper;
|
||||
import net.minecraftforge.client.model.b3d.B3DModel.Animation;
|
||||
import net.minecraftforge.client.model.b3d.B3DModel.Face;
|
||||
import net.minecraftforge.client.model.b3d.B3DModel.Key;
|
||||
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.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.model.animation.IClip;
|
||||
import net.minecraftforge.common.model.animation.IJoint;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.minecraftforge.common.property.IUnlistedProperty;
|
||||
import net.minecraftforge.common.property.Properties;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
|
||||
import java.util.function.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import java.util.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
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).
|
||||
* If you need more control over accepted resources - extend the class, and register a new instance with ModelLoaderRegistry.
|
||||
*/
|
||||
public enum B3DLoader implements ICustomModelLoader
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
private IResourceManager manager;
|
||||
|
||||
private final Set<String> enabledDomains = new HashSet<>();
|
||||
private final Map<ResourceLocation, B3DModel> cache = new HashMap<>();
|
||||
|
||||
public void addDomain(String domain)
|
||||
{
|
||||
enabledDomains.add(domain.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return enabledDomains.contains(modelLocation.getResourceDomain()) && modelLocation.getResourcePath().endsWith(".b3d");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public IModel loadModel(ResourceLocation modelLocation) throws Exception
|
||||
{
|
||||
ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
|
||||
if(!cache.containsKey(file))
|
||||
{
|
||||
IResource resource = null;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
resource = manager.getResource(file);
|
||||
}
|
||||
catch(FileNotFoundException e)
|
||||
{
|
||||
if(modelLocation.getResourcePath().startsWith("models/block/"))
|
||||
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/item/" + file.getResourcePath().substring("models/block/".length())));
|
||||
else if(modelLocation.getResourcePath().startsWith("models/item/"))
|
||||
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/block/" + file.getResourcePath().substring("models/item/".length())));
|
||||
else throw e;
|
||||
}
|
||||
B3DModel.Parser parser = new B3DModel.Parser(resource.getInputStream());
|
||||
B3DModel model = parser.parse();
|
||||
cache.put(file, model);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
cache.put(file, null);
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(resource);
|
||||
}
|
||||
}
|
||||
B3DModel model = cache.get(file);
|
||||
if(model == null) throw new ModelLoaderRegistry.LoaderException("Error loading model previously: " + file);
|
||||
if(!(model.getRoot().getKind() instanceof Mesh))
|
||||
{
|
||||
return new ModelWrapper(modelLocation, model, ImmutableSet.of(), true, true, 1);
|
||||
}
|
||||
return new ModelWrapper(modelLocation, model, ImmutableSet.of(model.getRoot().getName()), true, true, 1);
|
||||
}
|
||||
|
||||
public static final class B3DState implements IModelState
|
||||
{
|
||||
@Nullable
|
||||
private final Animation animation;
|
||||
private final int frame;
|
||||
private final int nextFrame;
|
||||
private final float progress;
|
||||
@Nullable
|
||||
private final IModelState parent;
|
||||
|
||||
public B3DState(@Nullable Animation animation, int frame)
|
||||
{
|
||||
this(animation, frame, frame, 0);
|
||||
}
|
||||
|
||||
public B3DState(@Nullable Animation animation, int frame, IModelState parent)
|
||||
{
|
||||
this(animation, frame, frame, 0, parent);
|
||||
}
|
||||
|
||||
public B3DState(@Nullable Animation animation, int frame, int nextFrame, float progress)
|
||||
{
|
||||
this(animation, frame, nextFrame, progress, null);
|
||||
}
|
||||
|
||||
public B3DState(@Nullable Animation animation, int frame, int nextFrame, float progress, @Nullable IModelState parent)
|
||||
{
|
||||
this.animation = animation;
|
||||
this.frame = frame;
|
||||
this.nextFrame = nextFrame;
|
||||
this.progress = MathHelper.clamp(progress, 0, 1);
|
||||
this.parent = getParent(parent);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private IModelState getParent(@Nullable IModelState parent)
|
||||
{
|
||||
if (parent == null) return null;
|
||||
else if (parent instanceof B3DState) return ((B3DState)parent).parent;
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Animation getAnimation()
|
||||
{
|
||||
return animation;
|
||||
}
|
||||
|
||||
public int getFrame()
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
public int getNextFrame()
|
||||
{
|
||||
return nextFrame;
|
||||
}
|
||||
|
||||
public float getProgress()
|
||||
{
|
||||
return progress;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IModelState getParent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
||||
{
|
||||
// TODO make more use of Optional
|
||||
if(!part.isPresent())
|
||||
{
|
||||
if(parent != null)
|
||||
{
|
||||
return parent.apply(part);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
if(!(part.get() instanceof NodeJoint))
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
Node<?> node = ((NodeJoint)part.get()).getNode();
|
||||
TRSRTransformation nodeTransform;
|
||||
if(progress < 1e-5 || frame == nextFrame)
|
||||
{
|
||||
nodeTransform = getNodeMatrix(node, frame);
|
||||
}
|
||||
else if(progress > 1 - 1e-5)
|
||||
{
|
||||
nodeTransform = getNodeMatrix(node, nextFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeTransform = getNodeMatrix(node, frame);
|
||||
nodeTransform = nodeTransform.slerp(getNodeMatrix(node, nextFrame), progress);
|
||||
}
|
||||
if(parent != null && node.getParent() == null)
|
||||
{
|
||||
return Optional.of(parent.apply(part).orElse(TRSRTransformation.identity()).compose(nodeTransform));
|
||||
}
|
||||
return Optional.of(nodeTransform);
|
||||
}
|
||||
|
||||
private static LoadingCache<Triple<Animation, Node<?>, Integer>, TRSRTransformation> cache = CacheBuilder.newBuilder()
|
||||
.maximumSize(16384)
|
||||
.expireAfterAccess(2, TimeUnit.MINUTES)
|
||||
.build(new CacheLoader<Triple<Animation, Node<?>, Integer>, TRSRTransformation>()
|
||||
{
|
||||
@Override
|
||||
public TRSRTransformation load(Triple<Animation, Node<?>, Integer> key) throws Exception
|
||||
{
|
||||
return getNodeMatrix(key.getLeft(), key.getMiddle(), key.getRight());
|
||||
}
|
||||
});
|
||||
|
||||
public TRSRTransformation getNodeMatrix(Node<?> node)
|
||||
{
|
||||
return getNodeMatrix(node, frame);
|
||||
}
|
||||
|
||||
public TRSRTransformation getNodeMatrix(Node<?> node, int frame)
|
||||
{
|
||||
return cache.getUnchecked(Triple.of(animation, node, frame));
|
||||
}
|
||||
|
||||
public static TRSRTransformation getNodeMatrix(@Nullable Animation animation, Node<?> node, int frame)
|
||||
{
|
||||
TRSRTransformation ret = TRSRTransformation.identity();
|
||||
Key key = null;
|
||||
if(animation != null) key = animation.getKeys().get(frame, node);
|
||||
else if(node.getAnimation() != null) key = node.getAnimation().getKeys().get(frame, node);
|
||||
if(key != null)
|
||||
{
|
||||
Node<?> parent = node.getParent();
|
||||
if(parent != null)
|
||||
{
|
||||
// parent model-global current pose
|
||||
TRSRTransformation pm = cache.getUnchecked(Triple.of(animation, node.getParent(), frame));
|
||||
ret = ret.compose(pm);
|
||||
// joint offset in the parent coords
|
||||
ret = ret.compose(new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null));
|
||||
}
|
||||
// current node local pose
|
||||
ret = ret.compose(new TRSRTransformation(key.getPos(), key.getRot(), key.getScale(), null));
|
||||
// this part moved inside the model
|
||||
// inverse bind of the current node
|
||||
/*Matrix4f rm = new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null).getMatrix();
|
||||
rm.invert();
|
||||
ret = ret.compose(new TRSRTransformation(rm));
|
||||
if(parent != null)
|
||||
{
|
||||
// inverse bind of the parent
|
||||
rm = new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null).getMatrix();
|
||||
rm.invert();
|
||||
ret = ret.compose(new TRSRTransformation(rm));
|
||||
}*/
|
||||
// TODO cache
|
||||
TRSRTransformation invBind = new NodeJoint(node).getInvBindPose();
|
||||
ret = ret.compose(invBind);
|
||||
}
|
||||
else
|
||||
{
|
||||
Node<?> parent = node.getParent();
|
||||
if(parent != null)
|
||||
{
|
||||
// parent model-global current pose
|
||||
TRSRTransformation pm = cache.getUnchecked(Triple.of(animation, node.getParent(), frame));
|
||||
ret = ret.compose(pm);
|
||||
// joint offset in the parent coords
|
||||
ret = ret.compose(new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null));
|
||||
}
|
||||
ret = ret.compose(new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null));
|
||||
// TODO cache
|
||||
TRSRTransformation invBind = new NodeJoint(node).getInvBindPose();
|
||||
ret = ret.compose(invBind);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static final class NodeJoint implements IJoint
|
||||
{
|
||||
private final Node<?> node;
|
||||
|
||||
public NodeJoint(Node<?> node)
|
||||
{
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TRSRTransformation getInvBindPose()
|
||||
{
|
||||
Matrix4f m = new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null).getMatrix();
|
||||
m.invert();
|
||||
TRSRTransformation pose = new TRSRTransformation(m);
|
||||
|
||||
if(node.getParent() != null)
|
||||
{
|
||||
TRSRTransformation parent = new NodeJoint(node.getParent()).getInvBindPose();
|
||||
pose = pose.compose(parent);
|
||||
}
|
||||
return pose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NodeJoint> getParent()
|
||||
{
|
||||
// FIXME cache?
|
||||
if(node.getParent() == null) return Optional.empty();
|
||||
return Optional.of(new NodeJoint(node.getParent()));
|
||||
}
|
||||
|
||||
public Node<?> getNode()
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return node.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (!super.equals(obj)) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
NodeJoint other = (NodeJoint) obj;
|
||||
return Objects.equal(node, other.node);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ModelWrapper implements IModel
|
||||
{
|
||||
private final ResourceLocation modelLocation;
|
||||
private final B3DModel model;
|
||||
private final ImmutableSet<String> meshes;
|
||||
private final ImmutableMap<String, ResourceLocation> textures;
|
||||
private final boolean smooth;
|
||||
private final boolean gui3d;
|
||||
private final int defaultKey;
|
||||
|
||||
public ModelWrapper(ResourceLocation modelLocation, B3DModel model, ImmutableSet<String> meshes, boolean smooth, boolean gui3d, int defaultKey)
|
||||
{
|
||||
this(modelLocation, model, meshes, smooth, gui3d, defaultKey, buildTextures(model.getTextures()));
|
||||
}
|
||||
|
||||
public ModelWrapper(ResourceLocation modelLocation, B3DModel model, ImmutableSet<String> meshes, boolean smooth, boolean gui3d, int defaultKey, ImmutableMap<String, ResourceLocation> textures)
|
||||
{
|
||||
this.modelLocation = modelLocation;
|
||||
this.model = model;
|
||||
this.meshes = meshes;
|
||||
this.textures = textures;
|
||||
this.smooth = smooth;
|
||||
this.gui3d = gui3d;
|
||||
this.defaultKey = defaultKey;
|
||||
}
|
||||
|
||||
private static ImmutableMap<String, ResourceLocation> buildTextures(List<Texture> textures)
|
||||
{
|
||||
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
|
||||
|
||||
for(Texture t : textures)
|
||||
{
|
||||
String path = t.getPath();
|
||||
String location = getLocation(path);
|
||||
if(!location.startsWith("#")) location = "#" + location;
|
||||
builder.put(path, new ResourceLocation(location));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static String getLocation(String path)
|
||||
{
|
||||
if(path.endsWith(".png")) path = path.substring(0, path.length() - ".png".length());
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
return Collections2.filter(textures.values(), loc -> !loc.getResourcePath().startsWith("#"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
|
||||
TextureAtlasSprite missing = bakedTextureGetter.apply(new ResourceLocation("missingno"));
|
||||
for(Map.Entry<String, ResourceLocation> e : textures.entrySet())
|
||||
{
|
||||
if(e.getValue().getResourcePath().startsWith("#"))
|
||||
{
|
||||
FMLLog.log.fatal("unresolved texture '{}' for b3d model '{}'", e.getValue().getResourcePath(), modelLocation);
|
||||
builder.put(e.getKey(), missing);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.put(e.getKey(), bakedTextureGetter.apply(e.getValue()));
|
||||
}
|
||||
}
|
||||
builder.put("missingno", missing);
|
||||
return new BakedWrapper(model.getRoot(), state, smooth, gui3d, format, meshes, builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelWrapper retexture(ImmutableMap<String, String> textures)
|
||||
{
|
||||
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
|
||||
for(Map.Entry<String, ResourceLocation> e : this.textures.entrySet())
|
||||
{
|
||||
String path = e.getKey();
|
||||
String loc = getLocation(path);
|
||||
if(textures.containsKey(loc))
|
||||
{
|
||||
String newLoc = textures.get(loc);
|
||||
if(newLoc == null) newLoc = getLocation(path);
|
||||
builder.put(e.getKey(), new ResourceLocation(newLoc));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.put(e);
|
||||
}
|
||||
}
|
||||
return new ModelWrapper(modelLocation, model, meshes, smooth, gui3d, defaultKey, builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelWrapper process(ImmutableMap<String, String> data)
|
||||
{
|
||||
ImmutableSet<String> newMeshes = this.meshes;
|
||||
int newDefaultKey = this.defaultKey;
|
||||
boolean hasChanged = false;
|
||||
if(data.containsKey("mesh"))
|
||||
{
|
||||
JsonElement e = new JsonParser().parse(data.get("mesh"));
|
||||
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isString())
|
||||
{
|
||||
return new ModelWrapper(modelLocation, model, ImmutableSet.of(e.getAsString()), smooth, gui3d, defaultKey, textures);
|
||||
}
|
||||
else if (e.isJsonArray())
|
||||
{
|
||||
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
|
||||
for(JsonElement s : e.getAsJsonArray())
|
||||
{
|
||||
if(s.isJsonPrimitive() && s.getAsJsonPrimitive().isString())
|
||||
{
|
||||
builder.add(s.getAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.fatal("unknown mesh definition '{}' in array for b3d model '{}'", s.toString(), modelLocation);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
newMeshes = builder.build();
|
||||
hasChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.fatal("unknown mesh definition '{}' for b3d model '{}'", e.toString(), modelLocation);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
if(data.containsKey("key"))
|
||||
{
|
||||
JsonElement e = new JsonParser().parse(data.get("key"));
|
||||
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isNumber())
|
||||
{
|
||||
newDefaultKey = e.getAsNumber().intValue();
|
||||
hasChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.fatal("unknown keyframe definition '{}' for b3d model '{}'", e.toString(), modelLocation);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return hasChanged ? new ModelWrapper(modelLocation, model, newMeshes, smooth, gui3d, newDefaultKey, textures) : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IClip> getClip(String name)
|
||||
{
|
||||
if(name.equals("main"))
|
||||
{
|
||||
return Optional.of(B3DClip.INSTANCE);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelState getDefaultState()
|
||||
{
|
||||
return new B3DState(model.getRoot().getAnimation(), defaultKey, defaultKey, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelWrapper smoothLighting(boolean value)
|
||||
{
|
||||
if(value == smooth)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return new ModelWrapper(modelLocation, model, meshes, value, gui3d, defaultKey, textures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelWrapper gui3d(boolean value)
|
||||
{
|
||||
if(value == gui3d)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return new ModelWrapper(modelLocation, model, meshes, smooth, value, defaultKey, textures);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BakedWrapper implements IBakedModel
|
||||
{
|
||||
private final Node<?> node;
|
||||
private final IModelState state;
|
||||
private final boolean smooth;
|
||||
private final boolean gui3d;
|
||||
private final VertexFormat format;
|
||||
private final ImmutableSet<String> meshes;
|
||||
private final ImmutableMap<String, TextureAtlasSprite> textures;
|
||||
private final LoadingCache<Integer, B3DState> cache;
|
||||
|
||||
private ImmutableList<BakedQuad> quads;
|
||||
|
||||
public BakedWrapper(final Node<?> node, final IModelState state, final boolean smooth, final boolean gui3d, final VertexFormat format, final ImmutableSet<String> meshes, final ImmutableMap<String, TextureAtlasSprite> textures)
|
||||
{
|
||||
this(node, state, smooth, gui3d, format, meshes, textures, CacheBuilder.newBuilder()
|
||||
.maximumSize(128)
|
||||
.expireAfterAccess(2, TimeUnit.MINUTES)
|
||||
.build(new CacheLoader<Integer, B3DState>()
|
||||
{
|
||||
@Override
|
||||
public B3DState load(Integer frame) throws Exception
|
||||
{
|
||||
IModelState parent = state;
|
||||
Animation newAnimation = node.getAnimation();
|
||||
if(parent instanceof B3DState)
|
||||
{
|
||||
B3DState ps = (B3DState)parent;
|
||||
parent = ps.getParent();
|
||||
}
|
||||
return new B3DState(newAnimation, frame, frame, 0, parent);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public BakedWrapper(Node<?> node, IModelState state, boolean smooth, boolean gui3d, VertexFormat format, ImmutableSet<String> meshes, ImmutableMap<String, TextureAtlasSprite> textures, LoadingCache<Integer, B3DState> cache)
|
||||
{
|
||||
this.node = node;
|
||||
this.state = state;
|
||||
this.smooth = smooth;
|
||||
this.gui3d = gui3d;
|
||||
this.format = format;
|
||||
this.meshes = meshes;
|
||||
this.textures = textures;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
if(side != null) return ImmutableList.of();
|
||||
IModelState modelState = this.state;
|
||||
if(state instanceof IExtendedBlockState)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(quads == null)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
generateQuads(builder, node, this.state, ImmutableList.of());
|
||||
quads = builder.build();
|
||||
}
|
||||
// TODO: caching?
|
||||
if(this.state != modelState)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
generateQuads(builder, node, modelState, ImmutableList.of());
|
||||
return builder.build();
|
||||
}
|
||||
return quads;
|
||||
}
|
||||
|
||||
private void generateQuads(ImmutableList.Builder<BakedQuad> builder, Node<?> node, final IModelState state, ImmutableList<String> path)
|
||||
{
|
||||
ImmutableList.Builder<String> pathBuilder = ImmutableList.builder();
|
||||
pathBuilder.addAll(path);
|
||||
pathBuilder.add(node.getName());
|
||||
ImmutableList<String> newPath = pathBuilder.build();
|
||||
for(Node<?> child : node.getNodes().values())
|
||||
{
|
||||
generateQuads(builder, child, state, newPath);
|
||||
}
|
||||
if(node.getKind() instanceof Mesh && meshes.contains(node.getName()) && !state.apply(Optional.of(Models.getHiddenModelPart(newPath))).isPresent())
|
||||
{
|
||||
Mesh mesh = (Mesh)node.getKind();
|
||||
Collection<Face> faces = mesh.bake(new Function<Node<?>, Matrix4f>()
|
||||
{
|
||||
private final TRSRTransformation global = state.apply(Optional.empty()).orElse(TRSRTransformation.identity());
|
||||
private final LoadingCache<Node<?>, TRSRTransformation> localCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(32)
|
||||
.build(new CacheLoader<Node<?>, TRSRTransformation>()
|
||||
{
|
||||
@Override
|
||||
public TRSRTransformation load(Node<?> node) throws Exception
|
||||
{
|
||||
return state.apply(Optional.of(new NodeJoint(node))).orElse(TRSRTransformation.identity());
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public Matrix4f apply(Node<?> node)
|
||||
{
|
||||
return global.compose(localCache.getUnchecked(node)).getMatrix();
|
||||
}
|
||||
});
|
||||
for(Face f : faces)
|
||||
{
|
||||
UnpackedBakedQuad.Builder quadBuilder = new UnpackedBakedQuad.Builder(format);
|
||||
quadBuilder.setContractUVs(true);
|
||||
quadBuilder.setQuadOrientation(EnumFacing.getFacingFromVector(f.getNormal().x, f.getNormal().y, f.getNormal().z));
|
||||
List<Texture> textures = null;
|
||||
if(f.getBrush() != null) textures = f.getBrush().getTextures();
|
||||
TextureAtlasSprite sprite;
|
||||
if(textures == null || textures.isEmpty()) sprite = this.textures.get("missingno");
|
||||
else if(textures.get(0) == B3DModel.Texture.White) sprite = ModelLoader.White.INSTANCE;
|
||||
else sprite = this.textures.get(textures.get(0).getPath());
|
||||
quadBuilder.setTexture(sprite);
|
||||
putVertexData(quadBuilder, f.getV1(), f.getNormal(), sprite);
|
||||
putVertexData(quadBuilder, f.getV2(), f.getNormal(), sprite);
|
||||
putVertexData(quadBuilder, f.getV3(), f.getNormal(), sprite);
|
||||
putVertexData(quadBuilder, f.getV3(), f.getNormal(), sprite);
|
||||
builder.add(quadBuilder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void putVertexData(UnpackedBakedQuad.Builder builder, Vertex v, Vector3f faceNormal, TextureAtlasSprite sprite)
|
||||
{
|
||||
// TODO handle everything not handled (texture transformations, bones, transformations, normals, e.t.c)
|
||||
for(int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
switch(format.getElement(e).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
builder.put(e, v.getPos().x, v.getPos().y, v.getPos().z, 1);
|
||||
break;
|
||||
case COLOR:
|
||||
if(v.getColor() != null)
|
||||
{
|
||||
builder.put(e, v.getColor().x, v.getColor().y, v.getColor().z, v.getColor().w);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.put(e, 1, 1, 1, 1);
|
||||
}
|
||||
break;
|
||||
case UV:
|
||||
// TODO handle more brushes
|
||||
if(format.getElement(e).getIndex() < v.getTexCoords().length)
|
||||
{
|
||||
builder.put(e,
|
||||
sprite.getInterpolatedU(v.getTexCoords()[0].x * 16),
|
||||
sprite.getInterpolatedV(v.getTexCoords()[0].y * 16),
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.put(e, 0, 0, 0, 1);
|
||||
}
|
||||
break;
|
||||
case NORMAL:
|
||||
if(v.getNormal() != null)
|
||||
{
|
||||
builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
builder.put(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return smooth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return gui3d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
// FIXME somehow specify particle texture in the model
|
||||
return textures.values().asList().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
|
||||
{
|
||||
return PerspectiveMapWrapper.handlePerspective(this, state, cameraTransformType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
// TODO handle items
|
||||
return ItemOverrideList.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraftforge.client.model.b3d;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.obj;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ICustomModelLoader;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.Level;
|
||||
|
||||
/*
|
||||
* Loader for OBJ models.
|
||||
* To enable your mod call instance.addDomain(modid).
|
||||
* If you need more control over accepted resources - extend the class, and register a new instance with ModelLoaderRegistry.
|
||||
*/
|
||||
public enum OBJLoader implements ICustomModelLoader {
|
||||
INSTANCE;
|
||||
|
||||
private IResourceManager manager;
|
||||
private final Set<String> enabledDomains = new HashSet<>();
|
||||
private final Map<ResourceLocation, OBJModel> cache = new HashMap<>();
|
||||
private final Map<ResourceLocation, Exception> errors = new HashMap<>();
|
||||
|
||||
public void addDomain(String domain)
|
||||
{
|
||||
enabledDomains.add(domain.toLowerCase());
|
||||
FMLLog.log.info("OBJLoader: Domain {} has been added.", domain.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager)
|
||||
{
|
||||
this.manager = resourceManager;
|
||||
cache.clear();
|
||||
errors.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation)
|
||||
{
|
||||
return enabledDomains.contains(modelLocation.getResourceDomain()) && modelLocation.getResourcePath().endsWith(".obj");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation) throws Exception
|
||||
{
|
||||
ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
|
||||
if (!cache.containsKey(file))
|
||||
{
|
||||
IResource resource = null;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
resource = manager.getResource(file);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
if (modelLocation.getResourcePath().startsWith("models/block/"))
|
||||
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/item/" + file.getResourcePath().substring("models/block/".length())));
|
||||
else if (modelLocation.getResourcePath().startsWith("models/item/"))
|
||||
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/block/" + file.getResourcePath().substring("models/item/".length())));
|
||||
else throw e;
|
||||
}
|
||||
OBJModel.Parser parser = new OBJModel.Parser(resource, manager);
|
||||
OBJModel model = null;
|
||||
try
|
||||
{
|
||||
model = parser.parse();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errors.put(modelLocation, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cache.put(modelLocation, model);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(resource);
|
||||
}
|
||||
}
|
||||
OBJModel model = cache.get(file);
|
||||
if (model == null) throw new ModelLoaderRegistry.LoaderException("Error loading model previously: " + file, errors.get(modelLocation));
|
||||
return model;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraftforge.client.model.obj;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraftforge.client.model;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.color.BlockColors;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
public class BlockInfo
|
||||
{
|
||||
private static final EnumFacing[] SIDES = EnumFacing.values();
|
||||
|
||||
private final BlockColors colors;
|
||||
private IBlockAccess world;
|
||||
private IBlockState state;
|
||||
private BlockPos blockPos;
|
||||
|
||||
private final boolean[][][] t = new boolean[3][3][3];
|
||||
private final int[][][] s = new int[3][3][3];
|
||||
private final int[][][] b = new int[3][3][3];
|
||||
private final float[][][][] skyLight = new float[3][2][2][2];
|
||||
private final float[][][][] blockLight = new float[3][2][2][2];
|
||||
private final float[][][] ao = new float[3][3][3];
|
||||
|
||||
private final int[] packed = new int[7];
|
||||
|
||||
private boolean full;
|
||||
|
||||
private float shx = 0, shy = 0, shz = 0;
|
||||
|
||||
private int cachedTint = -1;
|
||||
private int cachedMultiplier = -1;
|
||||
|
||||
public BlockInfo(BlockColors colors)
|
||||
{
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public int getColorMultiplier(int tint)
|
||||
{
|
||||
if(cachedTint == tint) return cachedMultiplier;
|
||||
cachedTint = tint;
|
||||
cachedMultiplier = colors.colorMultiplier(state, world, blockPos, tint);
|
||||
return cachedMultiplier;
|
||||
}
|
||||
|
||||
public void updateShift()
|
||||
{
|
||||
Vec3d offset = state.getOffset(world, blockPos);
|
||||
shx = (float) offset.x;
|
||||
shy = (float) offset.y;
|
||||
shz = (float) offset.z;
|
||||
}
|
||||
|
||||
public void setWorld(IBlockAccess world)
|
||||
{
|
||||
this.world = world;
|
||||
cachedTint = -1;
|
||||
cachedMultiplier = -1;
|
||||
}
|
||||
|
||||
public void setState(IBlockState state)
|
||||
{
|
||||
this.state = state;
|
||||
cachedTint = -1;
|
||||
cachedMultiplier = -1;
|
||||
}
|
||||
|
||||
public void setBlockPos(BlockPos blockPos)
|
||||
{
|
||||
this.blockPos = blockPos;
|
||||
cachedTint = -1;
|
||||
cachedMultiplier = -1;
|
||||
shx = shy = shz = 0;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
this.world = null;
|
||||
this.state = null;
|
||||
this.blockPos = null;
|
||||
cachedTint = -1;
|
||||
cachedMultiplier = -1;
|
||||
shx = shy = shz = 0;
|
||||
}
|
||||
|
||||
private float combine(int c, int s1, int s2, int s3, boolean t0, boolean t1, boolean t2, boolean t3)
|
||||
{
|
||||
if (c == 0 && !t0) c = Math.max(0, Math.max(s1, s2) - 1);
|
||||
if (s1 == 0 && !t1) s1 = Math.max(0, c - 1);
|
||||
if (s2 == 0 && !t2) s2 = Math.max(0, c - 1);
|
||||
if (s3 == 0 && !t3) s3 = Math.max(0, Math.max(s1, s2) - 1);
|
||||
return (float) (c + s1 + s2 + s3) * 0x20 / (4 * 0xFFFF);
|
||||
}
|
||||
|
||||
public void updateLightMatrix()
|
||||
{
|
||||
for(int x = 0; x <= 2; x++)
|
||||
{
|
||||
for(int y = 0; y <= 2; y++)
|
||||
{
|
||||
for(int z = 0; z <= 2; z++)
|
||||
{
|
||||
BlockPos pos = blockPos.add(x - 1, y - 1, z - 1);
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
t[x][y][z] = state.getLightOpacity(world, pos) < 15;
|
||||
int brightness = state.getPackedLightmapCoords(world, pos);
|
||||
s[x][y][z] = (brightness >> 0x14) & 0xF;
|
||||
b[x][y][z] = (brightness >> 0x04) & 0xF;
|
||||
ao[x][y][z] = state.getAmbientOcclusionLightValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
for(EnumFacing side : SIDES)
|
||||
{
|
||||
if(!state.doesSideBlockRendering(world, blockPos, side))
|
||||
{
|
||||
int x = side.getFrontOffsetX() + 1;
|
||||
int y = side.getFrontOffsetY() + 1;
|
||||
int z = side.getFrontOffsetZ() + 1;
|
||||
s[x][y][z] = Math.max(s[1][1][1] - 1, s[x][y][z]);
|
||||
b[x][y][z] = Math.max(b[1][1][1] - 1, b[x][y][z]);
|
||||
}
|
||||
}
|
||||
for(int x = 0; x < 2; x++)
|
||||
{
|
||||
for(int y = 0; y < 2; y++)
|
||||
{
|
||||
for(int z = 0; z < 2; z++)
|
||||
{
|
||||
int x1 = x * 2;
|
||||
int y1 = y * 2;
|
||||
int z1 = z * 2;
|
||||
|
||||
int sxyz = s[x1][y1][z1];
|
||||
int bxyz = b[x1][y1][z1];
|
||||
boolean txyz = t[x1][y1][z1];
|
||||
|
||||
int sxz = s[x1][1][z1], sxy = s[x1][y1][1], syz = s[1][y1][z1];
|
||||
int bxz = b[x1][1][z1], bxy = b[x1][y1][1], byz = b[1][y1][z1];
|
||||
boolean txz = t[x1][1][z1], txy = t[x1][y1][1], tyz = t[1][y1][z1];
|
||||
|
||||
int sx = s[x1][1][1], sy = s[1][y1][1], sz = s[1][1][z1];
|
||||
int bx = b[x1][1][1], by = b[1][y1][1], bz = b[1][1][z1];
|
||||
boolean tx = t[x1][1][1], ty = t[1][y1][1], tz = t[1][1][z1];
|
||||
|
||||
skyLight [0][x][y][z] = combine(sx, sxz, sxy, txz || txy ? sxyz : sx,
|
||||
tx, txz, txy, txz || txy ? txyz : tx);
|
||||
blockLight[0][x][y][z] = combine(bx, bxz, bxy, txz || txy ? bxyz : bx,
|
||||
tx, txz, txy, txz || txy ? txyz : tx);
|
||||
|
||||
skyLight [1][x][y][z] = combine(sy, sxy, syz, txy || tyz ? sxyz : sy,
|
||||
ty, txy, tyz, txy || tyz ? txyz : ty);
|
||||
blockLight[1][x][y][z] = combine(by, bxy, byz, txy || tyz ? bxyz : by,
|
||||
ty, txy, tyz, txy || tyz ? txyz : ty);
|
||||
|
||||
skyLight [2][x][y][z] = combine(sz, syz, sxz, tyz || txz ? sxyz : sz,
|
||||
tz, tyz, txz, tyz || txz ? txyz : tz);
|
||||
blockLight[2][x][y][z] = combine(bz, byz, bxz, tyz || txz ? bxyz : bz,
|
||||
tz, tyz, txz, tyz || txz ? txyz : tz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFlatLighting()
|
||||
{
|
||||
full = state.isFullCube();
|
||||
packed[0] = state.getPackedLightmapCoords(world, blockPos);
|
||||
|
||||
for (EnumFacing side : SIDES)
|
||||
{
|
||||
int i = side.ordinal() + 1;
|
||||
packed[i] = state.getPackedLightmapCoords(world, blockPos.offset(side));
|
||||
}
|
||||
}
|
||||
|
||||
public IBlockAccess getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
public IBlockState getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
public BlockPos getBlockPos()
|
||||
{
|
||||
return blockPos;
|
||||
}
|
||||
|
||||
public boolean[][][] getTranslucent()
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
public float[][][][] getSkyLight()
|
||||
{
|
||||
return skyLight;
|
||||
}
|
||||
|
||||
public float[][][][] getBlockLight()
|
||||
{
|
||||
return blockLight;
|
||||
}
|
||||
|
||||
public float[][][] getAo()
|
||||
{
|
||||
return ao;
|
||||
}
|
||||
|
||||
public int[] getPackedLight()
|
||||
{
|
||||
return packed;
|
||||
}
|
||||
|
||||
public boolean isFullCube()
|
||||
{
|
||||
return full;
|
||||
}
|
||||
|
||||
public float getShx()
|
||||
{
|
||||
return shx;
|
||||
}
|
||||
|
||||
public float getShy()
|
||||
{
|
||||
return shy;
|
||||
}
|
||||
|
||||
public float getShz()
|
||||
{
|
||||
return shz;
|
||||
}
|
||||
|
||||
public int getCachedTint()
|
||||
{
|
||||
return cachedTint;
|
||||
}
|
||||
|
||||
public int getCachedMultiplier()
|
||||
{
|
||||
return cachedMultiplier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.BlockModelRenderer;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.color.BlockColors;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
|
||||
public class ForgeBlockModelRenderer extends BlockModelRenderer
|
||||
{
|
||||
private final ThreadLocal<VertexLighterFlat> lighterFlat;
|
||||
private final ThreadLocal<VertexLighterSmoothAo> lighterSmooth;
|
||||
private final ThreadLocal<VertexBufferConsumer> wrFlat = new ThreadLocal<>();
|
||||
private final ThreadLocal<VertexBufferConsumer> wrSmooth = new ThreadLocal<>();
|
||||
private final ThreadLocal<BufferBuilder> lastRendererFlat = new ThreadLocal<>();
|
||||
private final ThreadLocal<BufferBuilder> lastRendererSmooth = new ThreadLocal<>();
|
||||
|
||||
public ForgeBlockModelRenderer(BlockColors colors)
|
||||
{
|
||||
super(colors);
|
||||
lighterFlat = ThreadLocal.withInitial(() -> new VertexLighterFlat(colors));
|
||||
lighterSmooth = ThreadLocal.withInitial(() -> new VertexLighterSmoothAo(colors));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renderModelFlat(IBlockAccess world, IBakedModel model, IBlockState state, BlockPos pos, BufferBuilder buffer, boolean checkSides, long rand)
|
||||
{
|
||||
if(ForgeModContainer.forgeLightPipelineEnabled)
|
||||
{
|
||||
if(buffer != lastRendererFlat.get())
|
||||
{
|
||||
lastRendererFlat.set(buffer);
|
||||
VertexBufferConsumer newCons = new VertexBufferConsumer(buffer);
|
||||
wrFlat.set(newCons);
|
||||
lighterFlat.get().setParent(newCons);
|
||||
}
|
||||
wrFlat.get().setOffset(pos);
|
||||
return render(lighterFlat.get(), world, model, state, pos, buffer, checkSides, rand);
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.renderModelFlat(world, model, state, pos, buffer, checkSides, rand);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renderModelSmooth(IBlockAccess world, IBakedModel model, IBlockState state, BlockPos pos, BufferBuilder buffer, boolean checkSides, long rand)
|
||||
{
|
||||
if(ForgeModContainer.forgeLightPipelineEnabled)
|
||||
{
|
||||
if(buffer != lastRendererSmooth.get())
|
||||
{
|
||||
lastRendererSmooth.set(buffer);
|
||||
VertexBufferConsumer newCons = new VertexBufferConsumer(buffer);
|
||||
wrSmooth.set(newCons);
|
||||
lighterSmooth.get().setParent(newCons);
|
||||
}
|
||||
wrSmooth.get().setOffset(pos);
|
||||
return render(lighterSmooth.get(), world, model, state, pos, buffer, checkSides, rand);
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.renderModelSmooth(world, model, state, pos, buffer, checkSides, rand);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean render(VertexLighterFlat lighter, IBlockAccess world, IBakedModel model, IBlockState state, BlockPos pos, BufferBuilder wr, boolean checkSides, long rand)
|
||||
{
|
||||
lighter.setWorld(world);
|
||||
lighter.setState(state);
|
||||
lighter.setBlockPos(pos);
|
||||
boolean empty = true;
|
||||
List<BakedQuad> quads = model.getQuads(state, null, rand);
|
||||
if(!quads.isEmpty())
|
||||
{
|
||||
lighter.updateBlockInfo();
|
||||
empty = false;
|
||||
for(BakedQuad quad : quads)
|
||||
{
|
||||
quad.pipe(lighter);
|
||||
}
|
||||
}
|
||||
for(EnumFacing side : EnumFacing.values())
|
||||
{
|
||||
quads = model.getQuads(state, side, rand);
|
||||
if(!quads.isEmpty())
|
||||
{
|
||||
if(!checkSides || state.shouldSideBeRendered(world, pos, side))
|
||||
{
|
||||
if(empty) lighter.updateBlockInfo();
|
||||
empty = false;
|
||||
for(BakedQuad quad : quads)
|
||||
{
|
||||
quad.pipe(lighter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lighter.resetBlockInfo();
|
||||
return !empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
/**
|
||||
* Assumes that the data length is not less than e.getElementCount().
|
||||
* Also assumes that element index passed will increment from 0 to format.getElementCount() - 1.
|
||||
* Normal, Color and UV are assumed to be in 0-1 range.
|
||||
*/
|
||||
public interface IVertexConsumer
|
||||
{
|
||||
/**
|
||||
* @return the format that should be used for passed data.
|
||||
*/
|
||||
VertexFormat getVertexFormat();
|
||||
|
||||
void setQuadTint(int tint);
|
||||
void setQuadOrientation(EnumFacing orientation);
|
||||
void setApplyDiffuseLighting(boolean diffuse);
|
||||
void setTexture(TextureAtlasSprite texture);
|
||||
void put(int element, float... data);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
|
||||
public interface IVertexProducer
|
||||
{
|
||||
/**
|
||||
* @param consumer consumer to receive the vertex data this producer can provide
|
||||
*/
|
||||
void pipe(IVertexConsumer consumer);
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class LightUtil
|
||||
{
|
||||
public static float diffuseLight(float x, float y, float z)
|
||||
{
|
||||
return Math.min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f);
|
||||
}
|
||||
|
||||
public static float diffuseLight(EnumFacing side)
|
||||
{
|
||||
switch(side)
|
||||
{
|
||||
case DOWN:
|
||||
return .5f;
|
||||
case UP:
|
||||
return 1f;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return .8f;
|
||||
default:
|
||||
return .6f;
|
||||
}
|
||||
}
|
||||
|
||||
public static EnumFacing toSide(float x, float y, float z)
|
||||
{
|
||||
if(Math.abs(x) > Math.abs(y))
|
||||
{
|
||||
if(Math.abs(x) > Math.abs(z))
|
||||
{
|
||||
if(x < 0) return EnumFacing.WEST;
|
||||
return EnumFacing.EAST;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(z < 0) return EnumFacing.NORTH;
|
||||
return EnumFacing.SOUTH;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Math.abs(y) > Math.abs(z))
|
||||
{
|
||||
if(y < 0) return EnumFacing.DOWN;
|
||||
return EnumFacing.UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(z < 0) return EnumFacing.NORTH;
|
||||
return EnumFacing.SOUTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final ConcurrentMap<Pair<VertexFormat, VertexFormat>, int[]> formatMaps = new ConcurrentHashMap<>();
|
||||
|
||||
public static void putBakedQuad(IVertexConsumer consumer, BakedQuad quad)
|
||||
{
|
||||
consumer.setTexture(quad.getSprite());
|
||||
consumer.setQuadOrientation(quad.getFace());
|
||||
if(quad.hasTintIndex())
|
||||
{
|
||||
consumer.setQuadTint(quad.getTintIndex());
|
||||
}
|
||||
consumer.setApplyDiffuseLighting(quad.shouldApplyDiffuseLighting());
|
||||
float[] data = new float[4];
|
||||
VertexFormat formatFrom = consumer.getVertexFormat();
|
||||
VertexFormat formatTo = quad.getFormat();
|
||||
int countFrom = formatFrom.getElementCount();
|
||||
int countTo = formatTo.getElementCount();
|
||||
int[] eMap = mapFormats(formatFrom, formatTo);
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
for(int e = 0; e < countFrom; e++)
|
||||
{
|
||||
if(eMap[e] != countTo)
|
||||
{
|
||||
unpack(quad.getVertexData(), data, formatTo, v, eMap[e]);
|
||||
consumer.put(e, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
consumer.put(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] mapFormats(VertexFormat from, VertexFormat to)
|
||||
{
|
||||
return formatMaps.computeIfAbsent(Pair.of(from, to), pair -> generateMapping(pair.getLeft(), pair.getRight()));
|
||||
}
|
||||
|
||||
private static int[] generateMapping(VertexFormat from, VertexFormat to)
|
||||
{
|
||||
int fromCount = from.getElementCount();
|
||||
int toCount = to.getElementCount();
|
||||
int[] eMap = new int[fromCount];
|
||||
|
||||
for(int e = 0; e < fromCount; e++)
|
||||
{
|
||||
VertexFormatElement expected = from.getElement(e);
|
||||
int e2;
|
||||
for(e2 = 0; e2 < toCount; e2++)
|
||||
{
|
||||
VertexFormatElement current = to.getElement(e2);
|
||||
if(expected.getUsage() == current.getUsage() && expected.getIndex() == current.getIndex())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
eMap[e] = e2;
|
||||
}
|
||||
return eMap;
|
||||
}
|
||||
|
||||
public static void unpack(int[] from, float[] to, VertexFormat formatFrom, int v, int e)
|
||||
{
|
||||
int length = 4 < to.length ? 4 : to.length;
|
||||
VertexFormatElement element = formatFrom.getElement(e);
|
||||
int vertexStart = v * formatFrom.getNextOffset() + formatFrom.getOffset(e);
|
||||
int count = element.getElementCount();
|
||||
VertexFormatElement.EnumType type = element.getType();
|
||||
int size = type.getSize();
|
||||
int mask = (256 << (8 * (size - 1))) - 1;
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
if(i < count)
|
||||
{
|
||||
int pos = vertexStart + size * i;
|
||||
int index = pos >> 2;
|
||||
int offset = pos & 3;
|
||||
int bits = from[index];
|
||||
bits = bits >>> (offset * 8);
|
||||
if((pos + size - 1) / 4 != index)
|
||||
{
|
||||
bits |= from[index + 1] << ((4 - offset) * 8);
|
||||
}
|
||||
bits &= mask;
|
||||
if(type == VertexFormatElement.EnumType.FLOAT)
|
||||
{
|
||||
to[i] = Float.intBitsToFloat(bits);
|
||||
}
|
||||
else if(type == VertexFormatElement.EnumType.UBYTE || type == VertexFormatElement.EnumType.USHORT)
|
||||
{
|
||||
to[i] = (float)bits / mask;
|
||||
}
|
||||
else if(type == VertexFormatElement.EnumType.UINT)
|
||||
{
|
||||
to[i] = (float)((double)(bits & 0xFFFFFFFFL) / 0xFFFFFFFFL);
|
||||
}
|
||||
else if(type == VertexFormatElement.EnumType.BYTE)
|
||||
{
|
||||
to[i] = ((float)(byte)bits) / (mask >> 1);
|
||||
}
|
||||
else if(type == VertexFormatElement.EnumType.SHORT)
|
||||
{
|
||||
to[i] = ((float)(short)bits) / (mask >> 1);
|
||||
}
|
||||
else if(type == VertexFormatElement.EnumType.INT)
|
||||
{
|
||||
to[i] = (float)((double)(bits & 0xFFFFFFFFL) / (0xFFFFFFFFL >> 1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
to[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void pack(float[] from, int[] to, VertexFormat formatTo, int v, int e)
|
||||
{
|
||||
VertexFormatElement element = formatTo.getElement(e);
|
||||
int vertexStart = v * formatTo.getNextOffset() + formatTo.getOffset(e);
|
||||
int count = element.getElementCount();
|
||||
VertexFormatElement.EnumType type = element.getType();
|
||||
int size = type.getSize();
|
||||
int mask = (256 << (8 * (size - 1))) - 1;
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
if(i < count)
|
||||
{
|
||||
int pos = vertexStart + size * i;
|
||||
int index = pos >> 2;
|
||||
int offset = pos & 3;
|
||||
int bits = 0;
|
||||
float f = i < from.length ? from[i] : 0;
|
||||
if(type == VertexFormatElement.EnumType.FLOAT)
|
||||
{
|
||||
bits = Float.floatToRawIntBits(f);
|
||||
}
|
||||
else if(
|
||||
type == VertexFormatElement.EnumType.UBYTE ||
|
||||
type == VertexFormatElement.EnumType.USHORT ||
|
||||
type == VertexFormatElement.EnumType.UINT
|
||||
)
|
||||
{
|
||||
bits = Math.round(f * mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
bits = Math.round(f * (mask >> 1));
|
||||
}
|
||||
to[index] &= ~(mask << (offset * 8));
|
||||
to[index] |= (((bits & mask) << (offset * 8)));
|
||||
// TODO handle overflow into to[index + 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IVertexConsumer tessellator = null;
|
||||
public static IVertexConsumer getTessellator()
|
||||
{
|
||||
if(tessellator == null)
|
||||
{
|
||||
Tessellator tes = Tessellator.getInstance();
|
||||
BufferBuilder wr = tes.getBuffer();
|
||||
tessellator = new VertexBufferConsumer(wr);
|
||||
}
|
||||
return tessellator;
|
||||
}
|
||||
|
||||
private static ItemConsumer itemConsumer = null;
|
||||
public static ItemConsumer getItemConsumer()
|
||||
{
|
||||
if(itemConsumer == null)
|
||||
{
|
||||
itemConsumer = new ItemConsumer(getTessellator());
|
||||
}
|
||||
return itemConsumer;
|
||||
}
|
||||
|
||||
// renders quad in any Vertex Format, but is slower
|
||||
public static void renderQuadColorSlow(BufferBuilder wr, BakedQuad quad, int auxColor)
|
||||
{
|
||||
ItemConsumer cons;
|
||||
if(wr == Tessellator.getInstance().getBuffer())
|
||||
{
|
||||
cons = getItemConsumer();
|
||||
}
|
||||
else
|
||||
{
|
||||
cons = new ItemConsumer(new VertexBufferConsumer(wr));
|
||||
}
|
||||
float b = (float)(auxColor & 0xFF) / 0xFF;
|
||||
float g = (float)((auxColor >>> 8) & 0xFF) / 0xFF;
|
||||
float r = (float)((auxColor >>> 16) & 0xFF) / 0xFF;
|
||||
float a = (float)((auxColor >>> 24) & 0xFF) / 0xFF;
|
||||
|
||||
cons.setAuxColor(r, g, b, a);
|
||||
quad.pipe(cons);
|
||||
}
|
||||
|
||||
public static void renderQuadColor(BufferBuilder wr, BakedQuad quad, int auxColor)
|
||||
{
|
||||
if (quad.getFormat().equals(wr.getVertexFormat()))
|
||||
{
|
||||
wr.addVertexData(quad.getVertexData());
|
||||
ForgeHooksClient.putQuadColor(wr, quad, auxColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderQuadColorSlow(wr, quad, auxColor);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemConsumer extends VertexTransformer
|
||||
{
|
||||
private int vertices = 0;
|
||||
|
||||
private float[] auxColor = new float[]{1, 1, 1, 1};
|
||||
private float[] buf = new float[4];
|
||||
|
||||
public ItemConsumer(IVertexConsumer parent)
|
||||
{
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public void setAuxColor(float... auxColor)
|
||||
{
|
||||
System.arraycopy(auxColor, 0, this.auxColor, 0, this.auxColor.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data)
|
||||
{
|
||||
if(getVertexFormat().getElement(element).getUsage() == EnumUsage.COLOR)
|
||||
{
|
||||
System.arraycopy(auxColor, 0, buf, 0, buf.length);
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
buf[i] *= data[i];
|
||||
}
|
||||
super.put(element, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.put(element, data);
|
||||
}
|
||||
if(element == getVertexFormat().getElementCount() - 1)
|
||||
{
|
||||
vertices++;
|
||||
if(vertices == 4)
|
||||
{
|
||||
vertices = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
|
||||
public abstract class QuadGatheringTransformer implements IVertexConsumer
|
||||
{
|
||||
protected IVertexConsumer parent;
|
||||
protected VertexFormat format;
|
||||
protected int vertices = 0;
|
||||
|
||||
protected byte[] dataLength = null;
|
||||
protected float[][][] quadData = null;
|
||||
|
||||
public void setParent(IVertexConsumer parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setVertexFormat(VertexFormat format)
|
||||
{
|
||||
this.format = format;
|
||||
dataLength = new byte[format.getElementCount()];
|
||||
quadData = new float[format.getElementCount()][4][4];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat()
|
||||
{
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data)
|
||||
{
|
||||
System.arraycopy(data, 0, quadData[element][vertices], 0, data.length);
|
||||
if(element == getVertexFormat().getElementCount() - 1) vertices++;
|
||||
if(vertices == 0)
|
||||
{
|
||||
dataLength[element] = (byte)data.length;
|
||||
}
|
||||
else if(vertices == 4)
|
||||
{
|
||||
vertices = 0;
|
||||
processQuad();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void processQuad();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
|
||||
public abstract class TransformerConsumer implements IVertexConsumer {
|
||||
private IVertexConsumer parent;
|
||||
|
||||
protected TransformerConsumer(IVertexConsumer parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat()
|
||||
{
|
||||
return parent.getVertexFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data)
|
||||
{
|
||||
float[] newData = transform(element, data);
|
||||
parent.put(element, newData);
|
||||
}
|
||||
|
||||
protected abstract float[] transform(int element, float... data);
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
// advantages: non-fixed-length vertex format, no overhead of packing and unpacking attributes to transform the model
|
||||
// disadvantages: (possibly) larger memory footprint, overhead on packing the attributes at the final rendering stage
|
||||
public class UnpackedBakedQuad extends BakedQuad
|
||||
{
|
||||
protected final float[][][] unpackedData;
|
||||
protected final VertexFormat format;
|
||||
protected boolean packed = false;
|
||||
|
||||
public UnpackedBakedQuad(float[][][] unpackedData, int tint, EnumFacing orientation, TextureAtlasSprite texture, boolean applyDiffuseLighting, VertexFormat format)
|
||||
{
|
||||
super(new int[format.getNextOffset() /* / 4 * 4 */], tint, orientation, texture, applyDiffuseLighting, format);
|
||||
this.unpackedData = unpackedData;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getVertexData()
|
||||
{
|
||||
if(!packed)
|
||||
{
|
||||
packed = true;
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
for(int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
LightUtil.pack(unpackedData[v][e], vertexData, format, v, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return vertexData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pipe(IVertexConsumer consumer)
|
||||
{
|
||||
int[] eMap = LightUtil.mapFormats(consumer.getVertexFormat(), format);
|
||||
|
||||
if(hasTintIndex())
|
||||
{
|
||||
consumer.setQuadTint(getTintIndex());
|
||||
}
|
||||
consumer.setTexture(sprite);
|
||||
consumer.setApplyDiffuseLighting(applyDiffuseLighting);
|
||||
consumer.setQuadOrientation(getFace());
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
for(int e = 0; e < consumer.getVertexFormat().getElementCount(); e++)
|
||||
{
|
||||
if(eMap[e] != format.getElementCount())
|
||||
{
|
||||
consumer.put(e, unpackedData[v][eMap[e]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
consumer.put(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder implements IVertexConsumer
|
||||
{
|
||||
private final VertexFormat format;
|
||||
private final float[][][] unpackedData;
|
||||
private int tint = -1;
|
||||
private EnumFacing orientation;
|
||||
private TextureAtlasSprite texture;
|
||||
private boolean applyDiffuseLighting = true;
|
||||
|
||||
private int vertices = 0;
|
||||
private int elements = 0;
|
||||
private boolean full = false;
|
||||
private boolean contractUVs = false;
|
||||
|
||||
public Builder(VertexFormat format)
|
||||
{
|
||||
this.format = format;
|
||||
unpackedData = new float[4][format.getElementCount()][4];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat()
|
||||
{
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setContractUVs(boolean value)
|
||||
{
|
||||
this.contractUVs = value;
|
||||
}
|
||||
@Override
|
||||
public void setQuadTint(int tint)
|
||||
{
|
||||
this.tint = tint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadOrientation(EnumFacing orientation)
|
||||
{
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
// FIXME: move (or at least add) into constructor
|
||||
@Override
|
||||
public void setTexture(TextureAtlasSprite texture)
|
||||
{
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse)
|
||||
{
|
||||
this.applyDiffuseLighting = diffuse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data)
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
if(i < data.length)
|
||||
{
|
||||
unpackedData[vertices][element][i] = data[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
unpackedData[vertices][element][i] = 0;
|
||||
}
|
||||
}
|
||||
elements++;
|
||||
if(elements == format.getElementCount())
|
||||
{
|
||||
vertices++;
|
||||
elements = 0;
|
||||
}
|
||||
if(vertices == 4)
|
||||
{
|
||||
full = true;
|
||||
}
|
||||
}
|
||||
|
||||
private final float eps = 1f / 0x100;
|
||||
|
||||
public UnpackedBakedQuad build()
|
||||
{
|
||||
if(!full)
|
||||
{
|
||||
throw new IllegalStateException("not enough data");
|
||||
}
|
||||
if(texture == null)
|
||||
{
|
||||
throw new IllegalStateException("texture not set");
|
||||
}
|
||||
if(contractUVs)
|
||||
{
|
||||
float tX = texture.getIconWidth() / (texture.getMaxU() - texture.getMinU());
|
||||
float tY = texture.getIconHeight() / (texture.getMaxV() - texture.getMinV());
|
||||
float tS = tX > tY ? tX : tY;
|
||||
float ep = 1f / (tS * 0x100);
|
||||
int uve = 0;
|
||||
while(uve < format.getElementCount())
|
||||
{
|
||||
VertexFormatElement e = format.getElement(uve);
|
||||
if(e.getUsage() == VertexFormatElement.EnumUsage.UV && e.getIndex() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
uve++;
|
||||
}
|
||||
if(uve == format.getElementCount())
|
||||
{
|
||||
throw new IllegalStateException("Can't contract UVs: format doesn't contain UVs");
|
||||
}
|
||||
float[] uvc = new float[4];
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
uvc[i] += unpackedData[v][uve][i] / 4;
|
||||
}
|
||||
}
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float uo = unpackedData[v][uve][i];
|
||||
float un = uo * (1 - eps) + uvc[i] * eps;
|
||||
float ud = uo - un;
|
||||
float aud = ud;
|
||||
if(aud < 0) aud = -aud;
|
||||
if(aud < ep) // not moving a fraction of a pixel
|
||||
{
|
||||
float udc = uo - uvc[i];
|
||||
if(udc < 0) udc = -udc;
|
||||
if(udc < 2 * ep) // center is closer than 2 fractions of a pixel, don't move too close
|
||||
{
|
||||
un = (uo + uvc[i]) / 2;
|
||||
}
|
||||
else // move at least by a fraction
|
||||
{
|
||||
un = uo + (ud < 0 ? ep : -ep);
|
||||
}
|
||||
}
|
||||
unpackedData[v][uve][i] = un;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new UnpackedBakedQuad(unpackedData, tint, orientation, texture, applyDiffuseLighting, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
/**
|
||||
* Assumes VertexFormatElement is present in the BufferBuilder's vertex format.
|
||||
*/
|
||||
public class VertexBufferConsumer implements IVertexConsumer
|
||||
{
|
||||
private static final float[] dummyColor = new float[]{ 1, 1, 1, 1 };
|
||||
private final BufferBuilder renderer;
|
||||
private final int[] quadData;
|
||||
private int v = 0;
|
||||
private BlockPos offset = BlockPos.ORIGIN;
|
||||
|
||||
public VertexBufferConsumer(BufferBuilder renderer)
|
||||
{
|
||||
super();
|
||||
this.renderer = renderer;
|
||||
quadData = new int[renderer.getVertexFormat().getNextOffset()/* / 4 * 4 */];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat()
|
||||
{
|
||||
return renderer.getVertexFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int e, float... data)
|
||||
{
|
||||
VertexFormat format = getVertexFormat();
|
||||
if(renderer.isColorDisabled() && format.getElement(e).getUsage() == EnumUsage.COLOR)
|
||||
{
|
||||
data = dummyColor;
|
||||
}
|
||||
LightUtil.pack(data, quadData, format, v, e);
|
||||
if(e == format.getElementCount() - 1)
|
||||
{
|
||||
v++;
|
||||
if(v == 4)
|
||||
{
|
||||
renderer.addVertexData(quadData);
|
||||
renderer.putPosition(offset.getX(), offset.getY(), offset.getZ());
|
||||
//Arrays.fill(quadData, 0);
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOffset(BlockPos offset)
|
||||
{
|
||||
this.offset = new BlockPos(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint) {}
|
||||
@Override
|
||||
public void setQuadOrientation(EnumFacing orientation) {}
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse) {}
|
||||
@Override
|
||||
public void setTexture(TextureAtlasSprite texture ) {}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import javax.vecmath.Vector3f;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.color.BlockColors;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class VertexLighterFlat extends QuadGatheringTransformer
|
||||
{
|
||||
protected static final VertexFormatElement NORMAL_4F = new VertexFormatElement(0, VertexFormatElement.EnumType.FLOAT, VertexFormatElement.EnumUsage.NORMAL, 4);
|
||||
|
||||
protected final BlockInfo blockInfo;
|
||||
private int tint = -1;
|
||||
private boolean diffuse = true;
|
||||
|
||||
protected int posIndex = -1;
|
||||
protected int normalIndex = -1;
|
||||
protected int colorIndex = -1;
|
||||
protected int lightmapIndex = -1;
|
||||
|
||||
protected VertexFormat baseFormat;
|
||||
|
||||
public VertexLighterFlat(BlockColors colors)
|
||||
{
|
||||
this.blockInfo = new BlockInfo(colors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(IVertexConsumer parent)
|
||||
{
|
||||
super.setParent(parent);
|
||||
setVertexFormat(parent.getVertexFormat());
|
||||
}
|
||||
|
||||
private void updateIndices()
|
||||
{
|
||||
for(int i = 0; i < getVertexFormat().getElementCount(); i++)
|
||||
{
|
||||
switch(getVertexFormat().getElement(i).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
posIndex = i;
|
||||
break;
|
||||
case NORMAL:
|
||||
normalIndex = i;
|
||||
break;
|
||||
case COLOR:
|
||||
colorIndex = i;
|
||||
break;
|
||||
case UV:
|
||||
if(getVertexFormat().getElement(i).getIndex() == 1)
|
||||
{
|
||||
lightmapIndex = i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
if(posIndex == -1)
|
||||
{
|
||||
throw new IllegalArgumentException("vertex lighter needs format with position");
|
||||
}
|
||||
if(lightmapIndex == -1)
|
||||
{
|
||||
throw new IllegalArgumentException("vertex lighter needs format with lightmap");
|
||||
}
|
||||
if(colorIndex == -1)
|
||||
{
|
||||
throw new IllegalArgumentException("vertex lighter needs format with color");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVertexFormat(VertexFormat format)
|
||||
{
|
||||
if (Objects.equals(format, baseFormat)) return;
|
||||
baseFormat = format;
|
||||
super.setVertexFormat(withNormal(format));
|
||||
updateIndices();
|
||||
}
|
||||
|
||||
private static VertexFormat withNormal(VertexFormat format)
|
||||
{
|
||||
if (format == null || format.hasNormal()) return format;
|
||||
return new VertexFormat(format).addElement(NORMAL_4F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processQuad()
|
||||
{
|
||||
float[][] position = quadData[posIndex];
|
||||
float[][] normal = null;
|
||||
float[][] lightmap = quadData[lightmapIndex];
|
||||
float[][] color = quadData[colorIndex];
|
||||
|
||||
if (dataLength[normalIndex] >= 3
|
||||
&& (quadData[normalIndex][0][0] != -1
|
||||
|| quadData[normalIndex][0][1] != -1
|
||||
|| quadData[normalIndex][0][2] != -1))
|
||||
{
|
||||
normal = quadData[normalIndex];
|
||||
}
|
||||
else // normals must be generated
|
||||
{
|
||||
normal = new float[4][4];
|
||||
Vector3f v1 = new Vector3f(position[3]);
|
||||
Vector3f t = new Vector3f(position[1]);
|
||||
Vector3f v2 = new Vector3f(position[2]);
|
||||
v1.sub(t);
|
||||
t.set(position[0]);
|
||||
v2.sub(t);
|
||||
v1.cross(v2, v1);
|
||||
v1.normalize();
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
normal[v][0] = v1.x;
|
||||
normal[v][1] = v1.y;
|
||||
normal[v][2] = v1.z;
|
||||
normal[v][3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int multiplier = -1;
|
||||
if(tint != -1)
|
||||
{
|
||||
multiplier = blockInfo.getColorMultiplier(tint);
|
||||
}
|
||||
|
||||
VertexFormat format = parent.getVertexFormat();
|
||||
int count = format.getElementCount();
|
||||
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
position[v][0] += blockInfo.getShx();
|
||||
position[v][1] += blockInfo.getShy();
|
||||
position[v][2] += blockInfo.getShz();
|
||||
|
||||
float x = position[v][0] - .5f;
|
||||
float y = position[v][1] - .5f;
|
||||
float z = position[v][2] - .5f;
|
||||
|
||||
//if(blockInfo.getBlock().isFullCube())
|
||||
{
|
||||
x += normal[v][0] * .5f;
|
||||
y += normal[v][1] * .5f;
|
||||
z += normal[v][2] * .5f;
|
||||
}
|
||||
|
||||
float blockLight = lightmap[v][0], skyLight = lightmap[v][1];
|
||||
updateLightmap(normal[v], lightmap[v], x, y, z);
|
||||
if(dataLength[lightmapIndex] > 1)
|
||||
{
|
||||
if(blockLight > lightmap[v][0]) lightmap[v][0] = blockLight;
|
||||
if(skyLight > lightmap[v][1]) lightmap[v][1] = skyLight;
|
||||
}
|
||||
updateColor(normal[v], color[v], x, y, z, tint, multiplier);
|
||||
if(diffuse)
|
||||
{
|
||||
float d = LightUtil.diffuseLight(normal[v][0], normal[v][1], normal[v][2]);
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
color[v][i] *= d;
|
||||
}
|
||||
}
|
||||
if(EntityRenderer.anaglyphEnable)
|
||||
{
|
||||
applyAnaglyph(color[v]);
|
||||
}
|
||||
|
||||
// no need for remapping cause all we could've done is add 1 element to the end
|
||||
for(int e = 0; e < count; e++)
|
||||
{
|
||||
VertexFormatElement element = format.getElement(e);
|
||||
switch(element.getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
// position adding moved to VertexBufferConsumer due to x and z not fitting completely into a float
|
||||
/*float[] pos = new float[4];
|
||||
System.arraycopy(position[v], 0, pos, 0, position[v].length);
|
||||
pos[0] += blockInfo.getBlockPos().getX();
|
||||
pos[1] += blockInfo.getBlockPos().getY();
|
||||
pos[2] += blockInfo.getBlockPos().getZ();*/
|
||||
parent.put(e, position[v]);
|
||||
break;
|
||||
case NORMAL: if(normalIndex != -1)
|
||||
{
|
||||
parent.put(e, normal[v]);
|
||||
break;
|
||||
}
|
||||
case COLOR:
|
||||
parent.put(e, color[v]);
|
||||
break;
|
||||
case UV: if(element.getIndex() == 1)
|
||||
{
|
||||
parent.put(e, lightmap[v]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
parent.put(e, quadData[e][v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
tint = -1;
|
||||
}
|
||||
|
||||
protected void applyAnaglyph(float[] color)
|
||||
{
|
||||
float r = color[0];
|
||||
color[0] = (r * 30 + color[1] * 59 + color[2] * 11) / 100;
|
||||
color[1] = (r * 3 + color[1] * 7) / 10;
|
||||
color[2] = (r * 3 + color[2] * 7) / 10;
|
||||
}
|
||||
|
||||
protected void updateLightmap(float[] normal, float[] lightmap, float x, float y, float z)
|
||||
{
|
||||
final float e1 = 1f - 1e-2f;
|
||||
final float e2 = 0.95f;
|
||||
|
||||
boolean full = blockInfo.isFullCube();
|
||||
EnumFacing side = null;
|
||||
|
||||
if((full || y < -e1) && normal[1] < -e2) side = EnumFacing.DOWN;
|
||||
else if((full || y > e1) && normal[1] > e2) side = EnumFacing.UP;
|
||||
else if((full || z < -e1) && normal[2] < -e2) side = EnumFacing.NORTH;
|
||||
else if((full || z > e1) && normal[2] > e2) side = EnumFacing.SOUTH;
|
||||
else if((full || x < -e1) && normal[0] < -e2) side = EnumFacing.WEST;
|
||||
else if((full || x > e1) && normal[0] > e2) side = EnumFacing.EAST;
|
||||
|
||||
int i = side == null ? 0 : side.ordinal() + 1;
|
||||
int brightness = blockInfo.getPackedLight()[i];
|
||||
|
||||
lightmap[0] = ((float)((brightness >> 0x04) & 0xF) * 0x20) / 0xFFFF;
|
||||
lightmap[1] = ((float)((brightness >> 0x14) & 0xF) * 0x20) / 0xFFFF;
|
||||
}
|
||||
|
||||
protected void updateColor(float[] normal, float[] color, float x, float y, float z, float tint, int multiplier)
|
||||
{
|
||||
if(tint != -1)
|
||||
{
|
||||
color[0] *= (float)(multiplier >> 0x10 & 0xFF) / 0xFF;
|
||||
color[1] *= (float)(multiplier >> 0x8 & 0xFF) / 0xFF;
|
||||
color[2] *= (float)(multiplier & 0xFF) / 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint)
|
||||
{
|
||||
this.tint = tint;
|
||||
}
|
||||
@Override
|
||||
public void setQuadOrientation(EnumFacing orientation) {}
|
||||
public void setQuadCulled() {}
|
||||
@Override
|
||||
public void setTexture(TextureAtlasSprite texture) {}
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse)
|
||||
{
|
||||
this.diffuse = diffuse;
|
||||
}
|
||||
|
||||
public void setWorld(IBlockAccess world)
|
||||
{
|
||||
blockInfo.setWorld(world);
|
||||
}
|
||||
|
||||
public void setState(IBlockState state)
|
||||
{
|
||||
blockInfo.setState(state);
|
||||
}
|
||||
|
||||
public void setBlockPos(BlockPos blockPos)
|
||||
{
|
||||
blockInfo.setBlockPos(blockPos);
|
||||
}
|
||||
|
||||
public void resetBlockInfo()
|
||||
{
|
||||
blockInfo.reset();
|
||||
}
|
||||
|
||||
public void updateBlockInfo()
|
||||
{
|
||||
blockInfo.updateShift();
|
||||
blockInfo.updateFlatLighting();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.color.BlockColors;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
|
||||
public class VertexLighterSmoothAo extends VertexLighterFlat
|
||||
{
|
||||
public VertexLighterSmoothAo(BlockColors colors)
|
||||
{
|
||||
super(colors);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateLightmap(float[] normal, float[] lightmap, float x, float y, float z)
|
||||
{
|
||||
lightmap[0] = calcLightmap(blockInfo.getBlockLight(), x, y, z);
|
||||
lightmap[1] = calcLightmap(blockInfo.getSkyLight(), x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateColor(float[] normal, float[] color, float x, float y, float z, float tint, int multiplier)
|
||||
{
|
||||
super.updateColor(normal, color, x, y, z, tint, multiplier);
|
||||
float a = getAo(x, y, z);
|
||||
color[0] *= a;
|
||||
color[1] *= a;
|
||||
color[2] *= a;
|
||||
}
|
||||
|
||||
protected float calcLightmap(float[][][][] light, float x, float y, float z)
|
||||
{
|
||||
x *= 2;
|
||||
y *= 2;
|
||||
z *= 2;
|
||||
float l2 = x * x + y * y + z * z;
|
||||
if(l2 > 6 - 2e-2f)
|
||||
{
|
||||
float s = (float)Math.sqrt((6 - 2e-2f) / l2);
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
}
|
||||
float ax = x > 0 ? x : -x;
|
||||
float ay = y > 0 ? y : -y;
|
||||
float az = z > 0 ? z : -z;
|
||||
float e1 = 1 + 1e-4f;
|
||||
if(ax > 2 - 1e-4f && ay <= e1 && az <= e1)
|
||||
{
|
||||
x = x < 0 ? -2 + 1e-4f : 2 - 1e-4f;
|
||||
}
|
||||
else if(ay > 2 - 1e-4f && az <= e1 && ax <= e1)
|
||||
{
|
||||
y = y < 0 ? -2 + 1e-4f : 2 - 1e-4f;
|
||||
}
|
||||
else if(az > 2 - 1e-4f && ax <= e1 && ay <= e1)
|
||||
{
|
||||
z = z < 0 ? -2 + 1e-4f : 2 - 1e-4f;
|
||||
}
|
||||
ax = x > 0 ? x : -x;
|
||||
ay = y > 0 ? y : -y;
|
||||
az = z > 0 ? z : -z;
|
||||
if(ax <= e1 && ay + az > 3f - 1e-4f)
|
||||
{
|
||||
float s = (3f - 1e-4f) / (ay + az);
|
||||
y *= s;
|
||||
z *= s;
|
||||
}
|
||||
else if(ay <= e1 && az + ax > 3f - 1e-4f)
|
||||
{
|
||||
float s = (3f - 1e-4f) / (az + ax);
|
||||
z *= s;
|
||||
x *= s;
|
||||
}
|
||||
else if(az <= e1 && ax + ay > 3f - 1e-4f)
|
||||
{
|
||||
float s = (3f - 1e-4f) / (ax + ay);
|
||||
x *= s;
|
||||
y *= s;
|
||||
}
|
||||
else if(ax + ay + az > 4 - 1e-4f)
|
||||
{
|
||||
float s = (4 - 1e-4f) / (ax + ay + az);
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
}
|
||||
|
||||
float l = 0;
|
||||
float s = 0;
|
||||
|
||||
for(int ix = 0; ix <= 1; ix++)
|
||||
{
|
||||
for(int iy = 0; iy <= 1; iy++)
|
||||
{
|
||||
for(int iz = 0; iz <= 1; iz++)
|
||||
{
|
||||
float vx = x * (1 - ix * 2);
|
||||
float vy = y * (1 - iy * 2);
|
||||
float vz = z * (1 - iz * 2);
|
||||
|
||||
float s3 = vx + vy + vz + 4;
|
||||
float sx = vy + vz + 3;
|
||||
float sy = vz + vx + 3;
|
||||
float sz = vx + vy + 3;
|
||||
|
||||
float bx = (2 * vx + vy + vz + 6) / (s3 * sy * sz * (vx + 2));
|
||||
s += bx;
|
||||
l += bx * light[0][ix][iy][iz];
|
||||
|
||||
float by = (2 * vy + vz + vx + 6) / (s3 * sz * sx * (vy + 2));
|
||||
s += by;
|
||||
l += by * light[1][ix][iy][iz];
|
||||
|
||||
float bz = (2 * vz + vx + vy + 6) / (s3 * sx * sy * (vz + 2));
|
||||
s += bz;
|
||||
l += bz * light[2][ix][iy][iz];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l /= s;
|
||||
|
||||
if(l > 15f * 0x20 / 0xFFFF) l = 15f * 0x20 / 0xFFFF;
|
||||
if(l < 0) l = 0;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
protected float getAo(float x, float y, float z)
|
||||
{
|
||||
int sx = x < 0 ? 1 : 2;
|
||||
int sy = y < 0 ? 1 : 2;
|
||||
int sz = z < 0 ? 1 : 2;
|
||||
|
||||
if(x < 0) x++;
|
||||
if(y < 0) y++;
|
||||
if(z < 0) z++;
|
||||
|
||||
float a = 0;
|
||||
float[][][] ao = blockInfo.getAo();
|
||||
a += ao[sx - 1][sy - 1][sz - 1] * (1 - x) * (1 - y) * (1 - z);
|
||||
a += ao[sx - 1][sy - 1][sz - 0] * (1 - x) * (1 - y) * (0 + z);
|
||||
a += ao[sx - 1][sy - 0][sz - 1] * (1 - x) * (0 + y) * (1 - z);
|
||||
a += ao[sx - 1][sy - 0][sz - 0] * (1 - x) * (0 + y) * (0 + z);
|
||||
a += ao[sx - 0][sy - 1][sz - 1] * (0 + x) * (1 - y) * (1 - z);
|
||||
a += ao[sx - 0][sy - 1][sz - 0] * (0 + x) * (1 - y) * (0 + z);
|
||||
a += ao[sx - 0][sy - 0][sz - 1] * (0 + x) * (0 + y) * (1 - z);
|
||||
a += ao[sx - 0][sy - 0][sz - 0] * (0 + x) * (0 + y) * (0 + z);
|
||||
|
||||
a = MathHelper.clamp(a, 0, 1);
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBlockInfo()
|
||||
{
|
||||
blockInfo.updateShift();
|
||||
blockInfo.updateLightMatrix();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.model.pipeline;
|
||||
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
public class VertexTransformer implements IVertexConsumer
|
||||
{
|
||||
protected final IVertexConsumer parent;
|
||||
|
||||
public VertexTransformer(IVertexConsumer parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat()
|
||||
{
|
||||
return parent.getVertexFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint)
|
||||
{
|
||||
parent.setQuadTint(tint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexture(TextureAtlasSprite texture)
|
||||
{
|
||||
parent.setTexture(texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadOrientation(EnumFacing orientation)
|
||||
{
|
||||
parent.setQuadOrientation(orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse)
|
||||
{
|
||||
parent.setApplyDiffuseLighting(diffuse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data)
|
||||
{
|
||||
parent.put(element, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraftforge.client.model.pipeline;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.client.resource;
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* Represents a generic type of reloadable resource. Used for resource reload filtering.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public interface IResourceType
|
||||
{
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user