Jump to content

In game skin changer only works in dev environment


Dijkstra

Recommended Posts

I am making a mod that allows the user to change there skin game, it far from complete, but bubbled it down to just setting a skin me and sister to test on my server for performance and we both ended up with are skin set on minecraft.net, but in my dev  environment my skin does change to the one i set the set of code i am test is

 

 

package dijkstra.wardrobe.main;
public class testReflections{
public static ResourceLocation oldSkin;
public static AbstractClientPlayer player = Minecraft.getMinecraft().thePlayer;
public static void load(){
	Class Skin = AbstractClientPlayer.class;
	try {
		Field locationSkin = AbstractClientPlayer.class.getDeclaredField("locationSkin");
		locationSkin.setAccessible(true);
		locationSkin.set(Minecraft.getMinecraft().thePlayer, setSkin(Players.valueOf(player.getDisplayName())));
	}
	catch (Exception e){
		e.printStackTrace();
	}
}
private static ResourceLocation setSkin(Players player){
	switch(player){
	case Dijkstra:
		return new ResourceLocation("textures/players/Dijkstra.png");
	case Pegasus:
		return new ResourceLocation("textures/players/Pegasus.png");
	default:
		return null;
	}
}
private enum Players{
	Dijkstra,
	Pegasus
}

}

 

 

events

 

package dijkstra.wardrobe.main;

public class eventHandler{
public static boolean changed = true;
    @SubscribeEvent
    public void renderTick(TickEvent.RenderTickEvent event)
    {
        Minecraft mc = Minecraft.getMinecraft();

        if(mc.theWorld != null)
        {
            if(event.phase == TickEvent.Phase.START)
            {
            	if(changed){
            		testReflections.load();
            		changed = false;
            	}
            	
            }
        }
    }
    
    @SubscribeEvent
public void PlayerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event){
    	changed = true;
    }
}

 

main file

 

@EventHandler
public static void PreLoad(FMLPreInitializationEvent PreEvent){
	FMLCommonHandler.instance().bus().register(new eventHandler());
	proxy.registerRenderInfo();
}

 

 

Think that should be all you need if need more of the mod just ask but it is getting quite large

Link to comment
Share on other sites

In the obfuscated (non-development) environment, there's no field called

locationSkin

; instead it has the SRG name

field_110312_d

.

 

FML's

ObfuscationReflectionHelper#setPrivateValue

allows you to pass both the deobfuscated (MCP) and obfuscated (SRG) names of the field to set the value of. Either use it directly or adapt the logic to your class.

 

Make sure you only reference client-only classes like

Minecraft

and

AbstractClientPlayer

from client-side code (i.e. only register your event handler in your client proxy).

 

Edit: The SRG name of

AbstractClientPlayer#locationSkin

in 1.7.10 is actually

field_110312_d

.

field_178865_e

is the SRG name of

NetworkPlayerInfo#locationSkin

field in 1.8.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Ok so done use fml method still works fine in the dev environment but now crashes out of the dev environment

 

crash report out of dev

 

cpw.mods.fml.relauncher.ReflectionHelper$UnableToAccessFieldException: cpw.mods.fml.relauncher.ReflectionHelper$UnableToFindFieldException: java.lang.NoSuchFieldException: locationSkin

at cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(ReflectionHelper.java:147)

at cpw.mods.fml.common.ObfuscationReflectionHelper.setPrivateValue(ObfuscationReflectionHelper.java:91)

at dijkstra.wardrobe.main.testReflections.load(testReflections.java:15)

at dijkstra.wardrobe.main.eventHandler.renderTick(eventHandler.java:23)

at cpw.mods.fml.common.eventhandler.ASMEventHandler_7_eventHandler_renderTick_RenderTickEvent.invoke(.dynamic)

at cpw.mods.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:54)

at cpw.mods.fml.common.eventhandler.EventBus.post(EventBus.java:138)

at cpw.mods.fml.common.FMLCommonHandler.onRenderTickStart(FMLCommonHandler.java:335)

at net.minecraft.client.Minecraft.func_71411_J(Minecraft.java:999)

at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:898)

at net.minecraft.client.main.Main.main(SourceFile:148)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:483)

at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)

at net.minecraft.launchwrapper.Launch.main(Launch.java:28)

Caused by: cpw.mods.fml.relauncher.ReflectionHelper$UnableToFindFieldException: java.lang.NoSuchFieldException: locationSkin

at cpw.mods.fml.relauncher.ReflectionHelper.findField(ReflectionHelper.java:94)

at cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(ReflectionHelper.java:143)

... 16 more

Caused by: java.lang.NoSuchFieldException: locationSkin

at java.lang.Class.getDeclaredField(Class.java:2062)

at cpw.mods.fml.relauncher.ReflectionHelper.findField(ReflectionHelper.java:85)

... 17 more

 

 

 

Link to comment
Share on other sites

To answer the question in your previous post, only use reflection when you can't use a normal method call/field access. Examples of this include accessing non-public methods/fields or methods/fields with a dynamic name/argument list and instantiating a class that's only known at runtime (i.e. you have a

Class

object you want to create an instance of).

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Ok so done use fml method still works fine in the dev environment but now crashes out of the dev environment

 

crash report out of dev

 

cpw.mods.fml.relauncher.ReflectionHelper$UnableToAccessFieldException: cpw.mods.fml.relauncher.ReflectionHelper$UnableToFindFieldException: java.lang.NoSuchFieldException: locationSkin

at cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(ReflectionHelper.java:147)

at cpw.mods.fml.common.ObfuscationReflectionHelper.setPrivateValue(ObfuscationReflectionHelper.java:91)

at dijkstra.wardrobe.main.testReflections.load(testReflections.java:15)

at dijkstra.wardrobe.main.eventHandler.renderTick(eventHandler.java:23)

at cpw.mods.fml.common.eventhandler.ASMEventHandler_7_eventHandler_renderTick_RenderTickEvent.invoke(.dynamic)

at cpw.mods.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:54)

at cpw.mods.fml.common.eventhandler.EventBus.post(EventBus.java:138)

at cpw.mods.fml.common.FMLCommonHandler.onRenderTickStart(FMLCommonHandler.java:335)

at net.minecraft.client.Minecraft.func_71411_J(Minecraft.java:999)

at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:898)

at net.minecraft.client.main.Main.main(SourceFile:148)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:483)

at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)

at net.minecraft.launchwrapper.Launch.main(Launch.java:28)

Caused by: cpw.mods.fml.relauncher.ReflectionHelper$UnableToFindFieldException: java.lang.NoSuchFieldException: locationSkin

at cpw.mods.fml.relauncher.ReflectionHelper.findField(ReflectionHelper.java:94)

at cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(ReflectionHelper.java:143)

... 16 more

Caused by: java.lang.NoSuchFieldException: locationSkin

at java.lang.Class.getDeclaredField(Class.java:2062)

at cpw.mods.fml.relauncher.ReflectionHelper.findField(ReflectionHelper.java:85)

... 17 more

 

 

 

This is the same error as before: you're only using the deobfucated (MCP) name, not the obfuscated (SRG) name. You need to pass both names to

ObfuscationReflectionHelper.getPrivateValue

(and other methods in the same class that take a

String

array/vararg of field names).

 

You can find the SRG name of a method/field in the MCP mapping CSVs, which can be found in your Gradle cache. For recent 1.7.10 versions of Forge, the CSVs are in  ~/.gradle/caches/minecraft/net/minecraftforge/forge/<forge_version>/unpacked/conf (replace ~ with %USERPROFILE% on Windows). You can also download the mappings from the MCPBot Website.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

public static void load(){
	AbstractClientPlayer player = Minecraft.getMinecraft().thePlayer;
	ResourceLocation skin = new ResourceLocation("textures/players/"+player.getDisplayName()+".png");
	ObfuscationReflectionHelper.setPrivateValue(AbstractClientPlayer.class, player, skin, new String[]{"locationSkin","field_178865_e"});

}

 

this is code i am using, clearly i am doing something but can not work it out  i have passed in both the dev name and real, still works fine in dev but not out of dev

Link to comment
Share on other sites

Ah, I gave you the SRG name of 1.8's

NetworkPlayerInfo#locationSkin

field instead of 1.7.10's

AbstractClientPlayer#locationSkin

field. The SRG name you want is actually

field_110312_d

.

 

In future you should include the Minecraft version in the title so people know which version you're working with.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Skins are downloaded and applied to players asynchronously, so you can't immediately replace the player's skin with your custom skin.

 

When an

AbstractClientPlayer

is instantiated, it calls

SkinManager#func_152790_a

. This downloads the the name of the player's skin and cape textures from Mojang's session servers and calls

SkinManager#func_152789_a

for each one. This downloads the texture in a separate thread (if it hasn't already been downloaded) and then calls

SkinManager.SkinAvailableCallback#func_152121_a

(implemented by

AbstractClientPlayer

) on the next tick to store the

ResourceLocation

of the texture in the appropriate field of

AbstractClientPlayer

.

 

I'd recommend subscribing to

EntityJoinWorldEvent

(only on the client side) and checking if the entity is an

AbstractClientPlayer

. If it is, call

SkinManager#func_152790_a

with your own implementation of

SkinManager.SkinAvailableCallback#func_152121_a

that that the

Type

is

Type.SKIN

and then sets the player's

locationSkin

field.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

  • 4 weeks later...

Sorry i have not got back sooner, but I have be busy with more important stuff.

 

 

I used to get the skin manager instance from the Minecraft class

 

SkinManager sm = Minecraft.getMinecraft().func_152342_ad();

 

so that i can call

 

SkinCallback sc = new SkinCallback(); // my class that implements SkinAvailableCallback 
sm.func_152790_a(GameProfile, sc, false);

 

but i am sure where to get the game profile class or the what to set boolean to

Link to comment
Share on other sites

Use

EntityPlayer#getGameProfile

to get a player's

GameProfile

.

 

The

boolean

is whether the downloaded texture names need to be securely signed.

AbstractClientPlayer

passes

true

, you probably should too.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I have subscribed to both PlayerLoggedInEvent and the EntityJoinWorldEvent, but i have a problem the EntityJoinWorldEvent is not trigger by a player and the PlayerLoggedInEvent gives me an EntityPlayer and not an abstract client player and i can not cast the  EntityPlayer to an abstract client player

Link to comment
Share on other sites

I have subscribed to both PlayerLoggedInEvent and the EntityJoinWorldEvent, but i have a problem the EntityJoinWorldEvent is not trigger by a player and the PlayerLoggedInEvent gives me an EntityPlayer and not an abstract client player and i can not cast the  EntityPlayer to an abstract client player

 

Wrong. EntityJoinWorldEvent is triggered by all entities joining the world, hence the name. Subscribe to the EntityJoinWorldEvent, check the instance of the AbstractClientPlayer against the event.entity, and then cast and do whatever you need. Remember, changing the skin with reflection during the EntityJoinWorldEvent will result in a NullPointerException (if you are changing NetworkPlayerInfo.locationSkin), so you will need to create a delayed runnable and schedule it to run on the main thread. Be sure to use ObfuscationReflectionHelper with SRG names.

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.