Начинающий
- Статус
- Оффлайн
- Регистрация
- 13 Янв 2025
- Сообщения
- 32
- Реакции
- 0
- Выберите загрузчик игры
- Vanilla
- Forge
- Fabric
- OptiFine
Функция улучшает визуал зелий при броске
Отображает время до падения, Круг действия зелья, название эффекта
Отображает время до падения, Круг действия зелья, название эффекта
Код:
package wtf.loft.functions.impl.render;
import com.google.common.eventbus.Subscribe;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.PotionEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.potion.*;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceContext.BlockMode;
import net.minecraft.util.math.RayTraceContext.FluidMode;
import net.minecraft.util.math.RayTraceResult.Type;
import net.minecraft.util.math.vector.Vector2f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.registry.Registry;
import org.lwjgl.opengl.GL11;
import wtf.loft.events.EventDisplay;
import wtf.loft.events.WorldEvent;
import wtf.loft.functions.api.Category;
import wtf.loft.functions.api.Function;
import wtf.loft.functions.api.FunctionRegister;
import wtf.loft.utils.projections.ProjectionUtil;
import wtf.loft.utils.render.ColorUtils;
import wtf.loft.utils.render.DisplayUtils;
import wtf.loft.utils.render.font.Fonts;
import java.util.ArrayList;
import java.util.List;
@FunctionRegister(
name = "PotionProject",
type = Category.Render
)
public class PotionProject extends Function {
private float lineWidth = 1.5F;
final List<ThrowablePoint> throwablePoints = new ArrayList<>();
private final List<PotionRadius> potionRadii = new ArrayList<>();
@Subscribe
public void onRender(EventDisplay e) {
for(ThrowablePoint throwablePoint : this.throwablePoints) {
Vector3d pos = throwablePoint.position;
Vector2f projection = ProjectionUtil.project(pos.x, pos.y - 0.3, pos.z);
int ticks = throwablePoint.ticks;
ResourceLocation texture = throwablePoint.texture;
if (!projection.equals(new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE))) {
boolean isMoving = ticks > 0;
if (isMoving) {
double time = (double)(ticks * 50) / 1000.0;
String text = String.format("%.1f сек.", time);
float width = Fonts.montserrat.getWidth(text, 5.0F);
float textWidth = width + 8.0F + 8.0F;
float posX = projection.x - textWidth / 2.0F;
float posY = projection.y;
DisplayUtils.drawRoundedRect(posX + 2.0F, posY + 2.0F - 3.0F, textWidth - 4.0F, 9.0F, 0.0F, ColorUtils.rgba(24, 24, 24, 80));
DisplayUtils.drawImage(texture, (float)((int)posX + 4), (float)((int)posY + 2 + 1 - 4), 8.0F, 8.0F, -1);
Fonts.montserrat.drawText(e.getMatrixStack(), text, posX + 14.0F, posY + 4.5F - 4.0F, -1, 5.0F);
}
}
}
for(PotionRadius radius : potionRadii) {
Vector2f projection = ProjectionUtil.project(radius.position.x, radius.position.y, radius.position.z);
if (!projection.equals(new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE))) {
String effectText = getEffectText(radius.potionType);
String radiusText = String.format("%.1f блоков", radius.radius);
float effectWidth = Fonts.montserrat.getWidth(effectText, 5.0F);
float radiusWidth = Fonts.montserrat.getWidth(radiusText, 5.0F);
float posX = projection.x - Math.max(effectWidth, radiusWidth) / 2.0F;
float posY = projection.y - 20.0F;
Fonts.montserrat.drawText(e.getMatrixStack(), effectText, posX, posY, getTextColor(radius.potionType), 5.0F);
Fonts.montserrat.drawText(e.getMatrixStack(), radiusText, posX, posY + 10.0F, -1, 5.0F);
}
}
}
@Subscribe
public void onWorldRender(WorldEvent event) {
GL11.glPushMatrix();
GL11.glDisable(3553);
GL11.glDisable(2929);
GL11.glEnable(3042);
GL11.glEnable(2848);
Vector3d renderOffset = mc.getRenderManager().info.getProjectedView();
GL11.glTranslated(-renderOffset.x, -renderOffset.y, -renderOffset.z);
GL11.glLineWidth(this.lineWidth);
buffer.begin(1, DefaultVertexFormats.POSITION);
this.throwablePoints.clear();
this.potionRadii.clear();
for(Entity entity : mc.world.getAllEntities()) {
if (entity instanceof PotionEntity potion) {
if (isExplosivePotion(potion)) {
this.processPotion(potion);
}
}
}
tessellator.draw();
if (!potionRadii.isEmpty()) {
buffer.begin(6, DefaultVertexFormats.POSITION_COLOR);
for (PotionRadius radius : potionRadii) {
Vector3d pos = radius.position;
float r = radius.radius;
int baseColor = getPotionColor(radius.potionType);
int darkColor = ColorUtils.rgba(0, 0, 0, 80);
int edgeColor = ColorUtils.rgba(0, 0, 0, 30);
buffer.pos(pos.x, pos.y, pos.z).color(darkColor).endVertex();
for (int i = 0; i <= 360; i += 10) {
double x = pos.x + Math.sin(Math.toRadians(i)) * r;
double z = pos.z + Math.cos(Math.toRadians(i)) * r;
buffer.pos(x, pos.y, z).color(edgeColor).endVertex();
}
}
tessellator.draw();
buffer.begin(3, DefaultVertexFormats.POSITION_COLOR);
for (PotionRadius radius : potionRadii) {
Vector3d pos = radius.position;
float r = radius.radius;
int color = getPotionColor(radius.potionType);
for (int i = 0; i <= 360; i += 5) {
double x = pos.x + Math.sin(Math.toRadians(i)) * r;
double z = pos.z + Math.cos(Math.toRadians(i)) * r;
buffer.pos(x, pos.y, z).color(color).endVertex();
}
buffer.pos(pos.x + Math.sin(0), pos.y, pos.z + Math.cos(0)).color(color).endVertex();
if (radius.potionType.equals("HARMING") || radius.potionType.equals("POISON")) {
for (int i = 0; i <= 360; i += 10) {
double x = pos.x + Math.sin(Math.toRadians(i)) * (r * 0.7);
double z = pos.z + Math.cos(Math.toRadians(i)) * (r * 0.7);
buffer.pos(x, pos.y + 0.1, z).color(color).endVertex();
}
}
}
tessellator.draw();
}
GL11.glDisable(3042);
GL11.glDisable(2848);
GL11.glEnable(3553);
GL11.glEnable(2929);
GL11.glPopMatrix();
}
private String getEffectText(String potionType) {
if (potionType.equals("OTHER")) {
return "Кастомное зелье";
}
switch(potionType) {
case "HARMING": return "Урон";
case "POISON": return "Яд";
case "SLOWNESS": return "Замедление";
case "WEAKNESS": return "Слабость";
case "INSTANT_HEALTH": return "Мгновенное лечение";
case "REGENERATION": return "Регенерация";
case "FIRE_RESISTANCE": return "Огнестойкость";
case "WATER_BREATHING": return "Подводное дыхание";
case "INVISIBILITY": return "Невидимость";
case "NIGHT_VISION": return "Ночное зрение";
case "JUMP_BOOST": return "Прыжок";
case "SPEED": return "Скорость";
case "STRENGTH": return "Сила";
default: return "Эффект";
}
}
private int getTextColor(String potionType) {
if (potionType.equals("OTHER")) {
return ColorUtils.rgba(200, 0, 200, 255);
}
switch(potionType) {
case "HARMING": return ColorUtils.rgba(255, 50, 50, 255);
case "POISON": return ColorUtils.rgba(50, 255, 50, 255);
case "SLOWNESS": return ColorUtils.rgba(50, 50, 255, 255);
case "WEAKNESS": return ColorUtils.rgba(150, 150, 150, 255);
case "INSTANT_HEALTH": return ColorUtils.rgba(0, 200, 0, 255);
case "REGENERATION": return ColorUtils.rgba(255, 105, 180, 255);
case "FIRE_RESISTANCE": return ColorUtils.rgba(255, 100, 0, 255);
case "WATER_BREATHING": return ColorUtils.rgba(0, 150, 200, 255);
case "INVISIBILITY": return ColorUtils.rgba(150, 150, 150, 255);
case "NIGHT_VISION": return ColorUtils.rgba(100, 0, 200, 255);
case "JUMP_BOOST": return ColorUtils.rgba(0, 255, 150, 255);
case "SPEED": return ColorUtils.rgba(100, 255, 255, 255);
case "STRENGTH": return ColorUtils.rgba(255, 100, 0, 255);
default: return -1;
}
}
private int getPotionColor(String potionType) {
if (potionType.equals("OTHER")) {
return ColorUtils.rgba(200, 0, 200, 100);
}
switch(potionType) {
case "HARMING": return ColorUtils.rgba(255, 0, 0, 100);
case "POISON": return ColorUtils.rgba(0, 255, 0, 100);
case "SLOWNESS": return ColorUtils.rgba(0, 0, 255, 100);
case "WEAKNESS": return ColorUtils.rgba(128, 128, 128, 100);
case "INSTANT_HEALTH": return ColorUtils.rgba(0, 200, 0, 80);
case "REGENERATION": return ColorUtils.rgba(255, 105, 180, 80);
case "FIRE_RESISTANCE": return ColorUtils.rgba(255, 100, 0, 80);
case "WATER_BREATHING": return ColorUtils.rgba(0, 150, 200, 80);
case "INVISIBILITY": return ColorUtils.rgba(150, 150, 150, 80);
case "NIGHT_VISION": return ColorUtils.rgba(100, 0, 200, 80);
case "JUMP_BOOST": return ColorUtils.rgba(0, 255, 150, 80);
case "SPEED": return ColorUtils.rgba(100, 255, 255, 80);
case "STRENGTH": return ColorUtils.rgba(255, 100, 0, 80);
default: return ColorUtils.rgba(255, 165, 0, 100);
}
}
private void processPotion(PotionEntity potion) {
Vector3d motion = potion.getMotion();
Vector3d pos = potion.getPositionVec();
int ticks = 0;
ResourceLocation texture = new ResourceLocation("textures/item/potion_bottle_splash.png");
String potionType = getPotionType(potion.getItem());
for(int i = 0; i < 150; ++i) {
Vector3d prevPos = pos;
pos = pos.add(motion);
motion = this.getNextMotion(potion, motion);
ColorUtils.setAlpha(ColorUtils.getColor(0), 165);
buffer.pos(prevPos.x, prevPos.y, prevPos.z).endVertex();
RayTraceContext rayTraceContext = new RayTraceContext(prevPos, pos, BlockMode.COLLIDER, FluidMode.NONE, potion);
BlockRayTraceResult blockHitResult = mc.world.rayTraceBlocks(rayTraceContext);
boolean isLast = blockHitResult.getType() == Type.BLOCK;
if (isLast) {
pos = blockHitResult.getHitVec();
potionRadii.add(new PotionRadius(pos, getRadiusForPotion(potionType), potionType));
}
buffer.pos(pos.x, pos.y, pos.z).endVertex();
if (blockHitResult.getType() == Type.BLOCK || pos.y < -128.0) {
if (!(motion.lengthSquared() < 0.04)) {
this.throwablePoints.add(new ThrowablePoint(pos, ticks, texture));
}
break;
}
++ticks;
}
}
private String getPotionType(ItemStack potionStack) {
List<EffectInstance> effects = PotionUtils.getEffectsFromStack(potionStack);
if (effects.isEmpty()) {
return "OTHER";
}
EffectInstance mainEffect = effects.get(0);
ResourceLocation effectId = Registry.EFFECTS.getKey(mainEffect.getPotion());
if (effectId == null) {
return "OTHER";
}
switch (effectId.getPath()) {
case "instant_damage": return "HARMING";
case "poison": return "POISON";
case "slowness": return "SLOWNESS";
case "weakness": return "WEAKNESS";
case "instant_health": return "INSTANT_HEALTH";
case "regeneration": return "REGENERATION";
case "fire_resistance": return "FIRE_RESISTANCE";
case "water_breathing": return "WATER_BREATHING";
case "invisibility": return "INVISIBILITY";
case "night_vision": return "NIGHT_VISION";
case "jump_boost": return "JUMP_BOOST";
case "speed": return "SPEED";
case "strength": return "STRENGTH";
default: return "OTHER";
}
}
private float getRadiusForPotion(String potionType) {
switch(potionType) {
case "HARMING": return 4.0f;
case "POISON": return 3.5f;
case "SLOWNESS": return 3.0f;
case "WEAKNESS": return 2.5f;
case "INSTANT_HEALTH": return 3.0f;
case "REGENERATION": return 3.0f;
case "FIRE_RESISTANCE": return 2.5f;
case "WATER_BREATHING": return 2.5f;
case "INVISIBILITY": return 2.0f;
case "NIGHT_VISION": return 2.0f;
case "JUMP_BOOST": return 2.5f;
case "SPEED": return 3.0f;
case "STRENGTH": return 3.0f;
default: return 3.0f;
}
}
private boolean isExplosivePotion(PotionEntity potion) {
ItemStack stack = potion.getItem();
if (stack.getItem() != Items.SPLASH_POTION && stack.getItem() != Items.LINGERING_POTION) {
return false;
}
return !PotionUtils.getEffectsFromStack(stack).isEmpty();
}
private Vector3d getNextMotion(Entity entity, Vector3d motion) {
if (entity instanceof PotionEntity) {
if (entity.isInWater()) {
motion = motion.scale(0.8);
} else {
motion = motion.scale(0.99);
}
if (!entity.hasNoGravity()) {
motion.y -= 0.05;
}
}
return motion;
}
static record ThrowablePoint(Vector3d position, int ticks, ResourceLocation texture) {}
static record PotionRadius(Vector3d position, float radius, String potionType) {}
}
Последнее редактирование модератором: