# Conflicts:
#	src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java
This commit is contained in:
Matthew Messinger 2018-07-22 15:52:09 -04:00
commit 8c03c42a3a
17 changed files with 284 additions and 113 deletions

View file

@ -1,3 +1,4 @@
#Build Number for ANT. Do not edit!
#Wed Jul 11 12:06:53 CAT 2018
build.number=503
#Sun Jul 08 20:46:02 CAT 2018
build.number=500
>>>>>>> Build number pls

View file

@ -24,6 +24,7 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import com.voxelmodpack.hdskins.gui.GuiSkins;
import com.voxelmodpack.hdskins.resource.SkinResourceManager;
import com.voxelmodpack.hdskins.skins.AsyncCacheLoader;
import com.voxelmodpack.hdskins.skins.BethlehemSkinServer;
import com.voxelmodpack.hdskins.skins.LegacySkinServer;
import com.voxelmodpack.hdskins.skins.ServerType;
import com.voxelmodpack.hdskins.skins.SkinServer;
@ -98,6 +99,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
// register default skin server types
addSkinServerType(LegacySkinServer.class);
addSkinServerType(ValhallaSkinServer.class);
addSkinServerType(BethlehemSkinServer.class);
}
public void setPrefferedSkinsGuiClass(Class<? extends GuiSkins> clazz) {

View file

@ -1,14 +1,16 @@
package com.voxelmodpack.hdskins.mod;
package com.voxelmodpack.hdskins;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.mumfrey.liteloader.Configurable;
import com.mumfrey.liteloader.InitCompleteListener;
import com.mumfrey.liteloader.ViewportListener;
import com.mumfrey.liteloader.core.LiteLoader;
import com.mumfrey.liteloader.modconfig.AdvancedExposable;
import com.mumfrey.liteloader.modconfig.ConfigPanel;
import com.mumfrey.liteloader.modconfig.ConfigStrategy;
import com.mumfrey.liteloader.modconfig.ExposableOptions;
import com.mumfrey.liteloader.util.ModUtilities;
import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
import com.voxelmodpack.hdskins.gui.GLWindow;
import com.voxelmodpack.hdskins.gui.HDSkinsConfigPanel;
@ -23,7 +25,7 @@ import java.io.File;
import java.util.List;
@ExposableOptions(strategy = ConfigStrategy.Unversioned, filename = "hdskins")
public class LiteModHDSkinsMod implements HDSkinsMod, AdvancedExposable {
public class LiteModHDSkins implements InitCompleteListener, ViewportListener, Configurable, AdvancedExposable {
@Expose
public List<SkinServer> skin_servers = SkinServer.defaultServers;
@ -49,10 +51,6 @@ public class LiteModHDSkinsMod implements HDSkinsMod, AdvancedExposable {
IReloadableResourceManager irrm = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager();
irrm.registerReloadListener(HDSkinManager.INSTANCE);
if (experimentalSkinDrop) {
GLWindow.create();
}
}
@Override
@ -81,6 +79,10 @@ public class LiteModHDSkinsMod implements HDSkinsMod, AdvancedExposable {
// register skin servers.
skin_servers.forEach(HDSkinManager.INSTANCE::addSkinServer);
if (experimentalSkinDrop) {
GLWindow.create();
}
}
@Override

View file

@ -5,7 +5,7 @@ import com.mumfrey.liteloader.core.LiteLoader;
import com.mumfrey.liteloader.modconfig.ConfigPanel;
import com.mumfrey.liteloader.modconfig.ConfigPanelHost;
import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.mod.LiteModHDSkinsMod;
import com.voxelmodpack.hdskins.LiteModHDSkins;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
@ -16,11 +16,11 @@ public class HDSkinsConfigPanel implements ConfigPanel {
private GuiCheckbox checkbox;
private LiteModHDSkinsMod mod;
private LiteModHDSkins mod;
@Override
public void onPanelShown(ConfigPanelHost host) {
this.mod = LiteLoader.getInstance().getMod(LiteModHDSkinsMod.class);
this.mod = LiteLoader.getInstance().getMod(LiteModHDSkins.class);
this.button = new GuiButton(0, 40, 70, 100, 20, "Clear Skin Cache");
this.checkbox = new GuiCheckbox(1, 40, 40, "Experimental Skin Drop");

View file

@ -1,8 +0,0 @@
package com.voxelmodpack.hdskins.mod;
import com.mumfrey.liteloader.Configurable;
import com.mumfrey.liteloader.InitCompleteListener;
import com.mumfrey.liteloader.ViewportListener;
public interface HDSkinsMod extends InitCompleteListener, ViewportListener, Configurable {
}

View file

@ -0,0 +1,96 @@
package com.voxelmodpack.hdskins.skins;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.gson.JsonObject;
import com.google.gson.annotations.Expose;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.util.UUIDTypeAdapter;
import com.voxelmodpack.hdskins.HDSkinManager;
import net.minecraft.util.Session;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.IOException;
import java.net.URI;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@ServerType("bethlehem")
public class BethlehemSkinServer implements SkinServer {
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
@Expose
private final String address;
private BethlehemSkinServer(String address) {
this.address = address;
}
@Override
public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
NetClient client = new NetClient("GET", getPath(profile));
String json = client.getResponseText();
JsonObject s = gson.fromJson(json, JsonObject.class);
if (s.has("success") && s.get("success").getAsBoolean()) {
s = s.get("data").getAsJsonObject();
return Optional.ofNullable(gson.fromJson(s, MinecraftTexturesPayload.class));
}
return Optional.empty();
}
@Override
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, URI image, Type type, Map<String, String> metadata) {
return CallableFutures.asyncFailableFuture(() -> {
SkinServer.verifyServerConnection(session, SERVER_ID);
NetClient client = new NetClient("POST", address).putHeaders(createHeaders(session, type, image, metadata));
if (image != null) {
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
}
if (!client.send()) {
throw new IOException(client.getResponseText());
}
return new SkinUploadResponse(client.getResponseText());
}, HDSkinManager.skinUploadExecutor);
}
protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
.put("accessToken", session.getToken())
.put("user", session.getUsername())
.put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId()))
.put("type", type.toString().toLowerCase(Locale.US));
if (image == null) {
builder.put("clear", "1");
} else {
builder.put("model", metadata.getOrDefault("mode", "default"));
}
return builder.build();
}
private String getPath(GameProfile profile) {
return String.format("%s/profile/%s", address, UUIDTypeAdapter.fromUUID(profile.getId()));
}
@Override
public String toString() {
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)
.append("address", address)
.build();
}
}

View file

@ -5,6 +5,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
public class IndentedToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 2031593562293731492L;
public static final ToStringStyle INSTANCE = new IndentedToStringStyle();
private IndentedToStringStyle() {

View file

@ -4,14 +4,11 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.Expose;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.util.UUIDTypeAdapter;
import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Session;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.logging.log4j.LogManager;
@ -83,25 +80,18 @@ public class LegacySkinServer implements SkinServer {
return Optional.empty();
}
return Optional.of(new TexturesPayloadBuilder()
.profileId(profile.getId())
.profileName(profile.getName())
.timestamp(System.currentTimeMillis())
.isPublic(true)
.textures(map)
.build());
return Optional.of(TexturesPayloadBuilder.createTexuresPayload(profile, map));
}
@SuppressWarnings("deprecation")
@Override
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image,
MinecraftProfileTexture.Type type, Map<String, String> metadata) {
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) {
if (Strings.isNullOrEmpty(this.gateway)) {
return CallableFutures.failedFuture(new NullPointerException("gateway url is blank"));
}
return CallableFutures.asyncFailableFuture(() -> {
verifyServerConnection(session, SERVER_ID);
SkinServer.verifyServerConnection(session, SERVER_ID);
String model = metadata.getOrDefault("model", "default");
Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, model, image);
ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data);
@ -139,11 +129,6 @@ public class LegacySkinServer implements SkinServer {
return String.format("%s/%s/%s.png", address, path, uuid);
}
private static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
service.joinServer(session.getProfile(), session.getToken(), serverId);
}
@Override
public String toString() {
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)

View file

@ -0,0 +1,102 @@
package com.voxelmodpack.hdskins.skins;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClients;
/**
* Ew. Why so many builders? >.<
*/
public class NetClient {
private final RequestBuilder rqBuilder;
private Map<String, ?> headers;
private CloseableHttpResponse response = null;
public NetClient(String method, String uri) {
rqBuilder = RequestBuilder.create(method).setUri(uri);
}
public NetClient putFile(String key, String contentType, URI file) {
File f = new File(file);
HttpEntity entity = MultipartEntityBuilder.create().addBinaryBody(key, f, ContentType.create(contentType), f.getName()).build();
rqBuilder.setEntity(entity);
return this;
}
public NetClient putHeaders(Map<String, ?> headers) {
this.headers = headers;
return this;
}
public boolean send() {
HttpUriRequest request = rqBuilder.build();
for (Map.Entry<String, ?> parameter : headers.entrySet()) {
request.addHeader(parameter.getKey(), parameter.getValue().toString());
}
try {
response = HttpClients.createSystem().execute(request);
return getResponseCode() == HttpStatus.SC_OK;
} catch (IOException e) { }
return false;
}
public int getResponseCode() {
if (response == null) {
send();
}
return response.getStatusLine().getStatusCode();
}
public String getResponseText() {
if (response == null) {
if (!send()) {
return "";
}
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder builder = new StringBuilder();
int ch;
while ((ch = reader.read()) != -1) {
builder.append((char)ch);
}
return builder.toString();
} catch (IOException e) {
} finally {
IOUtils.closeQuietly(reader);
}
return "";
}
}

View file

@ -1,9 +1,17 @@
package com.voxelmodpack.hdskins.skins;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.util.UUIDTypeAdapter;
import com.mumfrey.liteloader.modconfig.Exposable;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Session;
import java.net.URI;
@ -11,11 +19,16 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
public interface SkinServer {
public interface SkinServer extends Exposable {
static final Gson gson = new GsonBuilder()
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
.create();
List<SkinServer> defaultServers = Lists.newArrayList(new LegacySkinServer(
"http://skins.voxelmodpack.com",
@ -27,7 +40,11 @@ public interface SkinServer {
return loadProfileData(profile).map(MinecraftTexturesPayload::getTextures).orElse(Collections.emptyMap());
}
CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image,
MinecraftProfileTexture.Type type, Map<String, String> metadata);
CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata);
public static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
service.joinServer(session.getProfile(), session.getToken(), serverId);
}
}

View file

@ -17,18 +17,21 @@ public class SkinServerSerializer implements JsonSerializer<SkinServer>, JsonDes
@Override
public JsonElement serialize(SkinServer src, Type typeOfSrc, JsonSerializationContext context) {
ServerType serverType = src.getClass().getAnnotation(ServerType.class);
if (serverType == null) {
throw new JsonIOException("Skin server class did not have a type: " + typeOfSrc);
}
JsonObject obj = context.serialize(src).getAsJsonObject();
obj.addProperty("type", serverType.value());
return obj;
}
@Override
public SkinServer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String type = json.getAsJsonObject().get("type").getAsString();
Class<? extends SkinServer> clas = HDSkinManager.INSTANCE.getSkinServerClass(type);
return context.deserialize(json, clas);
return context.deserialize(json, HDSkinManager.INSTANCE.getSkinServerClass(type));
}
}

View file

@ -3,7 +3,9 @@ package com.voxelmodpack.hdskins.skins;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.util.UUIDTypeAdapter;
@ -20,46 +22,26 @@ public class TexturesPayloadBuilder {
private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
public static MinecraftTexturesPayload createTexuresPayload(GameProfile profile, Map<Type, MinecraftProfileTexture> textures) {
return gson.fromJson(gson.toJson(new TexturesPayloadBuilder(profile, textures)), MinecraftTexturesPayload.class);
}
private long timestamp;
private UUID profileId;
private String profileName;
private boolean isPublic;
private Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures;
public TexturesPayloadBuilder timestamp(long time) {
this.timestamp = time;
return this;
}
private Map<Type, MinecraftProfileTexture> textures;
public TexturesPayloadBuilder profileId(UUID uuid) {
this.profileId = uuid;
return this;
}
public TexturesPayloadBuilder(GameProfile profile, Map<Type, MinecraftProfileTexture> textures) {
profileId = profile.getId();
profileName = profile.getName();
timestamp = System.currentTimeMillis();
public TexturesPayloadBuilder profileName(String name) {
this.profileName = name;
return this;
}
isPublic = true;
public TexturesPayloadBuilder isPublic(boolean pub) {
this.isPublic = pub;
return this;
}
public TexturesPayloadBuilder texture(MinecraftProfileTexture.Type type, MinecraftProfileTexture texture) {
if (textures == null) textures = Maps.newEnumMap(MinecraftProfileTexture.Type.class);
this.textures.put(type, texture);
return this;
}
public TexturesPayloadBuilder textures(Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures) {
this.textures = textures;
return this;
}
public MinecraftTexturesPayload build() {
return gson.fromJson(gson.toJson(this), MinecraftTexturesPayload.class);
}
}

View file

@ -1,8 +1,6 @@
package com.voxelmodpack.hdskins.skins;
import com.google.common.base.Preconditions;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.annotations.Expose;
import com.mojang.authlib.GameProfile;
@ -46,9 +44,6 @@ public class ValhallaSkinServer implements SkinServer {
@Expose
private final String address;
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
.create();
private transient String accessToken;
@ -73,8 +68,7 @@ public class ValhallaSkinServer implements SkinServer {
}
@Override
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image,
MinecraftProfileTexture.Type type, Map<String, String> metadata) {
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) {
return CallableFutures.asyncFailableFuture(() -> {
try (CloseableHttpClient client = HttpClients.createSystem()) {
authorize(client, session);
@ -104,8 +98,7 @@ public class ValhallaSkinServer implements SkinServer {
.build());
}
private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type,
Map<String, String> metadata) throws IOException {
private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
MultipartEntityBuilder b = MultipartEntityBuilder.create();
b.addBinaryBody("file", file, ContentType.create("image/png"), file.getName());
metadata.forEach(b::addTextBody);
@ -117,8 +110,7 @@ public class ValhallaSkinServer implements SkinServer {
.build());
}
private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type,
Map<String, String> metadata) throws IOException {
private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
return upload(client, RequestBuilder.post()
.setUri(buildUserTextureUri(profile, type))

View file

@ -729,16 +729,17 @@ public abstract class AbstractPonyModel extends ModelPlayer implements IModel {
@Override
public float getRiderYOffset() {
if (isChild()) {
return 1.05F;
return 0.25F;
}
switch (getMetadata().getSize()) {
case NORMAL: return 0.4F;
case FOAL: return 1.05F;
case FOAL:
case TALL:
case LARGE:
default: return 0.25F;
default: return 0.25F;
}
}

View file

@ -4,10 +4,10 @@ import com.minelittlepony.MineLittlePony;
import com.minelittlepony.transform.PonyTransformation;
public enum PonySize implements ITriggerPixelMapped<PonySize> {
NORMAL(0, 0.4f, 1f, PonyTransformation.NORMAL),
LARGE(0xce3254, 0.5f, 0.8f, PonyTransformation.LARGE),
FOAL(0xffbe53, 0.25f, 0.8f, PonyTransformation.FOAL),
TALL(0x534b76, 0.45f, 1f, PonyTransformation.TALL);
TALL(0x534b76, 0.45f, 1.1F, PonyTransformation.TALL),
LARGE(0xce3254, 0.5f, 1, PonyTransformation.LARGE),
NORMAL(0, 0.4f, 0.8F, PonyTransformation.NORMAL),
FOAL(0xffbe53, 0.25f, 0.5F, PonyTransformation.FOAL);
private int triggerValue;

View file

@ -112,7 +112,7 @@ public class RenderPonyPlayer extends RenderPlayer implements IRenderPony {
@Override
public float prepareScale(AbstractClientPlayer player, float ticks) {
if (!player.isRiding()) {
if (!player.isRiding() && !player.isPlayerSleeping()) {
float x = player.width/2;
float y = 0;
@ -147,7 +147,7 @@ public class RenderPonyPlayer extends RenderPlayer implements IRenderPony {
@Override
public void doRenderShadowAndFire(Entity player, double x, double y, double z, float yaw, float ticks) {
if (player.isRiding()) {
if (player.isRiding() && ((AbstractClientPlayer)player).isPlayerSleeping()) {
super.doRenderShadowAndFire(player, x, y, z, yaw, ticks);
}
}

View file

@ -11,7 +11,7 @@ public enum PonyTransformation {
NORMAL {
@Override
public void transform(IModel model, BodyPart part) {
if (model.isSleeping()) translate(0, -0.61F, 0.25F);
if (model.isSleeping()) translate(0, -0.61F, 0);
switch (part) {
case NECK:
@ -52,31 +52,25 @@ public enum PonyTransformation {
FOAL {
@Override
public void transform(IModel model, BodyPart part) {
if (model.isCrouching()) translate(0, -0.12F, 0);
if (model.isSleeping()) translate(0, -1.48F, 0.25F);
if (model.isRiding()) translate(0, -0.1F, 0);
if (model.isCrouching()) translate(0, -0.3F, 0);
if (model.isSleeping()) translate(0, -0.6F, -0.5F);
if (model.isRiding()) translate(0, -0.4F, 0);
translate(0, 0.2F, 0);
switch (part) {
case NECK:
translate(0, 0.76F, 0);
scale(0.9F, 0.9F, 0.9F);
scale(1.3F, 1.3F, 1.3F);
if (model.isCrouching()) translate(0, -0.01F, 0.15F);
break;
case HEAD:
translate(0, 0.76F, 0);
scale(0.9F, 0.9F, 0.9F);
break;
case BODY:
case TAIL:
translate(0, 0.76F, -0.04F);
scale(0.6F, 0.6F, 0.6F);
scale(1.3F, 1.3F, 1.3F);
break;
case LEGS:
translate(0, 0.89F, 0);
scale(0.6F, 0.41F, 0.6F);
if (model.isCrouching()) translate(0, 0.12F, 0);
if (model.isGoingFast()) translate(0, -0.08F, 0);
translate(0, 0.1F, 0);
scale(1, 0.81F, 1);
break;
default:
}
}
},