Merge pull request #31 from saturnclientmc/rewrote-3d-cosmetic-rendering
Rewrote 3d cosmetic rendering #18
This commit is contained in:
+7
-10
@@ -47,11 +47,8 @@ repositories {
|
||||
// Parchment mappings (if needed later)
|
||||
maven { url 'https://maven.parchmentmc.org' }
|
||||
|
||||
// Special Model Loader
|
||||
maven { name = "FelNull Maven"; url = "https://maven.felnull.dev" }
|
||||
|
||||
// Player Animation Library
|
||||
maven { name = "KosmX Maven"; url = 'https://maven.kosmx.dev/' }
|
||||
maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
|
||||
|
||||
// Central repository
|
||||
mavenCentral()
|
||||
@@ -83,9 +80,9 @@ dependencies {
|
||||
// Rendering / Model Libraries
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
// Special Model Loader (included inside your mod jar)
|
||||
modApi "dev.felnull:special-model-loader:1.4.0+pre.1"
|
||||
include "dev.felnull:special-model-loader:1.4.0+pre.1"
|
||||
// OBJ Reading Library
|
||||
implementation "de.javagl:obj:0.4.0"
|
||||
include "de.javagl:obj:0.4.0"
|
||||
|
||||
// SVG Rendering Library
|
||||
include implementation("com.formdev:svgSalamander:1.1.4")
|
||||
@@ -95,12 +92,12 @@ dependencies {
|
||||
// Animation
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
// Player Animation Library (bundled into your mod)
|
||||
// Player Animation Library
|
||||
include modImplementation(
|
||||
"dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim}"
|
||||
)
|
||||
|
||||
// Optional: BendyLib (only if you directly use it)
|
||||
// Optional: BendyLib
|
||||
// include modRuntimeOnly(
|
||||
// "io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendylib_version}"
|
||||
// )
|
||||
@@ -110,7 +107,7 @@ dependencies {
|
||||
// External Libraries
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
// Session Java (auth/session handling)
|
||||
// Session Java (Saturn auth/session handling)
|
||||
include implementation("com.github.selimaj-dev:session-java:0.1.6")
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.saturnclient.saturnclient.cosmetics;
|
||||
package org.saturnclient.cosmetics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
+27
-18
@@ -1,10 +1,9 @@
|
||||
package org.saturnclient.saturnclient.cosmetics;
|
||||
package org.saturnclient.cosmetics.cloak;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.config.Config;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
|
||||
|
||||
import net.minecraft.client.render.OverlayTexture;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
@@ -24,6 +23,7 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.equipment.EquipmentAsset;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.RotationAxis;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ import net.minecraft.util.math.Vec3d;
|
||||
*/
|
||||
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
||||
private final EquipmentModelLoader equipmentModelLoader;
|
||||
private static final int PARTS = 16;
|
||||
private static final int PARTS = 24;
|
||||
private final float[] segmentValues = new float[PARTS];
|
||||
|
||||
private static final float TEX_W = 176f;
|
||||
@@ -208,23 +208,23 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
Vec3d innerBotRight = new Vec3d(x1, nextY, nextZ);
|
||||
|
||||
// Outer Vertices (Offset by the specific joint thickness)
|
||||
Vec3d outerTopLeft = new Vec3d(x2, curY + thickYStart, curZ + thickZStart);
|
||||
Vec3d outerTopRight = new Vec3d(x1, curY + thickYStart, curZ + thickZStart);
|
||||
Vec3d outerBotLeft = new Vec3d(x2, nextY + thickYEnd, nextZ + thickZEnd);
|
||||
Vec3d outerBotRight = new Vec3d(x1, nextY + thickYEnd, nextZ + thickZEnd);
|
||||
Vec3d outerTopLeft = new Vec3d(x2, curY - thickYStart, curZ - thickZStart);
|
||||
Vec3d outerTopRight = new Vec3d(x1, curY - thickYStart, curZ - thickZStart);
|
||||
Vec3d outerBotLeft = new Vec3d(x2, nextY - thickYEnd, nextZ - thickZEnd);
|
||||
Vec3d outerBotRight = new Vec3d(x1, nextY - thickYEnd, nextZ - thickZEnd);
|
||||
|
||||
// FRONT (Inner) - Changed winding/order to fix flipping
|
||||
this.renderCapeQuad(vertexConsumer, matrixStack,
|
||||
innerBotLeft, innerBotRight, innerTopRight, innerTopLeft,
|
||||
frontU1, frontV1 + (frontPartV * i), frontU2, frontV1 + (frontPartV * (i + 1)),
|
||||
light, overlay, 0, 0, -1, false);
|
||||
|
||||
// BACK (Outer)
|
||||
// FRONT (facing camera)
|
||||
this.renderCapeQuad(vertexConsumer, matrixStack,
|
||||
outerBotRight, outerBotLeft, outerTopLeft, outerTopRight,
|
||||
backU1, backV1 + (backPartV * i), backU2, backV1 + (backPartV * (i + 1)),
|
||||
frontU2, frontV1 + (frontPartV * i), frontU1, frontV1 + (frontPartV * (i + 1)),
|
||||
light, overlay, 0, 0, 1, false);
|
||||
|
||||
// BACK (Facing player)
|
||||
this.renderCapeQuad(vertexConsumer, matrixStack,
|
||||
innerBotLeft, innerBotRight, innerTopRight, innerTopLeft,
|
||||
backU2, backV1 + (backPartV * i), backU1, backV1 + (backPartV * (i + 1)),
|
||||
light, overlay, 0, 0, -1, false);
|
||||
|
||||
// LEFT EDGE
|
||||
this.renderCapeQuad(vertexConsumer, matrixStack,
|
||||
innerBotLeft, outerBotLeft, outerTopLeft, innerTopLeft,
|
||||
@@ -300,16 +300,25 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
|
||||
matrixStack.push();
|
||||
|
||||
matrixStack.translate(0.0f, 0.0f, 0.19f);
|
||||
matrixStack.translate(0.0f, 0.0f, 0.12f);
|
||||
|
||||
if (this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.HUMANOID)) {
|
||||
matrixStack.translate(0.0F, -0.053125F, 0.06875F);
|
||||
}
|
||||
|
||||
if (playerEntityRenderState.isInSneakingPose) {
|
||||
matrixStack.translate(0, 0.16f, 0.0f);
|
||||
matrixStack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(29.0f));
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastUpdate >= 20) {
|
||||
float value = Math.min(1.0f, playerEntityRenderState.field_53537 / 108.0f)
|
||||
+ (Math.max(0, playerEntityRenderState.field_53536) / 16);
|
||||
float velX = Math.min(1.0f, playerEntityRenderState.field_53537 / 108.0f);
|
||||
float rawVelY = playerEntityRenderState.field_53536;
|
||||
float velY = (rawVelY > 4.0f ? rawVelY : 0.0f) / 16;
|
||||
|
||||
float value = playerEntityRenderState.isSwimming ? 0.0f : velX + velY;
|
||||
|
||||
if (Config.cloakPhysics.value) {
|
||||
updateSegmentValues(value);
|
||||
} else {
|
||||
+3
-3
@@ -1,11 +1,9 @@
|
||||
package org.saturnclient.saturnclient.cosmetics.cloaks;
|
||||
package org.saturnclient.cosmetics.cloak;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import org.saturnclient.saturnclient.client.ServiceClient;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.utils.AnimatedCloakData;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.utils.IdentifierUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -17,6 +15,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.saturnclient.cosmetics.cloak.utils.AnimatedCloakData;
|
||||
import org.saturnclient.cosmetics.cloak.utils.IdentifierUtils;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
|
||||
/**
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.saturnclient.saturnclient.cosmetics.cloaks;
|
||||
package org.saturnclient.cosmetics.cloak;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.saturnclient.saturnclient.cosmetics.cloaks.utils;
|
||||
package org.saturnclient.cosmetics.cloak.utils;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.saturnclient.saturnclient.cosmetics.cloaks.utils;
|
||||
package org.saturnclient.cosmetics.cloak.utils;
|
||||
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import net.minecraft.client.texture.NativeImage;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.saturnclient.saturnclient.cosmetics.cloaks.utils;
|
||||
package org.saturnclient.cosmetics.cloak.utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.saturnclient.cosmetics.hat;
|
||||
|
||||
import org.saturnclient.cosmetics.obj.MtlLoader;
|
||||
import org.saturnclient.cosmetics.obj.ObjModel;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
|
||||
import net.minecraft.client.render.OverlayTexture;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
||||
public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
|
||||
PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
||||
SaturnPlayer player = SaturnPlayer.get(state.name);
|
||||
|
||||
if (state.invisible || player == null || player.hat.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
matrices.push();
|
||||
|
||||
this.getContextModel().head.rotate(matrices);
|
||||
|
||||
ObjModel.cosmetic("hat", player.hat).render(MtlLoader.cosmetic(player.hat),
|
||||
matrices, vertexConsumers, light,
|
||||
OverlayTexture.DEFAULT_UV);
|
||||
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.saturnclient.saturnclient.cosmetics;
|
||||
package org.saturnclient.cosmetics.hat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.saturnclient.cosmetics.obj;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import de.javagl.obj.*;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class MtlLoader {
|
||||
static Map<Identifier, Map<String, Mtl>> loadedMtls = new HashMap<>();
|
||||
|
||||
static Map<String, Mtl> loadMtl(Identifier mtlId) throws IOException {
|
||||
try (InputStream is = MinecraftClient.getInstance().getResourceManager()
|
||||
.getResource(mtlId).get().getInputStream()) {
|
||||
List<Mtl> mtlList = MtlReader.read(is);
|
||||
Map<String, Mtl> mtlMap = new java.util.LinkedHashMap<>();
|
||||
for (Mtl mtl : mtlList) {
|
||||
mtlMap.put(mtl.getName(), mtl);
|
||||
}
|
||||
return mtlMap;
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, Mtl> of(Identifier mtlId) {
|
||||
System.out.println(mtlId);
|
||||
if (loadedMtls.containsKey(mtlId))
|
||||
return loadedMtls.get(mtlId);
|
||||
|
||||
try {
|
||||
Map<String, Mtl> mtl = loadMtl(mtlId);
|
||||
loadedMtls.put(mtlId, mtl);
|
||||
|
||||
return mtl;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Mtl> cosmetic(String cosmeticId) {
|
||||
int index = cosmeticId.indexOf('_');
|
||||
|
||||
String mtlId = (index == -1) ? "" : cosmeticId.substring(index + 1);
|
||||
|
||||
if (mtlId.isEmpty())
|
||||
mtlId = "white";
|
||||
|
||||
return of(Identifier.of("saturnclient", "models/cosmetic/materials/" + mtlId + ".mtl"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.saturnclient.cosmetics.obj;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import de.javagl.obj.Mtl;
|
||||
import de.javagl.obj.Obj;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.resource.Resource;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class ObjModel {
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
public static final Map<Identifier, ObjModel> loadedObjModels = new HashMap<>();
|
||||
|
||||
public record Config(
|
||||
@JsonProperty("translate") Vec3d transform,
|
||||
@JsonProperty("scale") Vec3d scale,
|
||||
@JsonProperty("rotation") Vec3d rotation) {
|
||||
|
||||
public Config {
|
||||
transform = transform == null ? new Vec3d(0, 0, 0) : transform;
|
||||
scale = scale == null ? new Vec3d(1, 1, 1) : scale;
|
||||
rotation = rotation == null ? new Vec3d(0, 0, 0) : rotation;
|
||||
}
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
|
||||
public record Vec3d(float x, float y, float z) {
|
||||
}
|
||||
}
|
||||
|
||||
Obj obj;
|
||||
Config config;
|
||||
|
||||
public static ObjModel cosmetic(String cosmeticKind, String id) {
|
||||
return of(Identifier.of("saturnclient", "models/cosmetic/" + cosmeticKind + "/" + id.split("_")[0] + "/model"));
|
||||
}
|
||||
|
||||
public static ObjModel of(Identifier obj) {
|
||||
if (loadedObjModels.containsKey(obj))
|
||||
return loadedObjModels.get(obj);
|
||||
|
||||
ObjModel o = new ObjModel(obj);
|
||||
loadedObjModels.put(obj, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
ObjModel(Identifier identifier) {
|
||||
Identifier objId = Identifier.of(identifier.getNamespace(), identifier.getPath() + ".obj");
|
||||
Identifier jsonId = Identifier.of(identifier.getNamespace(), identifier.getPath() + ".json");
|
||||
|
||||
try {
|
||||
this.obj = ObjRenderer.loadObj(objId);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Try loading JSON config if it exists
|
||||
ResourceManager resourceManager = MinecraftClient.getInstance().getResourceManager();
|
||||
Optional<Resource> resource = resourceManager.getResource(jsonId);
|
||||
|
||||
if (resource.isPresent()) {
|
||||
try (InputStream stream = resource.get().getInputStream()) {
|
||||
this.config = MAPPER.readValue(stream, Config.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void render(Map<String, Mtl> mtlMap, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
|
||||
int overlay) {
|
||||
matrices.push();
|
||||
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(180.0f));
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(180.0f));
|
||||
|
||||
if (this.config != null) {
|
||||
matrices.translate(config.transform.x, config.transform.y, config.transform.z);
|
||||
|
||||
matrices.scale(config.scale.x, config.scale.y, config.scale.z);
|
||||
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(config.rotation.x));
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(config.rotation.y));
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Z.rotationDegrees(config.rotation.z));
|
||||
}
|
||||
|
||||
ObjRenderer.renderObj(this.obj, mtlMap, matrices, vertexConsumers, light, overlay);
|
||||
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package org.saturnclient.cosmetics.obj;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import de.javagl.obj.*;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class ObjRenderer {
|
||||
public static Obj loadObj(Identifier objId) throws IOException {
|
||||
try (InputStream is = MinecraftClient.getInstance().getResourceManager()
|
||||
.getResource(objId).get().getInputStream()) {
|
||||
return ObjReader.read(is);
|
||||
}
|
||||
}
|
||||
|
||||
public static void renderObj(Obj obj, Map<String, Mtl> mtlMap, MatrixStack matrices,
|
||||
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
||||
MatrixStack.Entry entry = matrices.peek();
|
||||
|
||||
Map<String, Obj> materialGroups = ObjSplitting.splitByMaterialGroups(obj);
|
||||
|
||||
for (Map.Entry<String, Obj> group : materialGroups.entrySet()) {
|
||||
String materialName = group.getKey();
|
||||
Obj groupObj = group.getValue();
|
||||
|
||||
Mtl mtl = mtlMap != null ? mtlMap.get(materialName) : null;
|
||||
|
||||
// Resolve texture identifier using same logic as ObjUnbakedModelModel
|
||||
Identifier texture = Identifier.of("minecraft:textures/misc/white.png");
|
||||
|
||||
if (mtl != null) {
|
||||
String mapKd = mtl.getMapKd();
|
||||
if (mapKd != null) {
|
||||
// "#key" references are not resolvable at runtime without a texture map,
|
||||
// so we only support direct resource location strings here
|
||||
if (!mapKd.startsWith("#")) {
|
||||
texture = Identifier.of(mapKd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Diffuse color (Kd)
|
||||
float r = 1f, g = 1f, b = 1f;
|
||||
if (mtl != null) {
|
||||
FloatTuple kd = mtl.getKd();
|
||||
if (kd != null) {
|
||||
r = kd.getX();
|
||||
g = kd.getY();
|
||||
b = kd.getZ();
|
||||
}
|
||||
}
|
||||
|
||||
VertexConsumer consumer = vertexConsumers.getBuffer(RenderLayer.getEntityAlpha(texture));
|
||||
|
||||
int faces = groupObj.getNumFaces();
|
||||
final float fr = r, fg = g, fb = b;
|
||||
|
||||
for (int f = 0; f < faces; f++) {
|
||||
ObjFace face = groupObj.getFace(f);
|
||||
int verts = face.getNumVertices();
|
||||
|
||||
// Your original winding order logic, untouched
|
||||
for (int i = verts - 1; i >= 0; i--) {
|
||||
writeVertex(groupObj, face, i, consumer, entry, light, overlay, fr, fg, fb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeVertex(Obj obj, ObjFace face, int index, VertexConsumer consumer,
|
||||
MatrixStack.Entry matrix, int light, int overlay,
|
||||
float r, float g, float b) {
|
||||
|
||||
FloatTuple pos = obj.getVertex(face.getVertexIndex(index));
|
||||
float x = pos.getX();
|
||||
float y = pos.getY();
|
||||
float z = pos.getZ();
|
||||
|
||||
float nx = 0f, ny = 1f, nz = 0f;
|
||||
int normalIndex = face.getNormalIndex(index);
|
||||
if (normalIndex >= 0) {
|
||||
FloatTuple n = obj.getNormal(normalIndex);
|
||||
nx = n.getX();
|
||||
ny = n.getY();
|
||||
nz = n.getZ();
|
||||
}
|
||||
|
||||
float u = 0f, v = 0f;
|
||||
int texIndex = face.getTexCoordIndex(index);
|
||||
if (texIndex >= 0) {
|
||||
FloatTuple tc = obj.getTexCoord(texIndex);
|
||||
u = tc.getX();
|
||||
v = 1f - tc.getY(); // Flip V: OBJ bottom-left origin -> Minecraft top-left
|
||||
}
|
||||
|
||||
consumer.vertex(matrix, x, y, z)
|
||||
.color(r, g, b, 1f)
|
||||
.texture(u, v)
|
||||
.overlay(overlay)
|
||||
.light(light)
|
||||
.normal(matrix, nx, ny, nz);
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,13 @@ import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
import org.saturnclient.cosmetics.Emotes;
|
||||
import org.saturnclient.cosmetics.cloak.Cloaks;
|
||||
import org.saturnclient.cosmetics.hat.Hats;
|
||||
import org.saturnclient.modules.ModManager;
|
||||
import org.saturnclient.saturnclient.client.ServiceClient;
|
||||
import org.saturnclient.saturnclient.config.Config;
|
||||
import org.saturnclient.saturnclient.config.manager.ConfigManager;
|
||||
import org.saturnclient.saturnclient.cosmetics.Emotes;
|
||||
import org.saturnclient.saturnclient.cosmetics.Hats;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
|
||||
import org.saturnclient.saturnclient.event.KeyInputHandler;
|
||||
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
||||
import org.saturnclient.ui2.RenderScope;
|
||||
@@ -23,8 +23,6 @@ import org.saturnclient.ui2.screens.TitleMenu;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dev.felnull.specialmodelloader.api.event.SpecialModelLoaderEvents;
|
||||
|
||||
/**
|
||||
* Main class for the Saturn Client mod.
|
||||
*/
|
||||
@@ -47,10 +45,6 @@ public class SaturnClient implements ModInitializer {
|
||||
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> ConfigManager.save());
|
||||
|
||||
SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> {
|
||||
return (resourceManager, location) -> MOD_ID.equals(location.getNamespace());
|
||||
});
|
||||
|
||||
ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
|
||||
if (screen != null && !(screen instanceof TitleMenu)) {
|
||||
if (screen instanceof SaturnScreen) {
|
||||
|
||||
@@ -3,10 +3,10 @@ package org.saturnclient.saturnclient.client;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.saturnclient.cosmetics.cloak.Cloaks;
|
||||
import org.saturnclient.cosmetics.hat.Hats;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.cosmetics.Hats;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
|
||||
|
||||
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package org.saturnclient.saturnclient.cosmetics;
|
||||
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import net.minecraft.client.render.OverlayTexture;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.component.type.EquippableComponent;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.item.ModelTransformationMode;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
||||
public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
|
||||
PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
||||
ItemStack headItem = state.equippedHeadStack;
|
||||
SaturnPlayer player = SaturnPlayer.get(state.name);
|
||||
|
||||
if (!headItem.isEmpty() || state.invisible || player == null || player.hat.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
matrices.push();
|
||||
|
||||
this.getContextModel().head.rotate(matrices);
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(180.0f));
|
||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(180.0f));
|
||||
|
||||
ItemStack customHat = new ItemStack(Items.STICK);
|
||||
customHat.set(DataComponentTypes.ITEM_MODEL,
|
||||
Identifier.of("saturnclient:hat_" + player.hat));
|
||||
customHat.set(DataComponentTypes.EQUIPPABLE,
|
||||
EquippableComponent.builder(EquipmentSlot.HEAD).build());
|
||||
|
||||
ItemRenderer itemRenderer = SaturnClient.client.getItemRenderer();
|
||||
|
||||
itemRenderer.renderItem(
|
||||
customHat,
|
||||
ModelTransformationMode.THIRD_PERSON_RIGHT_HAND,
|
||||
light,
|
||||
OverlayTexture.DEFAULT_UV,
|
||||
matrices,
|
||||
vertexConsumers,
|
||||
null,
|
||||
0);
|
||||
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
import org.saturnclient.saturnclient.cosmetics.CloakFeatureRenderer;
|
||||
import org.saturnclient.saturnclient.cosmetics.HatFeatureRenderer;
|
||||
import org.saturnclient.cosmetics.cloak.CloakFeatureRenderer;
|
||||
import org.saturnclient.cosmetics.hat.HatFeatureRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.kitfox.svg.SVGDiagram;
|
||||
import com.kitfox.svg.SVGUniverse;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.utils.IdentifierUtils;
|
||||
import org.saturnclient.cosmetics.cloak.utils.IdentifierUtils;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.saturnclient.ui2.screens;
|
||||
|
||||
import org.saturnclient.cosmetics.Emotes;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import org.saturnclient.saturnclient.client.ServiceClient;
|
||||
import org.saturnclient.saturnclient.config.AnimationConfig;
|
||||
import org.saturnclient.saturnclient.config.Config;
|
||||
import org.saturnclient.saturnclient.cosmetics.Emotes;
|
||||
import org.saturnclient.ui2.SaturnScreen;
|
||||
import org.saturnclient.ui2.Utils;
|
||||
import org.saturnclient.ui2.anim.Fade;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.saturnclient.ui2.screens.cosmetics;
|
||||
|
||||
import org.saturnclient.cosmetics.cloak.Cloaks;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.config.AnimationConfig;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
|
||||
import org.saturnclient.ui2.resources.Textures;
|
||||
import org.saturnclient.ui2.SaturnScreen;
|
||||
import org.saturnclient.ui2.anim.Fade;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.saturnclient.ui2.screens.cosmetics;
|
||||
|
||||
import org.saturnclient.cosmetics.hat.Hats;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.config.AnimationConfig;
|
||||
import org.saturnclient.saturnclient.cosmetics.Hats;
|
||||
import org.saturnclient.ui2.resources.Textures;
|
||||
import org.saturnclient.ui2.SaturnScreen;
|
||||
import org.saturnclient.ui2.anim.Fade;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.saturnclient.ui2.screens.store;
|
||||
|
||||
import org.saturnclient.cosmetics.cloak.Cloaks;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import org.saturnclient.saturnclient.client.ServiceClient;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.config.AnimationConfig;
|
||||
import org.saturnclient.saturnclient.config.Theme;
|
||||
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
|
||||
import org.saturnclient.ui2.SaturnScreen;
|
||||
import org.saturnclient.ui2.Utils;
|
||||
import org.saturnclient.ui2.anim.Fade;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.saturnclient.ui2.screens.store;
|
||||
|
||||
import org.saturnclient.cosmetics.hat.Hats;
|
||||
import org.saturnclient.saturnclient.SaturnClient;
|
||||
import org.saturnclient.saturnclient.client.ServiceClient;
|
||||
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||
import org.saturnclient.saturnclient.config.AnimationConfig;
|
||||
import org.saturnclient.saturnclient.config.Theme;
|
||||
import org.saturnclient.saturnclient.cosmetics.Hats;
|
||||
import org.saturnclient.ui2.SaturnScreen;
|
||||
import org.saturnclient.ui2.Utils;
|
||||
import org.saturnclient.ui2.anim.Fade;
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "saturnclient:item/halo/white"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "saturnclient:item/halo/black"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "saturnclient:item/horns/black"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "saturnclient:item/horns/white"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"translate": [0.0, 0.62, 0.0],
|
||||
"scale": [0.2, 0.1, 0.2]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"translate": [0.0, 0.25, 0.0],
|
||||
"scale": [0.25, 0.25, 0.25]
|
||||
}
|
||||
+1
-1
@@ -10,4 +10,4 @@ Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd saturnclient:item/halo_black
|
||||
map_Kd saturnclient:textures/item/halo_black.png
|
||||
+1
-1
@@ -10,4 +10,4 @@ Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd saturnclient:item/halo
|
||||
map_Kd saturnclient:textures/item/halo.png
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"parent": "special-model-loader:builtin/obj",
|
||||
"model": "saturnclient:models/item/halo/halo.obj",
|
||||
"mtl_override": "saturnclient:models/item/black.mtl",
|
||||
"flip_v": true,
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [0, 0, 0],
|
||||
"translation": [1.5, 12, 1.5],
|
||||
"scale": [0.2, 0.2, 0.2]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"parent": "special-model-loader:builtin/obj",
|
||||
"model": "saturnclient:models/item/halo/halo.obj",
|
||||
"mtl_override": "saturnclient:models/item/white.mtl",
|
||||
"flip_v": true,
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [0, 0, 0],
|
||||
"translation": [1.5, 12, 1.5],
|
||||
"scale": [0.2, 0.2, 0.2]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"parent": "special-model-loader:builtin/obj",
|
||||
"model": "saturnclient:models/item/horns/horns.obj",
|
||||
"mtl_override": "saturnclient:models/item/black.mtl",
|
||||
"flip_v": true,
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [0, 0, 0],
|
||||
"translation": [2, 6, 2],
|
||||
"scale": [0.25, 0.25, 0.25]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"parent": "special-model-loader:builtin/obj",
|
||||
"model": "saturnclient:models/item/horns/horns.obj",
|
||||
"mtl_override": "saturnclient:models/item/white.mtl",
|
||||
"flip_v": true,
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [0, 0, 0],
|
||||
"translation": [2, 6, 2],
|
||||
"scale": [0.25, 0.25, 0.25]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user