That should do the trick!

This commit is contained in:
flash 2024-07-12 15:48:06 +02:00
parent 552bd63c1a
commit 21a5d0062b
9 changed files with 129 additions and 102 deletions

View file

@ -0,0 +1,19 @@
package net.flashii.mcexts;
import com.mojang.authlib.yggdrasil.ProfileResult;
public class ProfileResultCache {
private static final long CACHE_TIMEOUT = 21600000;
public long readTime;
public ProfileResult value;
public ProfileResultCache(ProfileResult value) {
this.readTime = System.currentTimeMillis();
this.value = value;
}
public boolean needsRefresh() {
return readTime < System.currentTimeMillis() - CACHE_TIMEOUT;
}
}

View file

@ -4,7 +4,6 @@ import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;

View file

@ -0,0 +1,19 @@
package net.flashii.mcexts.mixin;
import net.minecraft.client.network.PlayerListEntry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(PlayerListEntry.class)
public abstract class PlayerListEntryMixin {
@ModifyVariable(
method = "texturesSupplier(Lcom/mojang/authlib/GameProfile;)Ljava/util/function/Supplier;",
at = @At("STORE"),
ordinal = 0
)
private static boolean texturesSupplier(boolean bl) {
// always enable BL
return true;
}
}

View file

@ -1,6 +1,5 @@
package net.flashii.mcexts.mixin; package net.flashii.mcexts.mixin;
import net.flashii.mcexts.Tools;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.PlayerListHud; import net.minecraft.client.gui.hud.PlayerListHud;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -17,8 +16,6 @@ public abstract class PlayerListHudMixin {
) )
) )
public boolean isInSinglePlayer(MinecraftClient client) { public boolean isInSinglePlayer(MinecraftClient client) {
Tools.Log.info("[FII MIXIN] Redirected isInSingleplayer call in PlayerListHud.render!!!");
// always enable BL // always enable BL
return true; return true;
} }

View file

@ -1,45 +0,0 @@
package net.flashii.mcexts.mixin;
import com.mojang.authlib.GameProfile;
import java.util.concurrent.CompletableFuture;
import net.minecraft.client.texture.PlayerSkinProvider;
import net.minecraft.client.util.SkinTextures;
import net.flashii.mcexts.Tools;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerSkinProvider.class)
public abstract class PlayerSkinProviderMixin {
@Inject(
method = "fetchSkinTextures(Lcom/mojang/authlib/GameProfile;)Ljava/util/concurrent/CompletableFuture;",
at = @At("RETURN"),
cancellable = true
)
private void fetchSkinTextures(GameProfile profile, CallbackInfoReturnable<CompletableFuture<SkinTextures>> cir) {
Tools.Log.info("[FII MIXIN] Intercepted PlayerSkinProvider.fetchSkinTextures!!!");
CompletableFuture<SkinTextures> future = cir.getReturnValue();
cir.setReturnValue(future.thenApply(st -> {
Tools.Log.info(
"[FII MIXIN] future texture:{} textureUrl:{} capeTexture:{} elytraTexture:{} model:{} secure:{}",
st.texture(),
st.textureUrl(),
st.capeTexture(),
st.elytraTexture(),
st.model(),
st.secure()
);
return new SkinTextures(
st.texture(),
st.textureUrl(),
st.capeTexture(),
st.elytraTexture(),
st.model(),
st.secure()
);
}));
cir.cancel();
}
}

View file

@ -2,7 +2,6 @@ package net.flashii.mcexts.mixin;
import com.mojang.authlib.yggdrasil.TextureUrlChecker; import com.mojang.authlib.yggdrasil.TextureUrlChecker;
import net.flashii.mcexts.URLs; import net.flashii.mcexts.URLs;
import net.flashii.mcexts.Tools;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -17,8 +16,6 @@ public abstract class TextureUrlCheckerMixin {
remap = false remap = false
) )
private static void isAllowedTextureDomain(String url, CallbackInfoReturnable<Boolean> cir) { private static void isAllowedTextureDomain(String url, CallbackInfoReturnable<Boolean> cir) {
Tools.Log.info("[FII MIXIN] Intercepted TextureUrlChecker.isAllowedTextureDomain!!!");
if(url == null || url.startsWith(URLs.getTexturesHostPrefix())) { if(url == null || url.startsWith(URLs.getTexturesHostPrefix())) {
cir.setReturnValue(true); cir.setReturnValue(true);
cir.cancel(); cir.cancel();

View file

@ -14,8 +14,10 @@ public abstract class YggdrasilEnvironmentMixin {
at = @At( at = @At(
value = "NEW", value = "NEW",
target = "com/mojang/authlib/Environment", target = "com/mojang/authlib/Environment",
ordinal = 0 ordinal = 0,
) remap = false
),
remap = false
) )
private Environment init(String sessionHost, String servicesHost, String name) { private Environment init(String sessionHost, String servicesHost, String name) {
return new Environment(URLs.getSessionHost(), servicesHost, name); return new Environment(URLs.getSessionHost(), servicesHost, name);

View file

@ -1,23 +1,82 @@
package net.flashii.mcexts.mixin; package net.flashii.mcexts.mixin;
import com.google.common.collect.Iterables;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.authlib.SignatureState; import com.mojang.authlib.SignatureState;
import com.mojang.authlib.minecraft.MinecraftProfileTextures; import com.mojang.authlib.minecraft.client.ObjectMapper;
import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.Property;
import com.mojang.authlib.yggdrasil.ProfileResult; import com.mojang.authlib.yggdrasil.ProfileResult;
import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService;
import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse;
import com.mojang.util.UndashedUuid;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import net.flashii.mcexts.ProfileResultCache;
import net.minecraft.client.util.SkinTextures;
import net.flashii.mcexts.Tools; import net.flashii.mcexts.Tools;
import net.flashii.mcexts.URLs;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(YggdrasilMinecraftSessionService.class) @Mixin(YggdrasilMinecraftSessionService.class)
public abstract class YggdrasilMinecraftSessionServiceMixin { public abstract class YggdrasilMinecraftSessionServiceMixin {
private static ObjectMapper objectMapper = ObjectMapper.create();
private static HashMap<UUID, ProfileResultCache> profileCache = new HashMap<>();
private static ProfileResult getProfileFromMince(UUID profileId, boolean allowCache) {
if(allowCache && profileCache.containsKey(profileId)) {
ProfileResultCache cachedProfile = profileCache.get(profileId);
if(!cachedProfile.needsRefresh())
return cachedProfile.value;
Tools.Log.info("[FII MIXIN] Cache expired!!!!!!!");
} else {
Tools.Log.info("[FII MIXIN] Forcing new fetch!!!!!!!");
}
ProfileResult profileResult = null;
try {
// this should probably have caching idk at what frequency this will get called
URI url;
try {
url = new URI(String.format("%s/session/minecraft/profile/%s", URLs.getSessionHost(), UndashedUuid.toString(profileId)));
} catch(URISyntaxException ex) {
Tools.Log.info("[FII MIXIN] INCORRECTLY FORMATTED PROFILE URL!!!!!!!!!!");
return profileResult;
}
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(url).GET().build();
HttpResponse<String> response;
try {
response = client.send(request, HttpResponse.BodyHandlers.ofString());
} catch(IOException | InterruptedException ex) {
Tools.Log.info("[FII MIXIN] FAILED TO SEND PROFILE REQUEST!!!!!!!!!!");
return profileResult;
}
if(response.statusCode() != 200) {
Tools.Log.info("[FII MIXIN] NON-200 PROFILE RESPONSE CODE!!!!!!!!!!");
return profileResult;
}
MinecraftProfilePropertiesResponse profileResponse = objectMapper.readValue(response.body(), MinecraftProfilePropertiesResponse.class);
if(profileResponse != null)
profileResult = new ProfileResult(profileResponse.toProfile());
} finally {
profileCache.put(profileId, new ProfileResultCache(profileResult));
}
return profileResult;
}
@Inject( @Inject(
method = "getPackedTextures(Lcom/mojang/authlib/GameProfile;)Lcom/mojang/authlib/properties/Property;", method = "getPackedTextures(Lcom/mojang/authlib/GameProfile;)Lcom/mojang/authlib/properties/Property;",
at = @At("RETURN"), at = @At("RETURN"),
@ -25,27 +84,22 @@ public abstract class YggdrasilMinecraftSessionServiceMixin {
remap = false remap = false
) )
private void getPackedTextures(GameProfile profile, CallbackInfoReturnable<Property> cir) { private void getPackedTextures(GameProfile profile, CallbackInfoReturnable<Property> cir) {
Tools.Log.info("[FII MIXIN] Intercepted YggdrasilMinecraftSessionService.getPackedTextures!!!"); boolean replace = false;
Tools.Log.info("[FII MIXIN] {}", profile);
Property prop = cir.getReturnValue(); Property prop = cir.getReturnValue();
if(prop == null) if(prop == null) {
Tools.Log.info("[FII MIXIN] prop is null"); ProfileResult result = getProfileFromMince(profile.getId(), true);
else if(result == null) {
Tools.Log.info("[FII MIXIN] name:{} value:{} signature:{}", prop.name(), prop.value(), prop.signature()); Tools.Log.info("[FII MIXIN] PROFILE RESULT IS NULL!!!!!!!!");
} } else {
replace = true;
prop = (Property)Iterables.getFirst(result.profile().getProperties().get("textures"), (Object)null);
}
}
@Inject( if(replace) {
method = "unpackTextures(Lcom/mojang/authlib/properties/Property;)Lcom/mojang/authlib/minecraft/MinecraftProfileTextures;", cir.setReturnValue(prop);
at = @At("RETURN"), cir.cancel();
cancellable = true, }
remap = false
)
private void unpackTextures(Property packedTextures, CallbackInfoReturnable<MinecraftProfileTextures> cir) {
Tools.Log.info("[FII MIXIN] Intercepted YggdrasilMinecraftSessionService.unpackTextures!!!");
MinecraftProfileTextures textures = cir.getReturnValue();
Tools.Log.info("[FII MIXIN] skin:{} cape:{} elytra:{} signature:{}", textures.skin(), textures.cape(), textures.elytra(), textures.signatureState());
} }
@Inject( @Inject(
@ -54,9 +108,7 @@ public abstract class YggdrasilMinecraftSessionServiceMixin {
cancellable = true, cancellable = true,
remap = false remap = false
) )
private void getSecurePropertyValue(Property property, CallbackInfoReturnable<String> cir) { public void getSecurePropertyValue(Property property, CallbackInfoReturnable<String> cir) {
Tools.Log.info("[FII MIXIN] Intercepted YggdrasilMinecraftSessionService.getSecurePropertyValue!!!");
cir.setReturnValue(property.value()); cir.setReturnValue(property.value());
cir.cancel(); cir.cancel();
} }
@ -68,34 +120,21 @@ public abstract class YggdrasilMinecraftSessionServiceMixin {
remap = false remap = false
) )
private void getPropertySignatureState(Property property, CallbackInfoReturnable<SignatureState> cir) { private void getPropertySignatureState(Property property, CallbackInfoReturnable<SignatureState> cir) {
Tools.Log.info("[FII MIXIN] Intercepted YggdrasilMinecraftSessionService.getPropertySignatureState!!!");
cir.setReturnValue(SignatureState.SIGNED); cir.setReturnValue(SignatureState.SIGNED);
cir.cancel(); cir.cancel();
} }
@Inject( @Inject(
method = "fetchProfileUncached(Ljava/util/UUID;Z)Lcom/mojang/authlib/yggdrasil/ProfileResult;", method = "fetchProfile(Ljava/util/UUID;Z)Lcom/mojang/authlib/yggdrasil/ProfileResult;",
at = @At("RETURN"), at = @At("HEAD"),
cancellable = true, cancellable = true,
remap = false remap = false
) )
private void fetchProfileUncached(UUID profileId, boolean requireSecure, CallbackInfoReturnable<ProfileResult> cir) { public void fetchProfile(UUID profileId, boolean requireSecure, CallbackInfoReturnable<ProfileResult> cir) {
Tools.Log.info("[FII MIXIN] Intercepted YggdrasilMinecraftSessionService.fetchProfileUncached!!!"); ProfileResult result = getProfileFromMince(profileId, !requireSecure);
Tools.Log.info("[FII MIXIN] {}", cir.getReturnValue().profile()); if(result != null) {
} cir.setReturnValue(result);
cir.cancel();
@ModifyArg( }
method = "fetchProfile",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService;fetchProfileUncached(Ljava/util/UUID;Z)Lcom/mojang/authlib/yggdrasil/ProfileResult;"
),
index = 1,
remap = false
)
private boolean modifyFetchProfileUncachedArg(boolean requireSecure) {
Tools.Log.info("[FII MIXIN] Intercepted requireSecure argument for YggdrasilMinecraftSessionService.fetchProfileUncached in fetchProfile!!!");
return false;
} }
} }

View file

@ -3,7 +3,7 @@
"package": "net.flashii.mcexts.mixin", "package": "net.flashii.mcexts.mixin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"PlayerSkinProviderMixin", "PlayerListEntryMixin",
"PlayerListHudMixin", "PlayerListHudMixin",
"TextureUrlCheckerMixin", "TextureUrlCheckerMixin",
"YggdrasilEnvironmentMixin", "YggdrasilEnvironmentMixin",