Skip to content

Commit 44d5e4e

Browse files
committed
Feat : Optimize Bargain Windows and Enhance Visuals
1 parent 71dcc51 commit 44d5e4e

File tree

19 files changed

+1908
-1296
lines changed

19 files changed

+1908
-1296
lines changed

src/generated/resources/assets/cosmiccore/lang/en_ud.json

Lines changed: 245 additions & 302 deletions
Large diffs are not rendered by default.

src/generated/resources/assets/cosmiccore/lang/en_us.json

Lines changed: 245 additions & 302 deletions
Large diffs are not rendered by default.

src/main/java/com/ghostipedia/cosmiccore/client/CosmicCoreClient.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ public static void init(IEventBus modBus) {
6464
@Getter
6565
private static ShaderInstance galaxyBgShader;
6666

67+
@Getter
68+
private static ShaderInstance soulCoreShader;
69+
70+
@Getter
71+
private static ShaderInstance soulThreadsShader;
72+
6773
@SubscribeEvent
6874
public static void shaderRegistry(RegisterShadersEvent event) {
6975
try {
@@ -78,6 +84,12 @@ public static void shaderRegistry(RegisterShadersEvent event) {
7884

7985
event.registerShader(new ShaderInstance(event.getResourceProvider(), CosmicCore.id("galaxy_bg"),
8086
DefaultVertexFormat.POSITION_TEX), (shaderInstance) -> galaxyBgShader = shaderInstance);
87+
88+
event.registerShader(new ShaderInstance(event.getResourceProvider(), CosmicCore.id("soul_core"),
89+
DefaultVertexFormat.POSITION_TEX), (shaderInstance) -> soulCoreShader = shaderInstance);
90+
91+
event.registerShader(new ShaderInstance(event.getResourceProvider(), CosmicCore.id("soul_threads"),
92+
DefaultVertexFormat.POSITION_TEX), (shaderInstance) -> soulThreadsShader = shaderInstance);
8193
} catch (IOException e) {
8294
throw new RuntimeException(e);
8395
}
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
package com.ghostipedia.cosmiccore.client.renderer;
2+
3+
import net.minecraft.client.gui.GuiGraphics;
4+
import net.minecraft.client.renderer.GameRenderer;
5+
import net.minecraft.resources.ResourceLocation;
6+
import net.minecraftforge.api.distmarker.Dist;
7+
import net.minecraftforge.api.distmarker.OnlyIn;
8+
9+
import com.mojang.blaze3d.systems.RenderSystem;
10+
import com.mojang.blaze3d.vertex.BufferBuilder;
11+
import com.mojang.blaze3d.vertex.BufferUploader;
12+
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
13+
import com.mojang.blaze3d.vertex.Tesselator;
14+
import com.mojang.blaze3d.vertex.VertexFormat;
15+
import org.joml.Matrix4f;
16+
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
20+
@OnlyIn(Dist.CLIENT)
21+
public class ChainRenderer {
22+
23+
private static final int SEGMENTS = 8;
24+
private static final float GRAVITY = 0.35f;
25+
private static final float DAMPENING = 0.96f;
26+
private static final int CONSTRAINT_ITERATIONS = 6;
27+
private static final float MOUSE_INFLUENCE_RADIUS = 20.0f;
28+
private static final float MOUSE_PUSH_STRENGTH = 2.0f;
29+
private static final int BASE_LINK_SIZE = 14;
30+
31+
private static final ResourceLocation CHAIN_TEXTURE = new ResourceLocation("minecraft",
32+
"textures/item/chain.png");
33+
34+
private final List<Chain> chains = new ArrayList<>();
35+
36+
public void clear() {
37+
chains.clear();
38+
}
39+
40+
public void addChain(float shellX, float shellY, float pinX, float pinY, int[] color) {
41+
chains.add(new Chain(shellX, shellY, pinX, pinY, color));
42+
}
43+
44+
public int getChainCount() {
45+
return chains.size();
46+
}
47+
48+
public Chain getChain(int index) {
49+
return chains.get(index);
50+
}
51+
52+
public void tick(float mouseX, float mouseY) {
53+
for (Chain chain : chains) {
54+
chain.simulate(mouseX, mouseY);
55+
}
56+
}
57+
58+
public void updateAnchors(int chainIndex, float shellX, float shellY, float pinX, float pinY) {
59+
if (chainIndex < 0 || chainIndex >= chains.size()) return;
60+
Chain chain = chains.get(chainIndex);
61+
62+
float dShellX = shellX - chain.points[0].x;
63+
float dShellY = shellY - chain.points[0].y;
64+
float dPinX = pinX - chain.points[SEGMENTS - 1].x;
65+
float dPinY = pinY - chain.points[SEGMENTS - 1].y;
66+
67+
for (int i = 1; i < SEGMENTS - 1; i++) {
68+
float t = (float) i / (SEGMENTS - 1);
69+
float dx = dShellX * (1 - t) + dPinX * t;
70+
float dy = dShellY * (1 - t) + dPinY * t;
71+
chain.points[i].x += dx;
72+
chain.points[i].y += dy;
73+
chain.points[i].prevX += dx;
74+
chain.points[i].prevY += dy;
75+
}
76+
77+
chain.points[0].x = shellX;
78+
chain.points[0].y = shellY;
79+
chain.points[0].prevX = shellX;
80+
chain.points[0].prevY = shellY;
81+
chain.points[SEGMENTS - 1].x = pinX;
82+
chain.points[SEGMENTS - 1].y = pinY;
83+
chain.points[SEGMENTS - 1].prevX = pinX;
84+
chain.points[SEGMENTS - 1].prevY = pinY;
85+
chain.recalcRestLength();
86+
}
87+
88+
public void render(GuiGraphics graphics, float fadeAlpha, float mouseX, float mouseY, float partialTick) {
89+
if (chains.isEmpty() || fadeAlpha <= 0.01f) return;
90+
91+
for (Chain chain : chains) {
92+
chain.hovered = chain.isNearMouse(mouseX, mouseY, 10.0f);
93+
}
94+
95+
graphics.flush();
96+
Matrix4f matrix = graphics.pose().last().pose();
97+
98+
RenderSystem.setShaderTexture(0, CHAIN_TEXTURE);
99+
RenderSystem.setShader(GameRenderer::getPositionTexShader);
100+
RenderSystem.enableBlend();
101+
RenderSystem.defaultBlendFunc();
102+
RenderSystem.disableDepthTest();
103+
104+
for (Chain chain : chains) {
105+
float alpha = fadeAlpha * (chain.hovered ? 0.85f : 0.55f);
106+
if (alpha <= 0.01f) continue;
107+
108+
RenderSystem.setShaderColor(chain.color[0] / 255f, chain.color[1] / 255f,
109+
chain.color[2] / 255f, alpha);
110+
111+
BufferBuilder buffer = Tesselator.getInstance().getBuilder();
112+
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
113+
emitChainQuads(buffer, matrix, chain, partialTick);
114+
BufferUploader.drawWithShader(buffer.end());
115+
}
116+
117+
RenderSystem.enableDepthTest();
118+
RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
119+
}
120+
121+
private void emitChainQuads(BufferBuilder buffer, Matrix4f matrix, Chain chain, float partialTick) {
122+
for (int i = 0; i < SEGMENTS - 1; i++) {
123+
float ax = lerp(chain.points[i].prevX, chain.points[i].x, partialTick);
124+
float ay = lerp(chain.points[i].prevY, chain.points[i].y, partialTick);
125+
float bx = lerp(chain.points[i + 1].prevX, chain.points[i + 1].x, partialTick);
126+
float by = lerp(chain.points[i + 1].prevY, chain.points[i + 1].y, partialTick);
127+
128+
float midX = (ax + bx) * 0.5f;
129+
float midY = (ay + by) * 0.5f;
130+
float dx = bx - ax;
131+
float dy = by - ay;
132+
float segDist = (float) Math.sqrt(dx * dx + dy * dy);
133+
134+
float hs = Math.max(BASE_LINK_SIZE, segDist * 1.15f) * 0.5f;
135+
136+
float angle = (float) Math.atan2(dy, dx) + (float) (Math.PI / 2);
137+
float cos = (float) Math.cos(angle);
138+
float sin = (float) Math.sin(angle);
139+
140+
float c00x = -hs * cos + hs * sin, c00y = -hs * sin - hs * cos;
141+
float c01x = -hs * cos - hs * sin, c01y = -hs * sin + hs * cos;
142+
float c11x = hs * cos - hs * sin, c11y = hs * sin + hs * cos;
143+
float c10x = hs * cos + hs * sin, c10y = hs * sin - hs * cos;
144+
145+
buffer.vertex(matrix, midX + c00x, midY + c00y, 0).uv(0, 0).endVertex();
146+
buffer.vertex(matrix, midX + c01x, midY + c01y, 0).uv(0, 1).endVertex();
147+
buffer.vertex(matrix, midX + c11x, midY + c11y, 0).uv(1, 1).endVertex();
148+
buffer.vertex(matrix, midX + c10x, midY + c10y, 0).uv(1, 0).endVertex();
149+
}
150+
}
151+
152+
private static float lerp(float a, float b, float t) {
153+
return a + (b - a) * t;
154+
}
155+
156+
public int getHoveredChain(float mouseX, float mouseY, float threshold) {
157+
for (int i = 0; i < chains.size(); i++) {
158+
if (chains.get(i).isNearMouse(mouseX, mouseY, threshold)) {
159+
return i;
160+
}
161+
}
162+
return -1;
163+
}
164+
165+
public static class Chain {
166+
167+
final Point[] points;
168+
final int[] color;
169+
private boolean hovered = false;
170+
private float restLength;
171+
172+
Chain(float shellX, float shellY, float pinX, float pinY, int[] color) {
173+
this.color = color;
174+
this.points = new Point[SEGMENTS];
175+
176+
float totalDist = (float) Math.sqrt(
177+
(pinX - shellX) * (pinX - shellX) + (pinY - shellY) * (pinY - shellY));
178+
179+
for (int i = 0; i < SEGMENTS; i++) {
180+
float t = (float) i / (SEGMENTS - 1);
181+
float x = shellX + (pinX - shellX) * t;
182+
float y = shellY + (pinY - shellY) * t;
183+
float sag = (float) Math.sin(t * Math.PI) * totalDist * 0.15f;
184+
y += sag;
185+
points[i] = new Point(x, y);
186+
}
187+
recalcRestLength();
188+
}
189+
190+
private void recalcRestLength() {
191+
float dx = points[SEGMENTS - 1].x - points[0].x;
192+
float dy = points[SEGMENTS - 1].y - points[0].y;
193+
float dist = (float) Math.sqrt(dx * dx + dy * dy);
194+
restLength = dist * 1.3f / (SEGMENTS - 1);
195+
}
196+
197+
void simulate(float mouseX, float mouseY) {
198+
float shellX = points[0].x;
199+
float shellY = points[0].y;
200+
float pinX = points[SEGMENTS - 1].x;
201+
float pinY = points[SEGMENTS - 1].y;
202+
203+
for (int i = 1; i < SEGMENTS - 1; i++) {
204+
Point p = points[i];
205+
float vx = (p.x - p.prevX) * DAMPENING;
206+
float vy = (p.y - p.prevY) * DAMPENING;
207+
208+
p.prevX = p.x;
209+
p.prevY = p.y;
210+
211+
p.x += vx;
212+
p.y += vy + GRAVITY;
213+
214+
float dx = p.x - mouseX;
215+
float dy = p.y - mouseY;
216+
float distSq = dx * dx + dy * dy;
217+
float radiusSq = MOUSE_INFLUENCE_RADIUS * MOUSE_INFLUENCE_RADIUS;
218+
219+
if (distSq < radiusSq && distSq > 0.01f) {
220+
float dist = (float) Math.sqrt(distSq);
221+
float force = (1.0f - dist / MOUSE_INFLUENCE_RADIUS) * MOUSE_PUSH_STRENGTH;
222+
p.x += (dx / dist) * force;
223+
p.y += (dy / dist) * force;
224+
}
225+
}
226+
227+
float rest = restLength;
228+
for (int iter = 0; iter < CONSTRAINT_ITERATIONS; iter++) {
229+
for (int i = 0; i < SEGMENTS - 1; i++) {
230+
Point a = points[i];
231+
Point b = points[i + 1];
232+
233+
float dx = b.x - a.x;
234+
float dy = b.y - a.y;
235+
float dist = (float) Math.sqrt(dx * dx + dy * dy);
236+
if (dist < 0.001f) continue;
237+
238+
float diff = (rest - dist) / dist;
239+
float offsetX = dx * diff * 0.5f;
240+
float offsetY = dy * diff * 0.5f;
241+
242+
if (i > 0) {
243+
a.x -= offsetX;
244+
a.y -= offsetY;
245+
}
246+
if (i + 1 < SEGMENTS - 1) {
247+
b.x += offsetX;
248+
b.y += offsetY;
249+
}
250+
}
251+
}
252+
253+
points[0].x = shellX;
254+
points[0].y = shellY;
255+
points[SEGMENTS - 1].x = pinX;
256+
points[SEGMENTS - 1].y = pinY;
257+
}
258+
259+
public boolean isHovered() {
260+
return hovered;
261+
}
262+
263+
boolean isNearMouse(float mouseX, float mouseY, float threshold) {
264+
float thresholdSq = threshold * threshold;
265+
for (int i = 0; i < SEGMENTS - 1; i++) {
266+
float distSq = pointToSegmentDistSq(mouseX, mouseY,
267+
points[i].x, points[i].y,
268+
points[i + 1].x, points[i + 1].y);
269+
if (distSq < thresholdSq) return true;
270+
}
271+
return false;
272+
}
273+
274+
private float pointToSegmentDistSq(float px, float py, float ax, float ay, float bx, float by) {
275+
float dx = bx - ax;
276+
float dy = by - ay;
277+
float lenSq = dx * dx + dy * dy;
278+
279+
if (lenSq < 0.001f) {
280+
float ex = px - ax;
281+
float ey = py - ay;
282+
return ex * ex + ey * ey;
283+
}
284+
285+
float t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / lenSq));
286+
float projX = ax + t * dx;
287+
float projY = ay + t * dy;
288+
float ex = px - projX;
289+
float ey = py - projY;
290+
return ex * ex + ey * ey;
291+
}
292+
}
293+
294+
static class Point {
295+
296+
float x, y;
297+
float prevX, prevY;
298+
299+
Point(float x, float y) {
300+
this.x = x;
301+
this.y = y;
302+
this.prevX = x;
303+
this.prevY = y;
304+
}
305+
}
306+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.ghostipedia.cosmiccore.client.renderer;
2+
3+
import com.ghostipedia.cosmiccore.client.CosmicCoreClient;
4+
5+
import net.minecraft.client.renderer.ShaderInstance;
6+
import net.minecraftforge.api.distmarker.Dist;
7+
import net.minecraftforge.api.distmarker.OnlyIn;
8+
9+
import com.mojang.blaze3d.vertex.PoseStack;
10+
11+
@OnlyIn(Dist.CLIENT)
12+
public class SoulCoreRenderer {
13+
14+
public static void render(PoseStack poseStack, int centerX, int centerY, int radius,
15+
int erosion, float intensity, int screenWidth, int screenHeight) {
16+
ShaderInstance shader = CosmicCoreClient.getSoulCoreShader();
17+
if (shader == null) return;
18+
19+
float normalizedErosion = SoulShaderHelper.getNormalizedErosion(erosion);
20+
float normalizedCenterX = (float) centerX / screenWidth;
21+
float normalizedCenterY = (float) centerY / screenHeight;
22+
float normalizedRadius = (float) radius / Math.min(screenWidth, screenHeight);
23+
24+
SoulShaderHelper.setupShader(shader, screenWidth, screenHeight,
25+
normalizedCenterX, normalizedCenterY,
26+
SoulShaderHelper.getCoreColor(erosion), SoulShaderHelper.getShellColor(erosion),
27+
intensity, normalizedRadius, normalizedErosion);
28+
29+
int drawSize = (int) (radius * (2.5f + normalizedErosion * 1.0f));
30+
SoulShaderHelper.drawQuad(poseStack, centerX, centerY, drawSize, screenWidth, screenHeight);
31+
}
32+
}

0 commit comments

Comments
 (0)