Начинающий
Начинающий
- Статус
- Оффлайн
- Регистрация
- 12 Янв 2025
- Сообщения
- 33
- Реакции
- 1
- Выберите загрузчик игры
- Fabric
Третья тема заполняю форум калом
В кратце прикольная визуальная штучка
В кратце прикольная визуальная штучка
Java:
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.gl.RenderPipelines;
import net.minecraft.client.render.*;
import net.minecraft.client.util.BufferAllocator;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
import org.joml.Matrix4f;
import ru.strange.client.event.EventInit;
import ru.strange.client.event.impl.EventEntityStatus;
import ru.strange.client.event.impl.EventRender3D;
import ru.strange.client.event.impl.EventUpdate;
import ru.strange.client.module.api.Category;
import ru.strange.client.module.api.IModule;
import ru.strange.client.module.api.Module;
import ru.strange.client.module.api.setting.impl.BooleanSetting;
import ru.strange.client.module.api.setting.impl.ModeSetting;
import ru.strange.client.module.api.setting.impl.SliderSetting;
import ru.strange.client.module.api.setting.impl.HueSetting;
import ru.strange.client.utils.render.RenderUtil;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
@IModule(
name = "WawePlayer",
description = "Запоминает позу при тотеме и рисует летящий призрак",
category = Category.Utilities,
bind = -1
)
public class TotemAngle extends Module {
private final SliderSetting riseHeight = new SliderSetting("Высота подъема", 4f, 0.2f, 5.0f, 0.1f, false);
private final SliderSetting duration = new SliderSetting("Время жизни", 3f, 0.2f, 6.0f, 0.1f, false);
private final HueSetting color = new HueSetting("Цвет", new Color(RenderUtil.ColorUtil.getClientColor()));
private final BooleanSetting onTotem = new BooleanSetting("При тотеме", true);
private final BooleanSetting onJump = new BooleanSetting("При прыжке", false);
private final BooleanSetting onWalk = new BooleanSetting("При ходьбе", false);
private final SliderSetting walkInterval = new SliderSetting("Интервал ходьбы", 0.6f, 0.1f, 3.0f, 0.1f, false)
.hidden(() -> !onWalk.get());
private final ModeSetting targets = new ModeSetting("Для кого", "Оба", "У меня", "У игроков", "Оба");
private final SliderSetting playersRadius = new SliderSetting("Радиус игроков", 8.0f, 1.0f, 64.0f, 1.0f, false)
.hidden(() -> !targets.is("У игроков") && !targets.is("Оба"));
private final List<TotemGhost> ghosts = new CopyOnWriteArrayList<>();
private boolean wasOnGround;
private long lastWalkSpawnMs;
private final Map<UUID, PlayerTrack> otherTracks = new HashMap<>();
public TotemAngle() {
addSettings(riseHeight, duration, color, onTotem, onJump, onWalk, walkInterval, targets, playersRadius);
}
@Override
public void onDisable() {
ghosts.clear();
wasOnGround = false;
lastWalkSpawnMs = 0L;
otherTracks.clear();
super.onDisable();
}
@EventInit
public void onStatus(EventEntityStatus event) {
if (!enable) return;
if (mc.world == null) return;
if (!onTotem.get()) return;
if (event.getStatus() != 35) return;
Entity e = event.getEntity();
if (!(e instanceof AbstractClientPlayerEntity player)) return;
if (!shouldProcess(player)) return;
addGhost(player, true);
}
@EventInit
public void onUpdate(EventUpdate event) {
if (!enable) return;
if (mc.player == null || mc.world == null) return;
long now = System.currentTimeMillis();
long intervalMs = (long) (walkInterval.get() * 1000.0f);
if (intervalMs < 1L) intervalMs = 1L;
if (shouldProcessSelf()) {
boolean onGround = mc.player.isOnGround();
if (onJump.get()) {
boolean jumpedThisTick = wasOnGround && !onGround && mc.player.getVelocity().y > 0.0D;
if (jumpedThisTick) {
addGhost(mc.player, true);
}
}
if (onWalk.get()) {
if (onJump.get() && !onGround) {
lastWalkSpawnMs = 0L;
} else {
Vec3d v = mc.player.getVelocity();
double horizontalSpeed = Math.sqrt(v.x * v.x + v.z * v.z);
boolean moving = horizontalSpeed > 0.02D;
if (moving) {
if (lastWalkSpawnMs == 0L) {
lastWalkSpawnMs = now;
}
if (now - lastWalkSpawnMs >= intervalMs) {
lastWalkSpawnMs = now;
addGhost(mc.player, false);
}
} else {
lastWalkSpawnMs = 0L;
}
}
}
wasOnGround = onGround;
}
if (shouldProcessOthers()) {
updateOtherPlayers(now, intervalMs);
} else {
otherTracks.clear();
}
}
private void updateOtherPlayers(long now, long intervalMs) {
if (mc.player == null || mc.world == null) return;
double radius = playersRadius.get();
double radiusSq = radius * radius;
otherTracks.entrySet().removeIf(e -> {
for (AbstractClientPlayerEntity p : mc.world.getPlayers()) {
if (p == mc.player) continue;
if (p.getUuid().equals(e.getKey()) && !p.isRemoved() && mc.player.squaredDistanceTo(p) <= radiusSq) {
return false;
}
}
return true;
});
for (AbstractClientPlayerEntity p : mc.world.getPlayers()) {
if (p == mc.player) continue;
if (p.isRemoved()) continue;
if (mc.player.squaredDistanceTo(p) > radiusSq) continue;
PlayerTrack track = otherTracks.computeIfAbsent(p.getUuid(), k -> new PlayerTrack());
boolean onGround = p.isOnGround();
if (onJump.get()) {
boolean jumpedThisTick = track.wasOnGround && !onGround && p.getVelocity().y > 0.0D;
if (jumpedThisTick) {
addGhost(p, true);
}
}
if (onWalk.get()) {
if (onJump.get() && !onGround) {
track.lastWalkSpawnMs = 0L;
} else {
double dx = p.getX() - track.lastX;
double dz = p.getZ() - track.lastZ;
double delta = Math.sqrt(dx * dx + dz * dz);
boolean moving = delta > 0.003D;
if (moving) {
if (track.lastWalkSpawnMs == 0L) {
track.lastWalkSpawnMs = now;
}
if (now - track.lastWalkSpawnMs >= intervalMs) {
track.lastWalkSpawnMs = now;
addGhost(p, false);
}
} else {
track.lastWalkSpawnMs = 0L;
}
}
}
track.wasOnGround = onGround;
track.lastX = p.getX();
track.lastZ = p.getZ();
}
}
private boolean shouldProcess(AbstractClientPlayerEntity player) {
if (mc.player == null) return false;
if (player == mc.player) return shouldProcessSelf();
return shouldProcessOthers();
}
private boolean shouldProcessSelf() {
return targets.is("У меня") || targets.is("Оба");
}
private boolean shouldProcessOthers() {
return targets.is("У игроков") || targets.is("Оба");
}
private static class PlayerTrack {
private boolean wasOnGround;
private long lastWalkSpawnMs;
private double lastX;
private double lastZ;
}
@EventInit
public void onRender(EventRender3D event) {
if (!enable) return;
renderGhosts(event);
}
private void addGhost(AbstractClientPlayerEntity player, boolean rising) {
if (mc.world == null) return;
Vec3d pos = player.getPos();
float bodyYaw = player.getBodyYaw();
boolean sneaking = player.isSneaking();
float walkPhase = player.age;
float horizontalSpeed = (float) player.getVelocity().horizontalLength();
float walkSpeed = net.minecraft.util.math.MathHelper.clamp(horizontalSpeed * 8.0f, 0.0f, 1.0f);
ghosts.add(new TotemGhost(pos, bodyYaw, sneaking, walkPhase, walkSpeed, rising, System.currentTimeMillis()));
}
private void renderGhosts(EventRender3D event) {
if (ghosts.isEmpty()) return;
if (mc.world == null) return;
Vec3d cameraPos = mc.gameRenderer.getCamera().getPos();
long now = System.currentTimeMillis();
List<TotemGhost> toRemove = new ArrayList<>();
BufferAllocator allocator = new BufferAllocator(1 << 18);
VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(allocator);
try {
VertexConsumer buffer = immediate.getBuffer(COLOR_QUADS_LAYER);
for (TotemGhost ghost : ghosts) {
float progress = (now - ghost.startTime) / (duration.get() * 1000.0f);
if (progress >= 1.0f) {
toRemove.add(ghost);
continue;
}
double motionY = ghost.rising ? (riseHeight.get() * ease(progress)) : 0.0D;
float alpha = (float) easeOutAlpha(progress);
int color = resolveColor(progress);
float r = ((color >> 16) & 0xFF) / 255f;
float g = ((color >> 8) & 0xFF) / 255f;
float b = (color & 0xFF) / 255f;
MatrixStack matrices = event.getMatrixStack();
matrices.push();
double renderX = ghost.position.x - cameraPos.x;
double renderY = ghost.position.y - cameraPos.y + motionY;
double renderZ = ghost.position.z - cameraPos.z;
matrices.translate(renderX, renderY, renderZ);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0f - ghost.bodyYaw));
float effectiveAlpha = net.minecraft.util.math.MathHelper.clamp(alpha, 0.0f, 0.75f);
renderFlatHumanoid(matrices, buffer, r, g, b, effectiveAlpha, ghost.sneaking, ghost.walkPhase, ghost.walkSpeed);
matrices.pop();
}
immediate.draw();
} finally {
allocator.close();
}
if (!toRemove.isEmpty()) {
ghosts.removeAll(toRemove);
}
}
private void renderFlatHumanoid(MatrixStack matrices, VertexConsumer buffer,
float r, float g, float b, float a,
boolean sneaking,
float walkPhase,
float walkSpeed) {
matrices.push();
matrices.scale(-1f, -1f, 1f);
matrices.translate(0.0D, -1.501D, 0.0D);
if (sneaking) {
matrices.translate(0.0D, 0.2D, 0.0D);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(28.0f));
}
Matrix4f matrix = matrices.peek().getPositionMatrix();
drawBox(buffer, matrix, -4 * U, 0 * U, -2 * U, 8 * U, 12 * U, 4 * U, r, g, b, a);
drawBox(buffer, matrix, -4 * U, -8 * U, -4 * U, 8 * U, 8 * U, 8 * U, r, g, b, a);
float swing = net.minecraft.util.math.MathHelper.sin(walkPhase * 0.6662f) * 1.4f * walkSpeed;
renderArm(matrices, buffer, r, g, b, a, true, -swing);
renderArm(matrices, buffer, r, g, b, a, false, swing);
renderLeg(matrices, buffer, r, g, b, a, true, swing);
renderLeg(matrices, buffer, r, g, b, a, false, -swing);
matrices.pop();
}
private void renderArm(MatrixStack matrices, VertexConsumer buffer,
float r, float g, float b, float a,
boolean left, float pitchRad) {
matrices.push();
float pivotX = (left ? -6.0f : 6.0f) * U;
float pivotY = 2.0f * U;
matrices.translate(pivotX, pivotY, 0.0f);
matrices.multiply(RotationAxis.POSITIVE_X.rotation(pitchRad));
matrices.translate(-pivotX, -pivotY, 0.0f);
Matrix4f matrix = matrices.peek().getPositionMatrix();
float boxX = (left ? -8.0f : 4.0f) * U;
drawBox(buffer, matrix, boxX, -2 * U, -2 * U, 4 * U, 12 * U, 4 * U, r, g, b, a);
matrices.pop();
}
private void renderLeg(MatrixStack matrices, VertexConsumer buffer,
float r, float g, float b, float a,
boolean left, float pitchRad) {
matrices.push();
float pivotX = (left ? -2.0f : 2.0f) * U;
float pivotY = 12.0f * U;
matrices.translate(pivotX, pivotY, 0.0f);
matrices.multiply(RotationAxis.POSITIVE_X.rotation(pitchRad));
matrices.translate(-pivotX, -pivotY, 0.0f);
Matrix4f matrix = matrices.peek().getPositionMatrix();
float boxX = (left ? -4.0f : 0.0f) * U;
drawBox(buffer, matrix, boxX, 12 * U, -2 * U, 4 * U, 12 * U, 4 * U, r, g, b, a);
matrices.pop();
}
private static final float U = 1.0f / 16.0f;
private static void drawBox(VertexConsumer buffer, Matrix4f matrix,
float x, float y, float z,
float sx, float sy, float sz,
float r, float g, float b, float a) {
float x1 = x;
float y1 = y;
float z1 = z;
float x2 = x + sx;
float y2 = y + sy;
float z2 = z + sz;
buffer.vertex(matrix, x1, y1, z2).color(r, g, b, a);
buffer.vertex(matrix, x2, y1, z2).color(r, g, b, a);
buffer.vertex(matrix, x2, y2, z2).color(r, g, b, a);
buffer.vertex(matrix, x1, y2, z2).color(r, g, b, a);
buffer.vertex(matrix, x2, y1, z1).color(r, g, b, a);
buffer.vertex(matrix, x1, y1, z1).color(r, g, b, a);
buffer.vertex(matrix, x1, y2, z1).color(r, g, b, a);
buffer.vertex(matrix, x2, y2, z1).color(r, g, b, a);
buffer.vertex(matrix, x1, y1, z1).color(r, g, b, a);
buffer.vertex(matrix, x1, y1, z2).color(r, g, b, a);
buffer.vertex(matrix, x1, y2, z2).color(r, g, b, a);
buffer.vertex(matrix, x1, y2, z1).color(r, g, b, a);
buffer.vertex(matrix, x2, y1, z2).color(r, g, b, a);
buffer.vertex(matrix, x2, y1, z1).color(r, g, b, a);
buffer.vertex(matrix, x2, y2, z1).color(r, g, b, a);
buffer.vertex(matrix, x2, y2, z2).color(r, g, b, a);
buffer.vertex(matrix, x1, y2, z2).color(r, g, b, a);
buffer.vertex(matrix, x2, y2, z2).color(r, g, b, a);
buffer.vertex(matrix, x2, y2, z1).color(r, g, b, a);
buffer.vertex(matrix, x1, y2, z1).color(r, g, b, a);
buffer.vertex(matrix, x1, y1, z1).color(r, g, b, a);
buffer.vertex(matrix, x2, y1, z1).color(r, g, b, a);
buffer.vertex(matrix, x2, y1, z2).color(r, g, b, a);
buffer.vertex(matrix, x1, y1, z2).color(r, g, b, a);
}
private int resolveColor(float progress) {
return color.getRGB();
}
private double ease(double t) {
t = net.minecraft.util.math.MathHelper.clamp(t, 0.0D, 0.75D);
return 1.0D - Math.pow(1.0D - t, 3);
}
private double easeOutAlpha(double t) {
t = net.minecraft.util.math.MathHelper.clamp(t, 0.0D, 1.0D);
double invT = 1.0D - t;
return 0.75D * Math.pow(invT, 3);
}
private static class TotemGhost {
private final Vec3d position;
private final float bodyYaw;
private final boolean sneaking;
private final float walkPhase;
private final float walkSpeed;
private final boolean rising;
private final long startTime;
private TotemGhost(Vec3d position, float bodyYaw, boolean sneaking, float walkPhase, float walkSpeed, boolean rising, long startTime) {
this.position = position;
this.bodyYaw = bodyYaw;
this.sneaking = sneaking;
this.walkPhase = walkPhase;
this.walkSpeed = walkSpeed;
this.rising = rising;
this.startTime = startTime;
}
}
private static final int QUAD_BUFFER_SIZE_BYTES = 1 << 10;
private static final String PIPELINE_NAMESPACE = "strange";
private static final RenderPipeline COLOR_QUADS_PIPELINE = RenderPipelines.register(
RenderPipeline.builder(RenderPipelines.POSITION_COLOR_SNIPPET)
.withLocation(Identifier.of(PIPELINE_NAMESPACE, "pipeline/world/totem_angle_color_quads"))
.withVertexFormat(VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.QUADS)
.withCull(false)
.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST)
.withDepthWrite(false)
.withBlend(BlendFunction.LIGHTNING)
.build()
);
private static final RenderLayer COLOR_QUADS_LAYER = RenderLayer.of(
"strange_totem_angle_quads",
QUAD_BUFFER_SIZE_BYTES,
false,
true,
COLOR_QUADS_PIPELINE,
RenderLayer.MultiPhaseParameters.builder().build(false)
);
}