818 lines
35 KiB
Java
818 lines
35 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2020.
|
|
*
|
|
* 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 com.google.common.collect.ImmutableList;
|
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
|
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
|
import net.minecraft.block.BlockState;
|
|
import net.minecraft.client.MainWindow;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.MouseHelper;
|
|
import net.minecraft.client.audio.ISound;
|
|
import net.minecraft.client.audio.SoundEngine;
|
|
import net.minecraft.client.gui.AbstractGui;
|
|
import net.minecraft.client.gui.ClientBossInfo;
|
|
import net.minecraft.client.gui.FontRenderer;
|
|
import net.minecraft.client.gui.screen.BiomeGeneratorTypeScreens;
|
|
import net.minecraft.client.gui.screen.MainMenuScreen;
|
|
import net.minecraft.client.gui.screen.Screen;
|
|
import net.minecraft.client.network.play.NetworkPlayerInfo;
|
|
import net.minecraft.client.renderer.*;
|
|
import net.minecraft.client.renderer.FogRenderer.FogType;
|
|
import net.minecraft.client.renderer.color.BlockColors;
|
|
import net.minecraft.client.renderer.color.ItemColors;
|
|
import net.minecraft.client.renderer.entity.model.BipedModel;
|
|
import net.minecraft.client.renderer.model.IBakedModel;
|
|
import net.minecraft.client.renderer.model.ItemCameraTransforms;
|
|
import net.minecraft.client.renderer.model.ModelManager;
|
|
import net.minecraft.client.renderer.model.RenderMaterial;
|
|
import net.minecraft.client.renderer.texture.AtlasTexture;
|
|
import net.minecraft.client.renderer.texture.NativeImage;
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
import net.minecraft.client.renderer.vertex.VertexFormat;
|
|
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
|
import net.minecraft.client.renderer.vertex.VertexFormatElement.Usage;
|
|
import net.minecraft.client.resources.I18n;
|
|
import net.minecraft.client.settings.KeyBinding;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.LivingEntity;
|
|
import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance;
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
import net.minecraft.fluid.Fluid;
|
|
import net.minecraft.fluid.FluidState;
|
|
import net.minecraft.inventory.EquipmentSlotType;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.item.crafting.RecipeManager;
|
|
import net.minecraft.util.Direction;
|
|
import net.minecraft.util.Hand;
|
|
import net.minecraft.util.MovementInput;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.util.math.BlockRayTraceResult;
|
|
import net.minecraft.util.math.EntityRayTraceResult;
|
|
import net.minecraft.util.math.RayTraceResult;
|
|
import net.minecraft.util.math.vector.Matrix3f;
|
|
import net.minecraft.util.math.vector.Matrix4f;
|
|
import net.minecraft.util.math.vector.TransformationMatrix;
|
|
import net.minecraft.util.math.vector.Vector3f;
|
|
import net.minecraft.util.text.ITextComponent;
|
|
import net.minecraft.util.text.TextFormatting;
|
|
import net.minecraft.util.text.TranslationTextComponent;
|
|
import net.minecraft.world.GameType;
|
|
import net.minecraft.world.IBlockDisplayReader;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.gen.settings.DimensionGeneratorSettings;
|
|
import net.minecraftforge.client.event.*;
|
|
import net.minecraftforge.client.event.sound.PlaySoundEvent;
|
|
import net.minecraftforge.client.model.ModelLoader;
|
|
import net.minecraftforge.client.model.animation.Animation;
|
|
import net.minecraftforge.common.ForgeMod;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.common.model.TransformationHelper;
|
|
import net.minecraftforge.eventbus.api.Event;
|
|
import net.minecraftforge.fml.ModLoader;
|
|
import net.minecraftforge.fml.VersionChecker;
|
|
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
|
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
|
import net.minecraftforge.registries.ForgeRegistries;
|
|
import net.minecraftforge.resource.ReloadRequirements;
|
|
import net.minecraftforge.resource.SelectiveReloadStateHandler;
|
|
import net.minecraftforge.resource.VanillaResourceType;
|
|
import net.minecraftforge.versions.forge.ForgeVersion;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy;
|
|
import org.apache.logging.log4j.core.impl.ReusableLogEventFactory;
|
|
import org.lwjgl.opengl.GL13;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
import java.io.File;
|
|
import java.lang.reflect.Field;
|
|
import java.nio.Buffer;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Random;
|
|
import java.util.Set;
|
|
import java.util.stream.Stream;
|
|
|
|
import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.BOSSINFO;
|
|
import static net.minecraftforge.fml.VersionChecker.Status.BETA;
|
|
import static net.minecraftforge.fml.VersionChecker.Status.BETA_OUTDATED;
|
|
import static org.lwjgl.opengl.GL11.*;
|
|
import static org.lwjgl.opengl.GL20.*;
|
|
|
|
public class ForgeHooksClient
|
|
{
|
|
private static final Logger LOGGER = LogManager.getLogger();
|
|
|
|
//private static final ResourceLocation ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
|
|
|
|
public static String getArmorTexture(Entity entity, ItemStack armor, String _default, EquipmentSlotType slot, String type)
|
|
{
|
|
String result = armor.getItem().getArmorTexture(armor, entity, slot, type);
|
|
return result != null ? result : _default;
|
|
}
|
|
|
|
//TODO: Rename to onDrawHighlight
|
|
public static boolean onDrawBlockHighlight(WorldRenderer context, ActiveRenderInfo info, RayTraceResult target, float partialTicks, MatrixStack matrix, IRenderTypeBuffer buffers)
|
|
{
|
|
switch (target.getType()) {
|
|
case BLOCK:
|
|
if (!(target instanceof BlockRayTraceResult)) return false;
|
|
return MinecraftForge.EVENT_BUS.post(new DrawHighlightEvent.HighlightBlock(context, info, target, partialTicks, matrix, buffers));
|
|
case ENTITY:
|
|
if (!(target instanceof EntityRayTraceResult)) return false;
|
|
return MinecraftForge.EVENT_BUS.post(new DrawHighlightEvent.HighlightEntity(context, info, target, partialTicks, matrix, buffers));
|
|
default:
|
|
return MinecraftForge.EVENT_BUS.post(new DrawHighlightEvent(context, info, target, partialTicks, matrix, buffers));
|
|
}
|
|
}
|
|
|
|
public static void dispatchRenderLast(WorldRenderer context, MatrixStack mat, float partialTicks, Matrix4f projectionMatrix, long finishTimeNano)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, mat, partialTicks, projectionMatrix, finishTimeNano));
|
|
}
|
|
|
|
public static boolean renderSpecificFirstPersonHand(Hand hand, MatrixStack mat, IRenderTypeBuffer buffers, int light, float partialTicks, float interpPitch, float swingProgress, float equipProgress, ItemStack stack)
|
|
{
|
|
return MinecraftForge.EVENT_BUS.post(new RenderHandEvent(hand, mat, buffers, light, partialTicks, interpPitch, swingProgress, equipProgress, stack));
|
|
}
|
|
|
|
public static void onTextureStitchedPre(AtlasTexture map, Set<ResourceLocation> resourceLocations)
|
|
{
|
|
StartupMessageManager.mcLoaderConsumer().ifPresent(c->c.accept("Atlas Stitching : "+map.getTextureLocation().toString()));
|
|
ModLoader.get().postEvent(new TextureStitchEvent.Pre(map, resourceLocations));
|
|
// ModelLoader.White.INSTANCE.register(map); // TODO Custom TAS
|
|
}
|
|
|
|
public static void onTextureStitchedPost(AtlasTexture map)
|
|
{
|
|
ModLoader.get().postEvent(new TextureStitchEvent.Post(map));
|
|
}
|
|
|
|
public static void onBlockColorsInit(BlockColors blockColors)
|
|
{
|
|
ModLoader.get().postEvent(new ColorHandlerEvent.Block(blockColors));
|
|
}
|
|
|
|
public static void onItemColorsInit(ItemColors itemColors, BlockColors blockColors)
|
|
{
|
|
ModLoader.get().postEvent(new ColorHandlerEvent.Item(itemColors, blockColors));
|
|
}
|
|
|
|
static final ThreadLocal<RenderType> renderLayer = new ThreadLocal<RenderType>();
|
|
|
|
public static void setRenderLayer(RenderType layer)
|
|
{
|
|
renderLayer.set(layer);
|
|
}
|
|
|
|
public static <A extends BipedModel<?>> A getArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlotType slot, A _default)
|
|
{
|
|
A 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;
|
|
}
|
|
}
|
|
/* TODO mouse input
|
|
public static boolean postMouseEvent()
|
|
{
|
|
return MinecraftForge.EVENT_BUS.post(new MouseEvent());
|
|
}
|
|
*/
|
|
public static float getOffsetFOV(PlayerEntity entity, float fov)
|
|
{
|
|
FOVUpdateEvent fovUpdateEvent = new FOVUpdateEvent(entity, fov);
|
|
MinecraftForge.EVENT_BUS.post(fovUpdateEvent);
|
|
return fovUpdateEvent.getNewfov();
|
|
}
|
|
|
|
public static double getFOVModifier(GameRenderer renderer, ActiveRenderInfo info, double renderPartialTicks, double fov) {
|
|
EntityViewRenderEvent.FOVModifier event = new EntityViewRenderEvent.FOVModifier(renderer, info, renderPartialTicks, fov);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
return event.getFOV();
|
|
}
|
|
|
|
/**
|
|
* Initialization of Forge Renderers.
|
|
*/
|
|
static
|
|
{
|
|
//FluidRegistry.renderIdFluid = RenderingRegistry.getNextAvailableRenderId();
|
|
//RenderingRegistry.registerBlockHandler(RenderBlockFluid.instance);
|
|
}
|
|
|
|
public static void renderMainMenu(MainMenuScreen gui, MatrixStack mStack, FontRenderer font, int width, int height)
|
|
{
|
|
VersionChecker.Status status = ForgeVersion.getStatus();
|
|
if (status == BETA || status == BETA_OUTDATED)
|
|
{
|
|
// render a warning at the top of the screen,
|
|
ITextComponent line = new TranslationTextComponent("forge.update.beta.1", TextFormatting.RED, TextFormatting.RESET).mergeStyle(TextFormatting.RED);
|
|
AbstractGui.drawCenteredString(mStack, font, line, width / 2, 4 + (0 * (font.FONT_HEIGHT + 1)), -1);
|
|
line = new TranslationTextComponent("forge.update.beta.2");
|
|
AbstractGui.drawCenteredString(mStack, font, line, width / 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;
|
|
}
|
|
|
|
forgeStatusLine = line;
|
|
}
|
|
|
|
public static String forgeStatusLine;
|
|
public static ISound playSound(SoundEngine 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(Screen screen, MatrixStack mStack, int mouseX, int mouseY, float partialTicks)
|
|
{
|
|
if (!MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.DrawScreenEvent.Pre(screen, mStack, mouseX, mouseY, partialTicks)))
|
|
screen.render(mStack, mouseX, mouseY, partialTicks);
|
|
MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.DrawScreenEvent.Post(screen, mStack, mouseX, mouseY, partialTicks));
|
|
}
|
|
|
|
public static float getFogDensity(FogType type, ActiveRenderInfo info, float partial, float density)
|
|
{
|
|
EntityViewRenderEvent.FogDensity event = new EntityViewRenderEvent.FogDensity(type, info, partial, density);
|
|
if (MinecraftForge.EVENT_BUS.post(event)) return event.getDensity();
|
|
return -1;
|
|
}
|
|
|
|
public static void onFogRender(FogType type, ActiveRenderInfo info, float partial, float distance)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new EntityViewRenderEvent.RenderFogEvent(type, info, partial, distance));
|
|
}
|
|
|
|
public static EntityViewRenderEvent.CameraSetup onCameraSetup(GameRenderer renderer, ActiveRenderInfo info, float partial)
|
|
{
|
|
EntityViewRenderEvent.CameraSetup event = new EntityViewRenderEvent.CameraSetup(renderer, info, partial, info.getYaw(), info.getPitch(), 0);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
return event;
|
|
}
|
|
|
|
public static void onModelBake(ModelManager modelManager, Map<ResourceLocation, IBakedModel> modelRegistry, ModelLoader modelLoader)
|
|
{
|
|
ModLoader.get().postEvent(new ModelBakeEvent(modelManager, modelRegistry, modelLoader));
|
|
modelLoader.onPostBakeEvent(modelRegistry);
|
|
}
|
|
|
|
private static final Matrix4f flipX;
|
|
private static final Matrix3f flipXNormal;
|
|
static {
|
|
flipX = Matrix4f.makeScale(-1,1,1);
|
|
flipXNormal = new Matrix3f(flipX);
|
|
}
|
|
|
|
public static IBakedModel handleCameraTransforms(MatrixStack matrixStack, IBakedModel model, ItemCameraTransforms.TransformType cameraTransformType, boolean leftHandHackery)
|
|
{
|
|
MatrixStack stack = new MatrixStack();
|
|
model = model.handlePerspective(cameraTransformType, stack);
|
|
|
|
// If the stack is not empty, the code has added a matrix for us to use.
|
|
if (!stack.clear())
|
|
{
|
|
// Apply the transformation to the real matrix stack, flipping for left hand
|
|
Matrix4f tMat = stack.getLast().getMatrix();
|
|
Matrix3f nMat = stack.getLast().getNormal();
|
|
if (leftHandHackery)
|
|
{
|
|
tMat.multiplyBackward(flipX);
|
|
tMat.mul(flipX);
|
|
nMat.multiplyBackward(flipXNormal);
|
|
nMat.mul(flipXNormal);
|
|
}
|
|
matrixStack.getLast().getMatrix().mul(tMat);
|
|
matrixStack.getLast().getNormal().mul(nMat);
|
|
}
|
|
return model;
|
|
}
|
|
|
|
// moved and expanded from WorldVertexBufferUploader.draw
|
|
|
|
public static void preDraw(Usage attrType, VertexFormat format, int element, int stride, ByteBuffer buffer)
|
|
{
|
|
VertexFormatElement attr = format.getElements().get(element);
|
|
int count = attr.getElementCount();
|
|
int constant = attr.getType().getGlConstant();
|
|
((Buffer)buffer).position(format.getOffset(element));
|
|
switch(attrType)
|
|
{
|
|
case POSITION:
|
|
glVertexPointer(count, constant, stride, buffer);
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
break;
|
|
case NORMAL:
|
|
if(count != 3)
|
|
{
|
|
throw new IllegalArgumentException("Normal attribute should have the size 3: " + attr);
|
|
}
|
|
glNormalPointer(constant, stride, buffer);
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
break;
|
|
case COLOR:
|
|
glColorPointer(count, constant, stride, buffer);
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
break;
|
|
case UV:
|
|
GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + attr.getIndex());
|
|
glTexCoordPointer(count, constant, stride, buffer);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
|
|
break;
|
|
case PADDING:
|
|
break;
|
|
case GENERIC:
|
|
glEnableVertexAttribArray(attr.getIndex());
|
|
glVertexAttribPointer(attr.getIndex(), count, constant, false, stride, buffer);
|
|
break;
|
|
default:
|
|
LOGGER.fatal("Unimplemented vanilla attribute upload: {}", attrType.getDisplayName());
|
|
}
|
|
}
|
|
|
|
public static void postDraw(Usage attrType, VertexFormat format, int element, int stride, ByteBuffer buffer)
|
|
{
|
|
VertexFormatElement attr = format.getElements().get(element);
|
|
switch(attrType)
|
|
{
|
|
case POSITION:
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
break;
|
|
case NORMAL:
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
break;
|
|
case COLOR:
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
break;
|
|
case UV:
|
|
GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + attr.getIndex());
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
|
|
break;
|
|
case PADDING:
|
|
break;
|
|
case GENERIC:
|
|
glDisableVertexAttribArray(attr.getIndex());
|
|
break;
|
|
default:
|
|
LOGGER.fatal("Unimplemented vanilla attribute upload: {}", attrType.getDisplayName());
|
|
}
|
|
}
|
|
|
|
public static int getColorIndex(VertexFormat fmt)
|
|
{
|
|
ImmutableList<VertexFormatElement> elements = fmt.getElements();
|
|
for(int i=0;i<elements.size();i++)
|
|
{
|
|
if (elements.get(i).getUsage() == Usage.COLOR)
|
|
return i;
|
|
}
|
|
throw new IndexOutOfBoundsException("There is no COLOR element in the provided VertexFormat.");
|
|
}
|
|
|
|
// TODO: IVertexBuilder doesn't have a means to modify existing data.
|
|
/*
|
|
public static void putQuadColor(IVertexBuilder renderer, BakedQuad quad, float cr, float cg, float cb, float ca)
|
|
{
|
|
VertexFormat format = quad.getFormat();
|
|
int size = format.getIntegerSize();
|
|
int offset = format.getOffset(getColorIndex(format)) / 4; // assumes that color is aligned
|
|
boolean hasColor = format.hasColor();
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
int vc = hasColor ? quad.getVertexData()[offset + size * i] : 0xFFFFFFFF;
|
|
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);
|
|
}
|
|
}*/
|
|
|
|
@SuppressWarnings("deprecation")
|
|
public static TextureAtlasSprite[] getFluidSprites(IBlockDisplayReader world, BlockPos pos, FluidState fluidStateIn)
|
|
{
|
|
ResourceLocation overlayTexture = fluidStateIn.getFluid().getAttributes().getOverlayTexture();
|
|
return new TextureAtlasSprite[] {
|
|
Minecraft.getInstance().getAtlasSpriteGetter(AtlasTexture.LOCATION_BLOCKS_TEXTURE).apply(fluidStateIn.getFluid().getAttributes().getStillTexture(world, pos)),
|
|
Minecraft.getInstance().getAtlasSpriteGetter(AtlasTexture.LOCATION_BLOCKS_TEXTURE).apply(fluidStateIn.getFluid().getAttributes().getFlowingTexture(world, pos)),
|
|
overlayTexture == null ? null : Minecraft.getInstance().getAtlasSpriteGetter(AtlasTexture.LOCATION_BLOCKS_TEXTURE).apply(overlayTexture),
|
|
};
|
|
}
|
|
|
|
public static void gatherFluidTextures(Set<RenderMaterial> textures)
|
|
{
|
|
ForgeRegistries.FLUIDS.getValues().stream()
|
|
.flatMap(ForgeHooksClient::getFluidMaterials)
|
|
.forEach(textures::add);
|
|
}
|
|
|
|
public static Stream<RenderMaterial> getFluidMaterials(Fluid fluid)
|
|
{
|
|
return fluid.getAttributes().getTextures()
|
|
.filter(Objects::nonNull)
|
|
.map(ForgeHooksClient::getBlockMaterial);
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
public static RenderMaterial getBlockMaterial(ResourceLocation loc)
|
|
{
|
|
return new RenderMaterial(AtlasTexture.LOCATION_BLOCKS_TEXTURE, loc);
|
|
}
|
|
|
|
/**
|
|
* internal, relies on fixed format of FaceBakery
|
|
*/
|
|
// TODO Do we need this?
|
|
public static void fillNormal(int[] faceData, Direction facing)
|
|
{
|
|
Vector3f v1 = getVertexPos(faceData, 3);
|
|
Vector3f t1 = getVertexPos(faceData, 1);
|
|
Vector3f v2 = getVertexPos(faceData, 2);
|
|
Vector3f t2 = getVertexPos(faceData, 0);
|
|
v1.sub(t1);
|
|
v2.sub(t2);
|
|
v2.cross(v1);
|
|
v2.normalize();
|
|
|
|
int x = ((byte) Math.round(v2.getX() * 127)) & 0xFF;
|
|
int y = ((byte) Math.round(v2.getY() * 127)) & 0xFF;
|
|
int z = ((byte) Math.round(v2.getZ() * 127)) & 0xFF;
|
|
|
|
int normal = x | (y << 0x08) | (z << 0x10);
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
faceData[i * 8 + 7] = normal;
|
|
}
|
|
}
|
|
|
|
private static Vector3f getVertexPos(int[] data, int vertex)
|
|
{
|
|
int idx = vertex * 8;
|
|
|
|
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);
|
|
}
|
|
|
|
public static void loadEntityShader(Entity entity, GameRenderer entityRenderer)
|
|
{
|
|
if (entity != null)
|
|
{
|
|
ResourceLocation shader = ClientRegistry.getEntityShader(entity.getClass());
|
|
if (shader != null)
|
|
{
|
|
entityRenderer.loadShader(shader);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 RenderGameOverlayEvent.BossInfo bossBarRenderPre(MatrixStack mStack, MainWindow res, ClientBossInfo bossInfo, int x, int y, int increment)
|
|
{
|
|
RenderGameOverlayEvent.BossInfo evt = new RenderGameOverlayEvent.BossInfo(mStack, new RenderGameOverlayEvent(mStack, Animation.getPartialTickTime(), res),
|
|
BOSSINFO, bossInfo, x, y, increment);
|
|
MinecraftForge.EVENT_BUS.post(evt);
|
|
return evt;
|
|
}
|
|
|
|
public static void bossBarRenderPost(MatrixStack mStack, MainWindow res)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(mStack, new RenderGameOverlayEvent(mStack, Animation.getPartialTickTime(), res), BOSSINFO));
|
|
}
|
|
|
|
public static ScreenshotEvent onScreenshot(NativeImage image, File screenshotFile)
|
|
{
|
|
ScreenshotEvent event = new ScreenshotEvent(image, screenshotFile);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
return event;
|
|
}
|
|
|
|
public static void onClientChangeGameMode(NetworkPlayerInfo info, GameType currentGameMode, GameType newGameMode)
|
|
{
|
|
if (currentGameMode != newGameMode)
|
|
{
|
|
ClientPlayerChangeGameModeEvent evt = new ClientPlayerChangeGameModeEvent(info, currentGameMode, newGameMode);
|
|
MinecraftForge.EVENT_BUS.post(evt);
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
public static IBakedModel handlePerspective(IBakedModel model, ItemCameraTransforms.TransformType type, MatrixStack stack)
|
|
{
|
|
TransformationMatrix tr = TransformationHelper.toTransformation(model.getItemCameraTransforms().getTransform(type));
|
|
if(!tr.isIdentity()) {
|
|
tr.push(stack);
|
|
}
|
|
return model;
|
|
}
|
|
|
|
public static void onInputUpdate(PlayerEntity player, MovementInput movementInput)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new InputUpdateEvent(player, movementInput));
|
|
}
|
|
|
|
public static void refreshResources(Minecraft mc, VanillaResourceType... types) {
|
|
SelectiveReloadStateHandler.INSTANCE.beginReload(ReloadRequirements.include(types));
|
|
mc.reloadResources();
|
|
SelectiveReloadStateHandler.INSTANCE.endReload();
|
|
}
|
|
|
|
public static boolean onGuiMouseClickedPre(Screen guiScreen, double mouseX, double mouseY, int button)
|
|
{
|
|
Event event = new GuiScreenEvent.MouseClickedEvent.Pre(guiScreen, mouseX, mouseY, button);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseClickedPost(Screen guiScreen, double mouseX, double mouseY, int button)
|
|
{
|
|
Event event = new GuiScreenEvent.MouseClickedEvent.Post(guiScreen, mouseX, mouseY, button);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseReleasedPre(Screen guiScreen, double mouseX, double mouseY, int button)
|
|
{
|
|
Event event = new GuiScreenEvent.MouseReleasedEvent.Pre(guiScreen, mouseX, mouseY, button);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseReleasedPost(Screen guiScreen, double mouseX, double mouseY, int button)
|
|
{
|
|
Event event = new GuiScreenEvent.MouseReleasedEvent.Post(guiScreen, mouseX, mouseY, button);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseDragPre(Screen guiScreen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY)
|
|
{
|
|
Event event = new GuiScreenEvent.MouseDragEvent.Pre(guiScreen, mouseX, mouseY, mouseButton, dragX, dragY);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseDragPost(Screen guiScreen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY)
|
|
{
|
|
Event event = new GuiScreenEvent.MouseDragEvent.Post(guiScreen, mouseX, mouseY, mouseButton, dragX, dragY);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseScrollPre(MouseHelper mouseHelper, Screen guiScreen, double scrollDelta)
|
|
{
|
|
MainWindow mainWindow = guiScreen.getMinecraft().getMainWindow();
|
|
double mouseX = mouseHelper.getMouseX() * (double) mainWindow.getScaledWidth() / (double) mainWindow.getWidth();
|
|
double mouseY = mouseHelper.getMouseY() * (double) mainWindow.getScaledHeight() / (double) mainWindow.getHeight();
|
|
Event event = new GuiScreenEvent.MouseScrollEvent.Pre(guiScreen, mouseX, mouseY, scrollDelta);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiMouseScrollPost(MouseHelper mouseHelper, Screen guiScreen, double scrollDelta)
|
|
{
|
|
MainWindow mainWindow = guiScreen.getMinecraft().getMainWindow();
|
|
double mouseX = mouseHelper.getMouseX() * (double) mainWindow.getScaledWidth() / (double) mainWindow.getWidth();
|
|
double mouseY = mouseHelper.getMouseY() * (double) mainWindow.getScaledHeight() / (double) mainWindow.getHeight();
|
|
Event event = new GuiScreenEvent.MouseScrollEvent.Post(guiScreen, mouseX, mouseY, scrollDelta);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiKeyPressedPre(Screen guiScreen, int keyCode, int scanCode, int modifiers)
|
|
{
|
|
Event event = new GuiScreenEvent.KeyboardKeyPressedEvent.Pre(guiScreen, keyCode, scanCode, modifiers);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiKeyPressedPost(Screen guiScreen, int keyCode, int scanCode, int modifiers)
|
|
{
|
|
Event event = new GuiScreenEvent.KeyboardKeyPressedEvent.Post(guiScreen, keyCode, scanCode, modifiers);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiKeyReleasedPre(Screen guiScreen, int keyCode, int scanCode, int modifiers)
|
|
{
|
|
Event event = new GuiScreenEvent.KeyboardKeyReleasedEvent.Pre(guiScreen, keyCode, scanCode, modifiers);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiKeyReleasedPost(Screen guiScreen, int keyCode, int scanCode, int modifiers)
|
|
{
|
|
Event event = new GuiScreenEvent.KeyboardKeyReleasedEvent.Post(guiScreen, keyCode, scanCode, modifiers);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiCharTypedPre(Screen guiScreen, char codePoint, int modifiers)
|
|
{
|
|
Event event = new GuiScreenEvent.KeyboardCharTypedEvent.Pre(guiScreen, codePoint, modifiers);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onGuiCharTypedPost(Screen guiScreen, char codePoint, int modifiers)
|
|
{
|
|
Event event = new GuiScreenEvent.KeyboardCharTypedEvent.Post(guiScreen, codePoint, modifiers);
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static void onRecipesUpdated(RecipeManager mgr)
|
|
{
|
|
Event event = new RecipesUpdatedEvent(mgr);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
// Resets cached thread fields in ThreadNameCachingStrategy and ReusableLogEventFactory to be repopulated during their next access.
|
|
// This serves a workaround for no built-in method of triggering this type of refresh as brought up by LOG4J2-2178.
|
|
public static void invalidateLog4jThreadCache()
|
|
{
|
|
if (System.getProperty("java.version").compareTo("1.8.0_102") >= 0) return; // skip for later JDKs, because it's not CACHED see LOG4J2-2052
|
|
try
|
|
{
|
|
Field nameField = ThreadNameCachingStrategy.class.getDeclaredField("THREADLOCAL_NAME");
|
|
Field logEventField = ReusableLogEventFactory.class.getDeclaredField("mutableLogEventThreadLocal");
|
|
nameField.setAccessible(true);
|
|
logEventField.setAccessible(true);
|
|
((ThreadLocal<?>) nameField.get(null)).set(null);
|
|
((ThreadLocal<?>) logEventField.get(null)).set(null);
|
|
}
|
|
catch (ReflectiveOperationException | NoClassDefFoundError e)
|
|
{
|
|
LOGGER.error("Unable to invalidate log4j thread cache, thread fields in logs may be inaccurate", e);
|
|
}
|
|
}
|
|
|
|
public static void fireMouseInput(int button, int action, int mods)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new InputEvent.MouseInputEvent(button, action, mods));
|
|
}
|
|
|
|
public static void fireKeyInput(int key, int scanCode, int action, int modifiers)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new InputEvent.KeyInputEvent(key, scanCode, action, modifiers));
|
|
}
|
|
|
|
public static boolean onMouseScroll(MouseHelper mouseHelper, double scrollDelta)
|
|
{
|
|
Event event = new InputEvent.MouseScrollEvent(scrollDelta, mouseHelper.isLeftDown(), mouseHelper.isMiddleDown(), mouseHelper.isRightDown(), mouseHelper.getMouseX(), mouseHelper.getMouseY());
|
|
return MinecraftForge.EVENT_BUS.post(event);
|
|
}
|
|
|
|
public static boolean onRawMouseClicked(int button, int action, int mods)
|
|
{
|
|
return MinecraftForge.EVENT_BUS.post(new InputEvent.RawMouseEvent(button, action, mods));
|
|
}
|
|
|
|
public static InputEvent.ClickInputEvent onClickInput(int button, KeyBinding keyBinding, Hand hand)
|
|
{
|
|
InputEvent.ClickInputEvent event = new InputEvent.ClickInputEvent(button, keyBinding, hand);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
return event;
|
|
}
|
|
|
|
public static void drawItemLayered(ItemRenderer renderer, IBakedModel modelIn, ItemStack itemStackIn, MatrixStack matrixStackIn,
|
|
IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn, boolean fabulous)
|
|
{
|
|
for(com.mojang.datafixers.util.Pair<IBakedModel,RenderType> layerModel : modelIn.getLayerModels(itemStackIn, fabulous))
|
|
{
|
|
IBakedModel layer = layerModel.getFirst();
|
|
RenderType rendertype = layerModel.getSecond();
|
|
net.minecraftforge.client.ForgeHooksClient.setRenderLayer(rendertype); // neded for compatibility with MultiLayerModels
|
|
IVertexBuilder ivertexbuilder;
|
|
if (fabulous)
|
|
{
|
|
ivertexbuilder = ItemRenderer.getEntityGlintVertexBuilder(bufferIn, rendertype, true, itemStackIn.hasEffect());
|
|
} else {
|
|
ivertexbuilder = ItemRenderer.getBuffer(bufferIn, rendertype, true, itemStackIn.hasEffect());
|
|
}
|
|
renderer.renderModel(layer, itemStackIn, combinedLightIn, combinedOverlayIn, matrixStackIn, ivertexbuilder);
|
|
}
|
|
net.minecraftforge.client.ForgeHooksClient.setRenderLayer(null);
|
|
}
|
|
|
|
public static boolean isNameplateInRenderDistance(Entity entity, double squareDistance) {
|
|
if (entity instanceof LivingEntity) {
|
|
final ModifiableAttributeInstance attribute = ((LivingEntity) entity).getAttribute(ForgeMod.NAMETAG_DISTANCE.get());
|
|
if (attribute != null) {
|
|
return !(squareDistance > (attribute.getValue() * attribute.getValue()));
|
|
}
|
|
}
|
|
return !(squareDistance > 4096.0f);
|
|
}
|
|
|
|
public static void renderPistonMovedBlocks(BlockPos pos, BlockState state, MatrixStack stack, IRenderTypeBuffer buffer, World world, boolean checkSides, int combinedOverlay, BlockRendererDispatcher blockRenderer) {
|
|
RenderType.getBlockRenderTypes().stream()
|
|
.filter(t -> RenderTypeLookup.canRenderInLayer(state, t))
|
|
.forEach(rendertype ->
|
|
{
|
|
rendertype = rendertype == RenderType.getTranslucent() ? RenderType.getTranslucentMovingBlock() : rendertype;
|
|
setRenderLayer(rendertype);
|
|
IVertexBuilder ivertexbuilder = buffer.getBuffer(rendertype);
|
|
blockRenderer.getBlockModelRenderer().renderModel(world, blockRenderer.getModelForState(state), state, pos, stack, ivertexbuilder, checkSides, new Random(), state.getPositionRandom(pos), combinedOverlay);
|
|
});
|
|
setRenderLayer(null);
|
|
}
|
|
|
|
public static void registerForgeWorldTypeScreens()
|
|
{
|
|
ForgeWorldTypeScreens.registerTypes();
|
|
}
|
|
|
|
public static BiomeGeneratorTypeScreens.IFactory getBiomeGeneratorTypeScreenFactory(Optional<BiomeGeneratorTypeScreens> generator, @Nullable BiomeGeneratorTypeScreens.IFactory biomegeneratortypescreens$ifactory)
|
|
{
|
|
return ForgeWorldTypeScreens.getGeneratorScreenFactory(generator, biomegeneratortypescreens$ifactory);
|
|
}
|
|
|
|
public static boolean hasBiomeGeneratorSettingsOptionsScreen(Optional<BiomeGeneratorTypeScreens> generator)
|
|
{
|
|
return getBiomeGeneratorTypeScreenFactory(generator, null) != null;
|
|
}
|
|
|
|
public static Optional<BiomeGeneratorTypeScreens> getWorldTypeFromGenerator(DimensionGeneratorSettings dimensionGeneratorSettings)
|
|
{
|
|
return BiomeGeneratorTypeScreens.func_239079_a_(dimensionGeneratorSettings);
|
|
}
|
|
|
|
public static Optional<BiomeGeneratorTypeScreens> getDefaultWorldType()
|
|
{
|
|
return Optional.of(ForgeWorldTypeScreens.getDefaultGenerator());
|
|
}
|
|
}
|