feat: add capes

This commit is contained in:
Timo Ley 2023-02-06 11:27:57 +01:00
parent 20858b2b9f
commit faaf0430d4
17 changed files with 992 additions and 1 deletions

View File

@ -2,8 +2,9 @@ publishing {
tasks.publish.dependsOn 'build'
publications {
mavenJava(MavenPublication) {
artifactId = project.archivesBaseName
artifactId = "appliedenergistics2"
artifact jar
artifact devJar
artifact sourceJar
artifact apiJar

View File

@ -52,6 +52,7 @@ import appeng.util.Platform;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import dev.tilera.capes.Capes;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@ -96,6 +97,7 @@ public class ClientHelper extends ServerHelper {
@Override
public void init() {
MinecraftForge.EVENT_BUS.register(this);
Capes.initCapes();
}
@Override

View File

@ -0,0 +1,163 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import com.jadarstudios.developercapes.cape.CapeConfig;
import com.jadarstudios.developercapes.cape.CapeConfigManager;
import net.minecraftforge.common.MinecraftForge;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* DeveloperCapes is a library for Minecraft. It allows developers to quickly add capes
* for players they specify. DevCapes uses Minecraft Forge.
*
* @author jadar
*/
public class DevCapes {
private static DevCapes instance;
public static final Logger logger = LogManager.getLogger("DevCapes");
protected DevCapes() {
MinecraftForge.EVENT_BUS.register(new RenderEventHandler());
}
public static DevCapes getInstance() {
if (instance == null) {
instance = new DevCapes();
}
return instance;
}
/**
* InputStream.close() needs to be called on this after you're done!
*
* @return {@link InputStream} for the {@link URL}
*/
public InputStream getStreamForURL(URL url) {
InputStream is = null;
try {
URLConnection connection = url.openConnection();
connection.setRequestProperty(
"User-Agent", System.getProperty("java.version")
);
connection.connect();
is = connection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
return is;
}
/**
* InputStream.close() needs to be called on this after you're done!
*
* @return {@link InputStream} for the {@link File}
*/
public InputStream getStreamForFile(File file) {
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return is;
}
@Deprecated
/**
* DEPRECATED: Please use {@link #registerConfig(String jsonUrl)} instead.<p>
* Registers a config with DevCapes.
*
* @param jsonUrl
* The URL as a String that links to the Json file that you want
* to add
* @param identifier
* A unique Identifier, normally your mod id
* @return The id of the registered config
*/
public int registerConfig(String jsonURL, String identifier) {
return this.registerConfig(jsonURL);
}
/**
* Registers a config with DevCapes.
*
* @param jsonUrl The URL as a String that links to the Json file that you want
* to add
* @return The id of the registered config
*/
public int registerConfig(String jsonUrl) {
int id = -1;
try {
URL url = new URL(jsonUrl);
id = this.registerConfig(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return id;
}
@Deprecated
/**
* DEPRECATED: Please use {@link #registerConfig(URL url)} instead.<p>
* Registers a config with DevCapes.
*
* @param jsonUrl
* A {@link URL} that links to the Json file that you want to add
* @param identifier
* A unique Identifier, normally your mod id
* @return The id of the registered config
*/
public int registerConfig(URL url, String identifier) {
return this.registerConfig(url);
}
/**
* Registers a config with DevCapes and returns the ID of the config.
*
* @param jsonUrl A {@link URL} that links to the Json file that you want to add
* @return The id of the registered config
*/
public int registerConfig(URL jsonUrl) {
int id = -1;
InputStream is = this.getStreamForURL(jsonUrl);
if (is == null) {
DevCapes.logger.error(String.format(
"Unable to establish a connection to the server, %s", jsonUrl.getHost()
));
return id;
}
CapeConfig config = CapeConfigManager.getInstance().parse(is);
try {
id = CapeConfigManager.getUniqueId();
CapeConfigManager.getInstance().addConfig(id, config);
} catch (CapeConfigManager.InvalidCapeConfigIdException e) {
e.printStackTrace();
}
silentClose(is);
return id;
}
private static void silentClose(InputStream is) {
try {
is.close();
} catch (IOException ignored) {}
}
}

View File

@ -0,0 +1,41 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 3.3.0.0
*/
package com.jadarstudios.developercapes;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.renderer.IImageBuffer;
/**
* This class is an implementation of {@link IImageBuffer} that allows capes to be in HD
*
* @author Jadar
*/
@SideOnly(Side.CLIENT)
public class HDImageBuffer implements IImageBuffer {
@Override
public BufferedImage parseUserSkin(final BufferedImage texture) {
if (texture == null)
return null;
int imageWidth = texture.getWidth(null) <= 64 ? 64 : texture.getWidth(null);
int imageHeight = texture.getHeight(null) <= 32 ? 32 : texture.getHeight(null);
BufferedImage capeImage = new BufferedImage(imageWidth, imageHeight, 2);
Graphics graphics = capeImage.getGraphics();
graphics.drawImage(texture, 0, 0, null);
graphics.dispose();
return capeImage;
}
@Override
public void func_152634_a() {}
}

View File

@ -0,0 +1,40 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes;
import com.jadarstudios.developercapes.cape.ICape;
import com.jadarstudios.developercapes.user.User;
import com.jadarstudios.developercapes.user.UserManager;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraftforge.client.event.RenderPlayerEvent;
/**
* This is not the class you are looking for.
*
* @author jadar
*/
public class RenderEventHandler {
@SubscribeEvent
public void renderPlayer(RenderPlayerEvent.Specials.Pre event) {
AbstractClientPlayer player = (AbstractClientPlayer) event.entityPlayer;
UserManager manager = UserManager.getInstance();
User user = manager.getUser(player.getUniqueID().toString());
if (user == null)
return;
ICape cape = user.capes.get(0);
if (cape == null)
return;
boolean flag = cape.isTextureLoaded(player);
if (!flag) {
cape.loadTexture(player);
}
}
}

View File

@ -0,0 +1,42 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.cape;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.util.ResourceLocation;
/**
* Abstract Implementation of ICape used within Dev. Capes
*
* @author jadar
*/
public abstract class AbstractCape implements ICape {
protected String name;
protected ITextureObject texture;
protected ResourceLocation location;
public AbstractCape(String name) {
this.name = name;
}
public AbstractCape() {}
@Override
public String getName() {
return name;
}
@Override
public ITextureObject getTexture() {
return this.texture;
}
@Override
public ResourceLocation getLocation() {
return this.location;
}
}

View File

@ -0,0 +1,27 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.cape;
import java.util.HashMap;
import com.jadarstudios.developercapes.user.Group;
import com.jadarstudios.developercapes.user.User;
/**
* The players that need to be outfitted are stored here
*
* @author jadar
*/
public class CapeConfig {
public HashMap<String, Group> groups;
public HashMap<String, User> users;
public CapeConfig() {
groups = new HashMap<String, Group>();
users = new HashMap<String, User>();
}
}

View File

@ -0,0 +1,180 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.cape;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.BitSet;
import java.util.Map;
import com.google.common.collect.HashBiMap;
import com.google.common.primitives.UnsignedBytes;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.jadarstudios.developercapes.DevCapes;
import com.jadarstudios.developercapes.user.Group;
import com.jadarstudios.developercapes.user.GroupManager;
import com.jadarstudios.developercapes.user.User;
import com.jadarstudios.developercapes.user.UserManager;
import org.apache.commons.lang3.ObjectUtils;
/**
* All configs need a manager, this is it.
*
* @author jadar
*/
public class CapeConfigManager {
protected static CapeConfigManager instance;
protected static BitSet availableIds = new BitSet(256);
protected HashBiMap<Integer, CapeConfig> configs;
static {
availableIds.clear(availableIds.size());
}
public CapeConfigManager() {
configs = HashBiMap.create();
}
public static CapeConfigManager getInstance() {
if (instance == null) {
instance = new CapeConfigManager();
}
return instance;
}
public void addConfig(int id, CapeConfig config) throws InvalidCapeConfigIdException {
int realId = claimId(id);
this.configs.put(realId, config);
addUsers(config.users);
addGroups(config.groups);
}
protected void addUsers(Map<String, User> users) {
try {
UserManager.getInstance().addUsers(users.values());
} catch (Exception e) {
e.printStackTrace();
}
}
protected void addGroups(Map<String, Group> groups) {
try {
GroupManager.getInstance().addGroups(groups.values());
} catch (Exception e) {
e.printStackTrace();
}
}
public CapeConfig getConfig(int id) {
return this.configs.get(id);
}
public int getIdForConfig(CapeConfig config) {
return this.configs.inverse().get(config);
}
public static int getUniqueId() {
return availableIds.nextClearBit(1);
}
public static int claimId(int id) throws InvalidCapeConfigIdException {
if (id <= 0) {
throw new InvalidCapeConfigIdException(
"The config ID must be a positive non-zero integer"
);
}
try {
UnsignedBytes.checkedCast(id);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
boolean isRegistered = availableIds.get(id);
if (isRegistered) {
throw new InvalidCapeConfigIdException(
String.format("The config ID %d is already claimed.", id)
);
}
availableIds.set(id);
return id;
}
public CapeConfig parse(InputStream is) {
if (is == null) {
throw new NullPointerException("Can not parse a null input stream!");
}
CapeConfig instance = new CapeConfig();
InputStreamReader isr = new InputStreamReader(is);
try {
Map<String, Object> entries = new Gson().fromJson(isr, Map.class);
for (Map.Entry<String, Object> entry : entries.entrySet()) {
final String nodeName = entry.getKey();
final Object obj = entry.getValue();
if (obj instanceof Map) {
parseGroup(instance, nodeName, (Map) obj);
} else if (obj instanceof String) {
parseUser(instance, nodeName, (String) obj);
}
}
} catch (JsonSyntaxException e) {
DevCapes.logger.error("CapeConfig could not be parsed because:");
e.printStackTrace();
}
return instance;
}
protected void parseGroup(CapeConfig config, String node, Map group) {
Group g = GroupManager.getInstance().parse(node, group);
if (g != null) {
config.groups.put(g.name, g);
}
}
protected void parseUser(CapeConfig config, String node, String user) {
User u = UserManager.getInstance().parse(node, user);
if (u != null) {
config.users.put(node, u);
}
}
/**
* DEPRECATED! Please use {@link
* com.jadarstudios.developercapes.cape.CapeConfigManager#parse(java.io.InputStream
* is)} This will be removed in the next major release.
*/
@Deprecated
public CapeConfig parseFromStream(InputStream is) {
return this.parse(is);
}
public static class InvalidCapeConfigIdException extends Exception {
public InvalidCapeConfigIdException() {
super();
}
public InvalidCapeConfigIdException(String s) {
super(s);
}
public InvalidCapeConfigIdException(Throwable cause) {
super(cause);
}
public InvalidCapeConfigIdException(String message, Throwable cause) {
super(message, cause);
}
}
}

View File

@ -0,0 +1,85 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.cape;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import com.jadarstudios.developercapes.DevCapes;
/**
* This manages all of the capes, be nice to it or you won't get one!
*
* @author jadar
*/
public class CapeManager {
protected static CapeManager instance;
private HashMap<String, ICape> capes;
public CapeManager() {
this.capes = new HashMap<String, ICape>();
}
public static CapeManager getInstance() {
if (instance == null) {
instance = new CapeManager();
}
return instance;
}
public void addCape(ICape cape) {
if (!capes.containsValue(cape)) {
capes.put(cape.getName(), cape);
}
}
public void addCapes(Collection<ICape> capes) {
for (ICape c : capes) {
this.addCape(c);
}
}
public ICape getCape(String capeName) {
return capes.get(capeName);
}
public ICape newCape(String name) {
StaticCape cape = new StaticCape(name);
this.capes.put(name, cape);
return cape;
}
public ICape parse(String name, Object object) {
ICape cape = null;
if (object instanceof String || object instanceof URL) {
cape = parse(name, object.toString());
} else {
DevCapes.logger.error(String.format(
"Cape, %s, could not be parsed because it is not in an accepted format!",
object
));
}
return cape;
}
protected ICape parse(String name, String url) {
ICape cape = null;
try {
cape = new StaticCape(name, new URL(url));
} catch (MalformedURLException e) {
DevCapes.logger.error(
String.format("Are you crazy?? \"%s\" is not a valid URL!", url)
);
e.printStackTrace();
}
return cape;
}
}

View File

@ -0,0 +1,28 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.cape;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.util.ResourceLocation;
/**
* Any class implementing this will be requested to act as a cape.
*
* @author jadar
*/
public interface ICape {
public String getName();
public ITextureObject getTexture();
public ResourceLocation getLocation();
public void loadTexture(AbstractClientPlayer player);
public boolean isTextureLoaded(AbstractClientPlayer player);
}

View File

@ -0,0 +1,61 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.cape;
import java.net.URL;
import com.jadarstudios.developercapes.HDImageBuffer;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.renderer.ThreadDownloadImageData;
import net.minecraft.util.ResourceLocation;
/**
* Default Cape implementation
*
* @author jadar
*/
public class StaticCape extends AbstractCape {
public StaticCape(String name, URL url) {
this.setName(name);
this.setURL(url);
}
public StaticCape(String name) {
this(name, null);
}
@Override
public void loadTexture(AbstractClientPlayer player) {
ResourceLocation location = this.getLocation();
player.func_152121_a(MinecraftProfileTexture.Type.CAPE, location);
Minecraft.getMinecraft().renderEngine.loadTexture(location, this.getTexture());
}
@Override
public boolean isTextureLoaded(AbstractClientPlayer player) {
ResourceLocation cape = player.getLocationCape();
return cape != null;
}
public void setURL(URL url) {
if (url == null) {
this.texture = null;
return;
}
this.texture = new ThreadDownloadImageData(
null, url.toString(), null, new HDImageBuffer()
);
}
public void setName(String name) {
this.name = name;
this.location = new ResourceLocation("DevCapes/" + name);
}
}

View File

@ -0,0 +1,60 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.user;
import java.util.HashMap;
import java.util.Set;
import com.jadarstudios.developercapes.cape.ICape;
/**
* This represents a group of players that share a cape
*
* @author jadar
*/
public class Group {
protected HashMap<String, User> users;
protected ICape cape;
public final String name;
public Group(String name) {
this.users = new HashMap<String, User>();
this.name = name;
}
public void addUser(User user) {
if (!this.users.containsValue(user)) {
user.capes.add(this.cape);
this.users.put(user.userUUID, user);
}
}
public void addUsers(Set<User> users) {
for (User user : users) {
this.addUser(user);
}
}
public void removeUser(User user) {
if (this.users.containsValue(user)) {
this.users.remove(user);
user.capes.remove(this.cape);
}
}
public ICape getCape() {
return this.cape;
}
public void setCape(ICape cape) {
for (User user : this.users.values()) {
user.capes.remove(this.cape);
}
this.cape = cape;
}
}

View File

@ -0,0 +1,94 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.user;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.jadarstudios.developercapes.DevCapes;
import com.jadarstudios.developercapes.cape.CapeManager;
/**
* All groups have to be managed
*
* @author jadar
*/
public class GroupManager {
protected static GroupManager instance;
private HashMap<String, Group> groups;
public GroupManager() {
this.groups = new HashMap<String, Group>();
}
public static GroupManager getInstance() {
if (instance == null) {
instance = new GroupManager();
}
return instance;
}
public void addGroup(Group group) {
groups.put(group.name, group);
try {
UserManager.getInstance().addUsers(group.users.values());
CapeManager.getInstance().addCape(group.cape);
} catch (Exception e) {
e.printStackTrace();
}
}
public void addGroups(Collection<Group> groups) {
for (Group g : groups) {
GroupManager.getInstance().addGroup(g);
}
}
public Group getGroup(String capeName) {
return groups.get(capeName);
}
public Group newGroup(String name) {
if (this.getGroup(name) != null) {
return this.getGroup(name);
}
Group group = new Group(name);
return group;
}
public Group parse(String name, Map<String, Object> data) {
Group group = new Group(name);
Object usersObj = data.get("users");
Object capeUrlObj = data.get("capeUrl");
if (!(usersObj instanceof ArrayList) || !(capeUrlObj instanceof String)) {
DevCapes.logger.error(String.format(
"Group %s could not be parsed because it either is invalid or missing elements.",
name
));
return null;
}
ArrayList users = (ArrayList) usersObj;
String capeUrl = (String) capeUrlObj;
group.cape = CapeManager.getInstance().parse(name, capeUrl);
for (Object obj : users) {
User user = UserManager.getInstance().parse((String) obj, group.cape);
if (user != null) {
group.addUser(user);
}
}
return group;
}
}

View File

@ -0,0 +1,27 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.user;
import java.util.ArrayList;
import java.util.List;
import com.jadarstudios.developercapes.cape.ICape;
/**
* This player is getting their own cape
*
* @author jadar
*/
public class User {
public List<ICape> capes;
public final String userUUID;
public User(String userUUID) {
this.userUUID = userUUID;
this.capes = new ArrayList<ICape>();
}
}

View File

@ -0,0 +1,84 @@
/**
* DeveloperCapes by Jadar
* License: MIT License
* (https://raw.github.com/jadar/DeveloperCapes/master/LICENSE)
* version 4.0.0.x
*/
package com.jadarstudios.developercapes.user;
import java.util.Collection;
import java.util.HashMap;
import com.jadarstudios.developercapes.DevCapes;
import com.jadarstudios.developercapes.cape.CapeManager;
import com.jadarstudios.developercapes.cape.ICape;
/**
* Users can not be trusted to put capes on by themselves
*
* @author jadar
*/
public class UserManager {
protected static UserManager instance;
protected HashMap<String, User> users;
public UserManager() {
this.users = new HashMap<String, User>();
}
public static UserManager getInstance() {
if (instance == null) {
instance = new UserManager();
}
return instance;
}
public User getUser(String username) {
return this.users.get(username);
}
public void addUser(User user) throws NullPointerException {
if (user == null || user.userUUID == null || user.userUUID.isEmpty()) {
throw new NullPointerException("Cannot add a null user!");
}
this.users.put(user.userUUID, user);
CapeManager.getInstance().addCapes(user.capes);
}
public void addUsers(Collection<User> users) throws NullPointerException {
for (User u : users) {
this.addUser(u);
}
}
public User newUser(String username) {
User user = null;
if (this.users.containsKey(username)) {
user = this.getUser(username);
} else {
user = new User(username);
this.users.put(username, user);
}
return user;
}
public User parse(String user, Object cape) {
User userInstance = new User(user);
ICape capeInstance = (cape instanceof ICape)
? (ICape) cape
: CapeManager.getInstance().parse(user, cape.toString());
if (capeInstance != null) {
userInstance.capes.add(capeInstance);
} else {
DevCapes.logger.error(String.format("Error parsing cape, %s", cape.toString())
);
}
return userInstance;
}
}

View File

@ -0,0 +1,25 @@
package dev.tilera.capes;
import com.jadarstudios.developercapes.DevCapes;
import net.minecraftforge.common.MinecraftForge;
public class Capes {
private static boolean capesInitialized = false;
public static void initCapes() {
if (!capesInitialized) {
capesInitialized = true;
try {
DevCapes.getInstance().registerConfig(
"https://capes.tilera.xyz/devcapes.json"
);
MinecraftForge.EVENT_BUS.register(new RenderEventHandler());
} catch (Exception e) {
System.out.print("Cant load capes\n" + e);
}
}
}
}

View File

@ -0,0 +1,31 @@
package dev.tilera.capes;
import com.jadarstudios.developercapes.cape.ICape;
import com.jadarstudios.developercapes.user.User;
import com.jadarstudios.developercapes.user.UserManager;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraftforge.client.event.RenderPlayerEvent;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
public class RenderEventHandler {
@SubscribeEvent
public void renderPlayer(RenderPlayerEvent.Specials.Pre event) {
AbstractClientPlayer player = (AbstractClientPlayer) event.entityPlayer;
UserManager manager = UserManager.getInstance();
User user = manager.getUser(player.getUniqueID().toString());
if (user == null) {
player.func_152121_a(MinecraftProfileTexture.Type.CAPE, null);
return;
}
ICape cape = user.capes.get(0);
if (cape == null) {
player.func_152121_a(MinecraftProfileTexture.Type.CAPE, null);
return;
}
cape.loadTexture(player);
}
}