Skip to content

Commit 11030e0

Browse files
committed
improved circle and sphere rendering in sculk range esp
added utils for sphere in circle rendering, unused for now.
1 parent cbb9fa3 commit 11030e0

3 files changed

Lines changed: 231 additions & 28 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ yarn_mappings=1.21.11+build.3
88
loader_version=0.18.2
99

1010
# Mod Properties
11-
mod_version=2.6.22
11+
mod_version=2.6.23
1212
maven_group=cqb13.NumbyHack
1313
archives_base_name=Numby-Hack

src/main/java/cqb13/NumbyHack/modules/general/SculkRangeEsp.java

Lines changed: 100 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import meteordevelopment.meteorclient.events.world.TickEvent;
1414
import meteordevelopment.meteorclient.settings.BoolSetting;
1515
import meteordevelopment.meteorclient.settings.ColorSetting;
16+
import meteordevelopment.meteorclient.settings.DoubleSetting;
1617
import meteordevelopment.meteorclient.settings.EnumSetting;
1718
import meteordevelopment.meteorclient.settings.IntSetting;
1819
import meteordevelopment.meteorclient.settings.Setting;
@@ -87,7 +88,7 @@ public class SculkRangeEsp extends Module {
8788
private final Setting<SettingColor> shapeColor = sgGeneral.add(new ColorSetting.Builder()
8889
.name("shape-color")
8990
.description("Color of the range indicator.")
90-
.defaultValue(new SettingColor(146, 188, 98, 255))
91+
.defaultValue(new SettingColor(146, 188, 98, 75))
9192
.build());
9293

9394
private final Setting<Boolean> advancedView = sgGeneral.add(new BoolSetting.Builder()
@@ -99,14 +100,14 @@ public class SculkRangeEsp extends Module {
99100
private final Setting<SettingColor> redstoneColor = sgGeneral.add(new ColorSetting.Builder()
100101
.name("redstone-shape-color")
101102
.description("Color of the range indicator with redstone output.")
102-
.defaultValue(new SettingColor(170, 0, 0, 255))
103+
.defaultValue(new SettingColor(170, 0, 0, 75))
103104
.visible(advancedView::get)
104105
.build());
105106

106107
private final Setting<SettingColor> shriekerColor = sgGeneral.add(new ColorSetting.Builder()
107108
.name("shrieker-shape-color")
108109
.description("Color of the range indicator with a shrieker in range.")
109-
.defaultValue(new SettingColor(0, 69, 170, 255))
110+
.defaultValue(new SettingColor(0, 69, 170, 75))
110111
.visible(advancedView::get)
111112
.build());
112113

@@ -117,12 +118,19 @@ public class SculkRangeEsp extends Module {
117118
.visible(() -> shape.get() == Shape.Circle || shape.get() == Shape.Both)
118119
.build());
119120

121+
private final Setting<Double> circleThickness = sgGeneral.add(new DoubleSetting.Builder()
122+
.name("circle-thickness")
123+
.description("The thickness of the circle.")
124+
.defaultValue(0.08)
125+
.sliderMax(1)
126+
.visible(() -> shape.get() == Shape.Sphere || shape.get() == Shape.Both)
127+
.build());
128+
120129
public Setting<Integer> gradation = sgGeneral.add(new IntSetting.Builder()
121130
.name("gradation")
122131
.description(
123-
"Determines the smoothness/detail of the sphere shape. Higher values produce a smoother sphere, lower values make it more blocky.")
132+
"Determines the smoothness of the sphere shape. Higher values produce a smoother sphere, lower values make it more blocky.")
124133
.defaultValue(30)
125-
.range(20, 100)
126134
.sliderRange(20, 100)
127135
.visible(() -> shape.get() == Shape.Sphere || shape.get() == Shape.Both)
128136
.build());
@@ -282,29 +290,47 @@ private void onRender(Render3DEvent event) {
282290
if (renderAtPlayerHeight.get()) {
283291
renderPos = new BlockPos(sensor.pos.getX(), (int) mc.player.getY(), sensor.pos.getZ());
284292
}
285-
renderCircle(event, radius, renderPos, sensor);
293+
renderCircle(event, radius, circleThickness.get(), renderPos, sensor);
286294
}
287295
}
288296
}
289297
}
290298

291-
private void renderCircle(Render3DEvent event, double radius, BlockPos origin, FoundSensor sensor) {
299+
private void renderCircle(Render3DEvent event, double radius, double thickness, BlockPos origin,
300+
FoundSensor sensor) {
292301
final double maxSegmentLength = 0.2;
293302

294303
int segments = (int) Math.ceil(2 * Math.PI * radius / maxSegmentLength);
295304
segments = Math.max(16, segments);
296305

297-
Vec3d[] pts = new Vec3d[segments];
306+
Vec3d[] outerPts = new Vec3d[segments];
307+
Vec3d[] innerPts = new Vec3d[segments];
298308
SettingColor[] cols = new SettingColor[segments];
299309

300310
boolean both = sensor.hasRedstoneOutput() && sensor.shriekerInRange();
301311
boolean advanced = advancedView.get();
302312

313+
double outerRadius = radius + thickness / 2.0;
314+
double innerRadius = radius - thickness / 2.0;
315+
316+
if (innerRadius < 0) {
317+
innerRadius = 0;
318+
}
319+
303320
for (int s = 0; s < segments; s++) {
304321
double angle = 2 * Math.PI * s / segments;
305-
double sin = Math.sin(angle) * radius;
306-
double cos = Math.cos(angle) * radius;
307-
pts[s] = new Vec3d(origin.getX() + sin, origin.getY(), origin.getZ() + cos);
322+
double sin = Math.sin(angle);
323+
double cos = Math.cos(angle);
324+
325+
outerPts[s] = new Vec3d(
326+
origin.getX() + sin * outerRadius,
327+
origin.getY(),
328+
origin.getZ() + cos * outerRadius);
329+
330+
innerPts[s] = new Vec3d(
331+
origin.getX() + sin * innerRadius,
332+
origin.getY(),
333+
origin.getZ() + cos * innerRadius);
308334

309335
int deg = (int) Math.round(Math.toDegrees(angle)) % 360;
310336

@@ -327,34 +353,63 @@ private void renderCircle(Render3DEvent event, double radius, BlockPos origin, F
327353

328354
for (int s = 0; s < segments; s++) {
329355
int next = (s + 1) % segments;
330-
event.renderer.line(
331-
pts[s].x, pts[s].y, pts[s].z,
332-
pts[next].x, pts[next].y, pts[next].z,
333-
cols[next]);
356+
357+
event.renderer.triangles.ensureTriCapacity();
358+
359+
int outer1 = event.renderer.triangles
360+
.vec3(outerPts[s].x, outerPts[s].y, outerPts[s].z)
361+
.color(cols[s])
362+
.next();
363+
364+
int outer2 = event.renderer.triangles
365+
.vec3(outerPts[next].x, outerPts[next].y, outerPts[next].z)
366+
.color(cols[next])
367+
.next();
368+
369+
int inner1 = event.renderer.triangles
370+
.vec3(innerPts[s].x, innerPts[s].y, innerPts[s].z)
371+
.color(cols[s])
372+
.next();
373+
374+
int inner2 = event.renderer.triangles
375+
.vec3(innerPts[next].x, innerPts[next].y, innerPts[next].z)
376+
.color(cols[next])
377+
.next();
378+
379+
event.renderer.triangles.triangle(outer1, outer2, inner1);
380+
event.renderer.triangles.triangle(inner1, outer2, inner2);
334381
}
335382
}
336383

337384
private void renderSphere(Render3DEvent event, double radius, int gradation, FoundSensor sensor) {
338385
boolean advanced = advancedView.get();
339386
boolean both = sensor.hasRedstoneOutput() && sensor.shriekerInRange();
340387

341-
for (float alpha = 0.0f; alpha < Math.PI; alpha += Math.PI / gradation) {
342-
for (float beta = 0.0f; beta < 2.0 * Math.PI; beta += Math.PI / gradation) {
343-
double x1 = sensor.pos.getX() + radius * Math.cos(beta) * Math.sin(alpha);
344-
double y1 = sensor.pos.getY() + radius * Math.sin(beta) * Math.sin(alpha);
345-
double z1 = sensor.pos.getZ() + radius * Math.cos(alpha);
388+
double cx = sensor.pos.getX();
389+
double cy = sensor.pos.getY();
390+
double cz = sensor.pos.getZ();
346391

347-
double sin = Math.sin(alpha + Math.PI / gradation);
348-
double x2 = sensor.pos.getX() + radius * Math.cos(beta) * sin;
349-
double y2 = sensor.pos.getY() + radius * Math.sin(beta) * sin;
350-
double z2 = sensor.pos.getZ() + radius * Math.cos(alpha + Math.PI / gradation);
392+
int horizontalSteps = Math.max(8, gradation);
393+
int verticalSteps = Math.max(16, gradation * 2);
351394

352-
SettingColor color;
395+
for (int hor = 0; hor < horizontalSteps; hor++) {
396+
double theta1 = Math.PI * hor / horizontalSteps;
397+
double theta2 = Math.PI * (hor + 1) / horizontalSteps;
353398

399+
for (int vert = 0; vert < verticalSteps; vert++) {
400+
double phi1 = 2.0 * Math.PI * vert / verticalSteps;
401+
double phi2 = 2.0 * Math.PI * (vert + 1) / verticalSteps;
402+
403+
Vec3d p1 = spherePoint(cx, cy, cz, radius, theta1, phi1);
404+
Vec3d p2 = spherePoint(cx, cy, cz, radius, theta1, phi2);
405+
Vec3d p3 = spherePoint(cx, cy, cz, radius, theta2, phi2);
406+
Vec3d p4 = spherePoint(cx, cy, cz, radius, theta2, phi1);
407+
408+
SettingColor color;
354409
if (!advanced) {
355410
color = shapeColor.get();
356411
} else if (both) {
357-
int segmentIndex = (int) (alpha / (Math.PI / gradation) + beta / (Math.PI / gradation));
412+
int segmentIndex = hor + vert;
358413
color = (segmentIndex % 2 == 0) ? redstoneColor.get() : shriekerColor.get();
359414
} else if (sensor.hasRedstoneOutput()) {
360415
color = redstoneColor.get();
@@ -364,11 +419,29 @@ private void renderSphere(Render3DEvent event, double radius, int gradation, Fou
364419
color = shapeColor.get();
365420
}
366421

367-
event.renderer.line(x1, y1, z1, x2, y2, z2, color);
422+
event.renderer.triangles.ensureQuadCapacity();
423+
424+
int i1 = event.renderer.triangles.vec3(p1.x, p1.y, p1.z).color(color).next();
425+
int i2 = event.renderer.triangles.vec3(p2.x, p2.y, p2.z).color(color).next();
426+
int i3 = event.renderer.triangles.vec3(p3.x, p3.y, p3.z).color(color).next();
427+
int i4 = event.renderer.triangles.vec3(p4.x, p4.y, p4.z).color(color).next();
428+
429+
event.renderer.triangles.triangle(i1, i2, i3);
430+
event.renderer.triangles.triangle(i1, i3, i4);
368431
}
369432
}
370433
}
371434

435+
private Vec3d spherePoint(double cx, double cy, double cz, double r, double theta, double phi) {
436+
double sinTheta = Math.sin(theta);
437+
438+
double x = cx + r * sinTheta * Math.cos(phi);
439+
double y = cy + r * Math.cos(theta);
440+
double z = cz + r * sinTheta * Math.sin(phi);
441+
442+
return new Vec3d(x, y, z);
443+
}
444+
372445
private record FoundSensor(SensorType sensorType, BlockPos pos, boolean hasRedstoneOutput,
373446
boolean shriekerInRange) {
374447
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package cqb13.NumbyHack.utils;
2+
3+
import meteordevelopment.meteorclient.events.render.Render3DEvent;
4+
import meteordevelopment.meteorclient.utils.render.color.Color;
5+
import net.minecraft.util.math.BlockPos;
6+
import net.minecraft.util.math.Vec3d;
7+
8+
public class RoundRenderUtils {
9+
private RoundRenderUtils() {
10+
}
11+
12+
// good thickness values for circles are very small around like 0.08 - 1
13+
public static void renderCircle(Render3DEvent event, double radius, double thickness,
14+
double cx, double cy, double cz, Color color) {
15+
final double maxSegmentLength = 0.2;
16+
17+
int segments = (int) Math.ceil(2 * Math.PI * radius / maxSegmentLength);
18+
segments = Math.max(16, segments);
19+
20+
Vec3d[] outerPts = new Vec3d[segments];
21+
Vec3d[] innerPts = new Vec3d[segments];
22+
23+
double outerRadius = radius + thickness / 2.0;
24+
double innerRadius = radius - thickness / 2.0;
25+
if (innerRadius < 0) {
26+
innerRadius = 0;
27+
}
28+
29+
// points around circle
30+
for (int s = 0; s < segments; s++) {
31+
double angle = 2 * Math.PI * s / segments;
32+
double sin = Math.sin(angle);
33+
double cos = Math.cos(angle);
34+
35+
outerPts[s] = new Vec3d(
36+
cx + sin * outerRadius,
37+
cy,
38+
cz + cos * outerRadius);
39+
40+
innerPts[s] = new Vec3d(
41+
cx + sin * innerRadius,
42+
cy,
43+
cz + cos * innerRadius);
44+
}
45+
46+
// connect with triangles
47+
for (int s = 0; s < segments; s++) {
48+
int next = (s + 1) % segments;
49+
50+
event.renderer.triangles.ensureQuadCapacity();
51+
52+
int outer1 = event.renderer.triangles
53+
.vec3(outerPts[s].x, outerPts[s].y, outerPts[s].z)
54+
.color(color)
55+
.next();
56+
57+
int outer2 = event.renderer.triangles
58+
.vec3(outerPts[next].x, outerPts[next].y, outerPts[next].z)
59+
.color(color)
60+
.next();
61+
62+
int inner1 = event.renderer.triangles
63+
.vec3(innerPts[s].x, innerPts[s].y, innerPts[s].z)
64+
.color(color)
65+
.next();
66+
67+
int inner2 = event.renderer.triangles
68+
.vec3(innerPts[next].x, innerPts[next].y, innerPts[next].z)
69+
.color(color)
70+
.next();
71+
72+
event.renderer.triangles.triangle(outer1, outer2, inner1);
73+
event.renderer.triangles.triangle(inner1, outer2, inner2);
74+
}
75+
}
76+
77+
public static void renderCircle(Render3DEvent event, double radius, double thickness,
78+
BlockPos origin, Color color) {
79+
renderCircle(event, radius, thickness, origin.getX(), origin.getY(), origin.getZ(), color);
80+
}
81+
82+
public static void renderSphere(Render3DEvent event, double radius, int gradation,
83+
double cx, double cy, double cz, Color color) {
84+
85+
// the number of slices in each direction
86+
int horizontalSteps = Math.max(8, gradation);
87+
int verticalSteps = Math.max(16, gradation * 2);
88+
89+
for (int lat = 0; lat < horizontalSteps; lat++) {
90+
double theta1 = Math.PI * lat / horizontalSteps;
91+
double theta2 = Math.PI * (lat + 1) / horizontalSteps;
92+
93+
for (int lon = 0; lon < verticalSteps; lon++) {
94+
double phi1 = 2.0 * Math.PI * lon / verticalSteps;
95+
double phi2 = 2.0 * Math.PI * (lon + 1) / verticalSteps;
96+
97+
Vec3d p1 = spherePoint(cx, cy, cz, radius, theta1, phi1);
98+
Vec3d p2 = spherePoint(cx, cy, cz, radius, theta1, phi2);
99+
Vec3d p3 = spherePoint(cx, cy, cz, radius, theta2, phi2);
100+
Vec3d p4 = spherePoint(cx, cy, cz, radius, theta2, phi1);
101+
102+
event.renderer.triangles.ensureQuadCapacity();
103+
104+
int i1 = event.renderer.triangles.vec3(p1.x, p1.y, p1.z).color(color).next();
105+
int i2 = event.renderer.triangles.vec3(p2.x, p2.y, p2.z).color(color).next();
106+
int i3 = event.renderer.triangles.vec3(p3.x, p3.y, p3.z).color(color).next();
107+
int i4 = event.renderer.triangles.vec3(p4.x, p4.y, p4.z).color(color).next();
108+
109+
event.renderer.triangles.triangle(i1, i2, i3);
110+
event.renderer.triangles.triangle(i1, i3, i4);
111+
}
112+
}
113+
}
114+
115+
public static void renderSphere(Render3DEvent event, double radius, int gradation,
116+
BlockPos origin, Color color) {
117+
renderSphere(event, radius, gradation, origin.getX(), origin.getY(), origin.getZ(), color);
118+
}
119+
120+
private static Vec3d spherePoint(double cx, double cy, double cz, double r,
121+
double theta, double phi) {
122+
double sinTheta = Math.sin(theta);
123+
124+
double x = cx + r * sinTheta * Math.cos(phi);
125+
double y = cy + r * Math.cos(theta);
126+
double z = cz + r * sinTheta * Math.sin(phi);
127+
128+
return new Vec3d(x, y, z);
129+
}
130+
}

0 commit comments

Comments
 (0)