async head texture lookup

This commit is contained in:
IzzelAliz 2020-05-17 11:32:50 +08:00
parent de7f78110b
commit ad1da3ce18
6 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,96 @@
package io.izzel.arclight.mixin.core.tileentity;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mojang.authlib.GameProfile;
import com.mysql.jdbc.StringUtils;
import io.izzel.arclight.bridge.server.MinecraftServerBridge;
import io.izzel.arclight.mod.util.ArclightHeadLoader;
import net.minecraft.tileentity.SkullTileEntity;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@Mixin(SkullTileEntity.class)
public abstract class SkullTileEntityMixin extends TileEntityMixin {
// @formatter:off
@Shadow public GameProfile playerProfile;
// @formatter:on
private static ExecutorService executor = Executors.newFixedThreadPool(3,
new ThreadFactoryBuilder()
.setNameFormat("Head Conversion Thread - %1$d")
.build()
);
private static LoadingCache<String, GameProfile> skinCache = CacheBuilder.newBuilder().maximumSize(5000L).expireAfterAccess(60L, TimeUnit.MINUTES).build(new ArclightHeadLoader());
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
private void updatePlayerProfile() {
GameProfile profile = this.playerProfile;
b(profile, input -> {
playerProfile = input;
markDirty();
return false;
}, false);
}
@SuppressWarnings({"UnusedReturnValue", "ConstantConditions"})
private static Future<GameProfile> b(GameProfile gameprofile, Predicate<GameProfile> callback, boolean sync) {
if (gameprofile != null && !StringUtils.isNullOrEmpty(gameprofile.getName())) {
if (gameprofile.isComplete() && gameprofile.getProperties().containsKey("textures")) {
callback.apply(gameprofile);
} else if (Bukkit.getServer() == null || ((CraftServer) Bukkit.getServer()).getServer() == null) {
callback.apply(gameprofile);
} else {
GameProfile profile = skinCache.getIfPresent(gameprofile.getName().toLowerCase(Locale.ROOT));
if (profile != null && Iterables.getFirst((profile.getProperties()).get("textures"), null) != null) {
callback.apply(profile);
return Futures.immediateFuture(profile);
}
Callable<GameProfile> callable = () -> {
GameProfile profile1 = skinCache.getUnchecked(gameprofile.getName().toLowerCase(Locale.ROOT));
((MinecraftServerBridge) ((CraftServer) Bukkit.getServer()).getServer()).bridge$queuedProcess(() -> {
if (profile1 == null) {
callback.apply(gameprofile);
} else {
callback.apply(profile1);
}
});
return profile1;
};
if (sync) {
try {
return Futures.immediateFuture(callable.call());
} catch (Exception ex) {
Throwables.throwIfUnchecked(ex);
throw new RuntimeException(ex);
}
}
return executor.submit(callable);
}
} else {
callback.apply(gameprofile);
}
return Futures.immediateFuture(gameprofile);
}
}

View File

@ -29,6 +29,7 @@ public abstract class TileEntityMixin implements TileEntityBridge {
@Shadow @Nullable protected World world; @Shadow @Nullable protected World world;
@Shadow protected BlockPos pos; @Shadow protected BlockPos pos;
@Shadow public abstract BlockState getBlockState(); @Shadow public abstract BlockState getBlockState();
@Shadow public abstract void markDirty();
// @formatter:on // @formatter:on
@Inject(method = "read", at = @At("RETURN")) @Inject(method = "read", at = @At("RETURN"))

View File

@ -82,6 +82,16 @@ public class ArclightMixinPlugin implements IMixinConfigPlugin {
new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "calculateBoundingBox", "(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;II)Lnet/minecraft/util/math/AxisAlignedBB;", null, null) new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "calculateBoundingBox", "(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;II)Lnet/minecraft/util/math/AxisAlignedBB;", null, null)
) )
)) ))
.put("net.minecraft.tileentity.SkullTileEntity",
Maps.immutableEntry(
ImmutableList.of(
new FieldNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "executor", "Ljava/util/concurrent/ExecutorService;", null, null),
new FieldNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "skinCache", "Lcom/google/common/cache/LoadingCache;", null, null)
),
ImmutableList.of(
new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "b", "(Lcom/mojang/authlib/GameProfile;Lcom/google/common/base/Predicate;Z)Ljava/util/concurrent/Future;", null, null)
)
))
.build(); .build();
private final Set<String> modifyConstructor = ImmutableSet.<String>builder() private final Set<String> modifyConstructor = ImmutableSet.<String>builder()

View File

@ -0,0 +1,46 @@
package io.izzel.arclight.mod.util;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.Iterables;
import com.mojang.authlib.Agent;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.ProfileLookupCallback;
import com.mojang.authlib.properties.Property;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.SkullTileEntity;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
import java.util.UUID;
public class ArclightHeadLoader extends CacheLoader<String, GameProfile> {
@Override
public GameProfile load(String key) {
GameProfile[] profiles = {null};
ProfileLookupCallback gameProfileLookup = new ProfileLookupCallback() {
@Override
public void onProfileLookupSucceeded(GameProfile gp) {
profiles[0] = gp;
}
@Override
public void onProfileLookupFailed(GameProfile gp, Exception excptn) {
profiles[0] = gp;
}
};
((CraftServer) Bukkit.getServer()).getServer().getGameProfileRepository().findProfilesByNames(new String[]{key}, Agent.MINECRAFT, gameProfileLookup);
GameProfile profile = profiles[0];
if (profile == null) {
UUID uuid = PlayerEntity.getUUID(new GameProfile(null, key));
profile = new GameProfile(uuid, key);
gameProfileLookup.onProfileLookupSucceeded(profile);
} else {
Property property = Iterables.getFirst((profile.getProperties()).get("textures"), null);
if (property == null) {
profile = SkullTileEntity.sessionService.fillProfileProperties(profile, true);
}
}
return profile;
}
}

View File

@ -16,6 +16,7 @@ public net.minecraft.util.math.shapes.IDoubleListMerger
public net.minecraft.util.math.shapes.IndirectMerger <init>(Lit/unimi/dsi/fastutil/doubles/DoubleList;Lit/unimi/dsi/fastutil/doubles/DoubleList;ZZ)V public net.minecraft.util.math.shapes.IndirectMerger <init>(Lit/unimi/dsi/fastutil/doubles/DoubleList;Lit/unimi/dsi/fastutil/doubles/DoubleList;ZZ)V
public net.minecraft.util.math.shapes.DoubleCubeMergingList <init>(II)V public net.minecraft.util.math.shapes.DoubleCubeMergingList <init>(II)V
public net.minecraft.block.ComposterBlock$EmptyInventory public net.minecraft.block.ComposterBlock$EmptyInventory
public net.minecraft.tileentity.SkullTileEntity field_184299_k #sessionService
# Bukkit # Bukkit
public net.minecraft.entity.player.PlayerEntity func_190531_bD()I public net.minecraft.entity.player.PlayerEntity func_190531_bD()I
public net.minecraft.entity.item.ItemFrameEntity func_174859_a(Lnet/minecraft/util/Direction;)V public net.minecraft.entity.item.ItemFrameEntity func_174859_a(Lnet/minecraft/util/Direction;)V

View File

@ -339,6 +339,7 @@
"tileentity.LockableTileEntityMixin", "tileentity.LockableTileEntityMixin",
"tileentity.ShulkerBoxTileEntityMixin", "tileentity.ShulkerBoxTileEntityMixin",
"tileentity.SignTileEntityMixin", "tileentity.SignTileEntityMixin",
"tileentity.SkullTileEntityMixin",
"tileentity.TileEntityMixin", "tileentity.TileEntityMixin",
"util.BootstrapMixin", "util.BootstrapMixin",
"util.DamageSourceMixin", "util.DamageSourceMixin",