mirror of
https://github.com/Suiranoil/SkinRestorer.git
synced 2026-01-16 04:42:12 +00:00
Let fake players have skin
This commit is contained in:
@@ -16,6 +16,7 @@ repositories {
|
|||||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
// for more information about repositories.
|
// for more information about repositories.
|
||||||
|
maven { url = "https://masa.dy.fi/maven" }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -26,6 +27,7 @@ dependencies {
|
|||||||
|
|
||||||
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||||
// You may need to force-disable transitiveness on them.
|
// You may need to force-disable transitiveness on them.
|
||||||
|
modImplementation "carpet:fabric-carpet:${project.carpet_branch}-${project.carpet_core_version}"
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
|||||||
@@ -9,3 +9,6 @@ loader_version=0.14.7
|
|||||||
mod_version=1.1.0
|
mod_version=1.1.0
|
||||||
maven_group=net.lionarius
|
maven_group=net.lionarius
|
||||||
archives_base_name=skin-restorer
|
archives_base_name=skin-restorer
|
||||||
|
# Fabric Carpet
|
||||||
|
carpet_branch=1.19
|
||||||
|
carpet_core_version=1.4.79+v220607
|
||||||
|
|||||||
@@ -1,12 +1,35 @@
|
|||||||
package net.lionarius.skinrestorer;
|
package net.lionarius.skinrestorer;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import net.fabricmc.api.DedicatedServerModInitializer;
|
import net.fabricmc.api.DedicatedServerModInitializer;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.network.packet.s2c.play.*;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.util.math.GlobalPos;
|
||||||
|
import net.minecraft.world.biome.source.BiomeAccess;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SkinRestorer implements DedicatedServerModInitializer {
|
public class SkinRestorer implements DedicatedServerModInitializer {
|
||||||
|
|
||||||
private static SkinStorage skinStorage;
|
private static SkinStorage skinStorage;
|
||||||
|
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger("SkinRestorer");
|
||||||
|
|
||||||
public static SkinStorage getSkinStorage() {
|
public static SkinStorage getSkinStorage() {
|
||||||
return skinStorage;
|
return skinStorage;
|
||||||
}
|
}
|
||||||
@@ -15,4 +38,99 @@ public class SkinRestorer implements DedicatedServerModInitializer {
|
|||||||
public void onInitializeServer() {
|
public void onInitializeServer() {
|
||||||
skinStorage = new SkinStorage(new SkinIO(FabricLoader.getInstance().getConfigDir().resolve("skinrestorer")));
|
skinStorage = new SkinStorage(new SkinIO(FabricLoader.getInstance().getConfigDir().resolve("skinrestorer")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CompletableFuture<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>> setSkinAsync(MinecraftServer server, Collection<GameProfile> targets, Supplier<Property> skinSupplier) {
|
||||||
|
return CompletableFuture.<Pair<Property, Collection<GameProfile>>>supplyAsync(() -> {
|
||||||
|
HashSet<GameProfile> acceptedProfiles = new HashSet<>();
|
||||||
|
Property skin = skinSupplier.get();
|
||||||
|
if (skin == null) {
|
||||||
|
SkinRestorer.LOGGER.error("Cannot get the skin for {}", targets.stream().findFirst().orElseThrow());
|
||||||
|
return Pair.of(null, Collections.emptySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (GameProfile profile : targets) {
|
||||||
|
SkinRestorer.getSkinStorage().setSkin(profile.getId(), skin);
|
||||||
|
acceptedProfiles.add(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair.of(skin, acceptedProfiles);
|
||||||
|
}).<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>>thenApplyAsync(pair -> {
|
||||||
|
Property skin = pair.left();
|
||||||
|
if (skin == null) {
|
||||||
|
return Pair.of(Collections.emptySet(), Collections.emptySet());
|
||||||
|
}
|
||||||
|
Collection<GameProfile> acceptedProfiles = pair.right();
|
||||||
|
HashSet<ServerPlayerEntity> acceptedPlayers = new HashSet<>();
|
||||||
|
JsonObject newSkinJson = gson.fromJson(new String(Base64.getDecoder().decode(skin.getValue()), StandardCharsets.UTF_8), JsonObject.class);
|
||||||
|
newSkinJson.remove("timestamp");
|
||||||
|
for (GameProfile profile : acceptedProfiles) {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(profile.getId());
|
||||||
|
if (player == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arePropertiesEquals(newSkinJson, player.getGameProfile())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyRestoredSkin(player, skin);
|
||||||
|
for (PlayerEntity observer : player.world.getPlayers()) {
|
||||||
|
ServerPlayerEntity observer1 = (ServerPlayerEntity) observer;
|
||||||
|
observer1.networkHandler.sendPacket(new PlayerListS2CPacket(PlayerListS2CPacket.Action.REMOVE_PLAYER, player));
|
||||||
|
observer1.networkHandler.sendPacket(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, player)); // refresh the player information
|
||||||
|
if (player != observer1 && observer1.canSee(player)) {
|
||||||
|
observer1.networkHandler.sendPacket(new EntitiesDestroyS2CPacket(player.getId()));
|
||||||
|
observer1.networkHandler.sendPacket(new PlayerSpawnS2CPacket(player));
|
||||||
|
observer1.networkHandler.sendPacket(new EntityTrackerUpdateS2CPacket(player.getId(), player.getDataTracker(), true));
|
||||||
|
observer1.networkHandler.sendPacket(new EntityPositionS2CPacket(player));
|
||||||
|
} else if (player == observer1) {
|
||||||
|
observer1.networkHandler.sendPacket(new PlayerRespawnS2CPacket(
|
||||||
|
observer1.world.getDimensionKey(),
|
||||||
|
observer1.world.getRegistryKey(),
|
||||||
|
BiomeAccess.hashSeed(observer1.getWorld().getSeed()),
|
||||||
|
observer1.interactionManager.getGameMode(),
|
||||||
|
observer1.interactionManager.getPreviousGameMode(),
|
||||||
|
observer1.getWorld().isDebugWorld(),
|
||||||
|
observer1.getWorld().isFlat(),
|
||||||
|
true,
|
||||||
|
Optional.of(GlobalPos.create(observer1.getWorld().getRegistryKey(), observer1.getBlockPos()))
|
||||||
|
));
|
||||||
|
observer1.requestTeleport(observer1.getX(), observer1.getY(), observer1.getZ());
|
||||||
|
observer1.networkHandler.sendPacket(new UpdateSelectedSlotS2CPacket(observer1.getInventory().selectedSlot));
|
||||||
|
observer1.sendAbilitiesUpdate();
|
||||||
|
observer1.playerScreenHandler.updateToClient();
|
||||||
|
for (StatusEffectInstance instance : observer1.getStatusEffects()) {
|
||||||
|
observer1.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(observer1.getId(), instance));
|
||||||
|
}
|
||||||
|
observer1.networkHandler.sendPacket(new EntityTrackerUpdateS2CPacket(player.getId(), player.getDataTracker(), true));
|
||||||
|
observer1.networkHandler.sendPacket(new ExperienceBarUpdateS2CPacket(player.experienceProgress, player.totalExperience, player.experienceLevel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acceptedPlayers.add(player);
|
||||||
|
}
|
||||||
|
return Pair.of(acceptedPlayers, acceptedProfiles);
|
||||||
|
}, server).orTimeout(10, TimeUnit.SECONDS).exceptionally(e -> Pair.of(Collections.emptySet(), Collections.emptySet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyRestoredSkin(ServerPlayerEntity playerEntity, Property skin) {
|
||||||
|
playerEntity.getGameProfile().getProperties().removeAll("textures");
|
||||||
|
playerEntity.getGameProfile().getProperties().put("textures", skin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
|
||||||
|
private static boolean arePropertiesEquals(@NotNull JsonObject x, @NotNull GameProfile y) {
|
||||||
|
Property py = y.getProperties().get("textures").stream().findFirst().orElse(null);
|
||||||
|
if (py == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
JsonObject jy = gson.fromJson(new String(Base64.getDecoder().decode(py.getValue()), StandardCharsets.UTF_8), JsonObject.class);
|
||||||
|
jy.remove("timestamp");
|
||||||
|
return x.equals(jy);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
SkinRestorer.LOGGER.info("Can not compare skin", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.lionarius.skinrestorer.command;
|
package net.lionarius.skinrestorer.command;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.properties.Property;
|
import com.mojang.authlib.properties.Property;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
@@ -7,7 +8,8 @@ import net.lionarius.skinrestorer.MineskinSkinProvider;
|
|||||||
import net.lionarius.skinrestorer.MojangSkinProvider;
|
import net.lionarius.skinrestorer.MojangSkinProvider;
|
||||||
import net.lionarius.skinrestorer.SkinRestorer;
|
import net.lionarius.skinrestorer.SkinRestorer;
|
||||||
import net.lionarius.skinrestorer.enums.SkinVariant;
|
import net.lionarius.skinrestorer.enums.SkinVariant;
|
||||||
import net.minecraft.command.argument.EntityArgumentType;
|
import net.lionarius.skinrestorer.util.TranslationUtils;
|
||||||
|
import net.minecraft.command.argument.GameProfileArgumentType;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
@@ -16,6 +18,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static net.lionarius.skinrestorer.SkinStorage.DEFAULT_SKIN;
|
||||||
import static net.minecraft.server.command.CommandManager.argument;
|
import static net.minecraft.server.command.CommandManager.argument;
|
||||||
import static net.minecraft.server.command.CommandManager.literal;
|
import static net.minecraft.server.command.CommandManager.literal;
|
||||||
|
|
||||||
@@ -27,58 +30,71 @@ public class SkinCommand {
|
|||||||
.then(literal("mojang")
|
.then(literal("mojang")
|
||||||
.then(argument("skin_name", StringArgumentType.word())
|
.then(argument("skin_name", StringArgumentType.word())
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(Collections.singleton(context.getSource().getPlayer()), false,
|
skinAction(context.getSource(), false,
|
||||||
() -> MojangSkinProvider.getSkin(StringArgumentType.getString(context, "skin_name"))))
|
() -> MojangSkinProvider.getSkin(StringArgumentType.getString(context, "skin_name"))))
|
||||||
.then(argument("targets", EntityArgumentType.players()).requires(source -> source.hasPermissionLevel(3))
|
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(3))
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(EntityArgumentType.getPlayers(context, "targets"), true,
|
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||||
() -> MojangSkinProvider.getSkin(StringArgumentType.getString(context, "skin_name")))))))
|
() -> MojangSkinProvider.getSkin(StringArgumentType.getString(context, "skin_name")))))))
|
||||||
.then(literal("web")
|
.then(literal("web")
|
||||||
.then(literal("classic")
|
.then(literal("classic")
|
||||||
.then(argument("url", StringArgumentType.string())
|
.then(argument("url", StringArgumentType.string())
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(Collections.singleton(context.getSource().getPlayer()), false,
|
skinAction(context.getSource(), false,
|
||||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.CLASSIC)))
|
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.CLASSIC)))
|
||||||
.then(argument("targets", EntityArgumentType.players()).requires(source -> source.hasPermissionLevel(3))
|
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(3))
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(EntityArgumentType.getPlayers(context, "targets"), true,
|
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.CLASSIC))))))
|
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.CLASSIC))))))
|
||||||
.then(literal("slim")
|
.then(literal("slim")
|
||||||
.then(argument("url", StringArgumentType.string())
|
.then(argument("url", StringArgumentType.string())
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(Collections.singleton(context.getSource().getPlayer()), false,
|
skinAction(context.getSource(), false,
|
||||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.SLIM)))
|
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.SLIM)))
|
||||||
.then(argument("targets", EntityArgumentType.players()).requires(source -> source.hasPermissionLevel(3))
|
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(3))
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(EntityArgumentType.getPlayers(context, "targets"), true,
|
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.SLIM))))))))
|
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.SLIM))))))))
|
||||||
.then(literal("clear")
|
.then(literal("clear")
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
skinAction(Collections.singleton(context.getSource().getPlayer()), false,
|
skinAction(context.getSource(), false,
|
||||||
() -> null))
|
() -> DEFAULT_SKIN))
|
||||||
.then(argument("targets", EntityArgumentType.players()).executes(context ->
|
.then(argument("targets", GameProfileArgumentType.gameProfile()).executes(context ->
|
||||||
skinAction(EntityArgumentType.getPlayers(context, "targets"), true,
|
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||||
() -> null))))
|
() -> DEFAULT_SKIN))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int skinAction(Collection<ServerPlayerEntity> targets, boolean setByOperator, Supplier<Property> skinSupplier) {
|
private static int skinAction(ServerCommandSource src, Collection<GameProfile> targets, boolean setByOperator, Supplier<Property> skinSupplier) {
|
||||||
new Thread(() -> {
|
SkinRestorer.setSkinAsync(src.getServer(), targets, skinSupplier).thenAccept(pair -> {
|
||||||
if (!setByOperator)
|
Collection<GameProfile> profiles = pair.right();
|
||||||
targets.stream().findFirst().get().sendMessage(Text.of("§6[SkinRestorer]§f Downloading skin."), true);
|
Collection<ServerPlayerEntity> players = pair.left();
|
||||||
|
if (profiles.size() == 0) {
|
||||||
Property skin = skinSupplier.get();
|
src.sendError(Text.of(TranslationUtils.translation.skinActionFailed));
|
||||||
|
return;
|
||||||
for (ServerPlayerEntity player : targets) {
|
|
||||||
SkinRestorer.getSkinStorage().setSkin(player.getUuid(), skin);
|
|
||||||
|
|
||||||
if (setByOperator)
|
|
||||||
player.sendMessage(Text.of("§a[SkinRestorer]§f Operator changed your skin. You need to reconnect to apply it."), true);
|
|
||||||
else
|
|
||||||
player.sendMessage(Text.of("§a[SkinRestorer]§f You need to reconnect to apply skin."), true);
|
|
||||||
}
|
}
|
||||||
}).start();
|
if (setByOperator) {
|
||||||
|
src.sendFeedback(Text.of(
|
||||||
|
String.format(TranslationUtils.translation.skinActionAffectedProfile,
|
||||||
|
String.join(", ", profiles.stream().map(GameProfile::getName).toList()))), true);
|
||||||
|
if (players.size() != 0) {
|
||||||
|
src.sendFeedback(Text.of(
|
||||||
|
String.format(TranslationUtils.translation.skinActionAffectedPlayer,
|
||||||
|
String.join(", ", players.stream().map(p -> p.getGameProfile().getName()).toList()))), true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
src.sendFeedback(Text.of(TranslationUtils.translation.skinActionOk), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
return targets.size();
|
return targets.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int skinAction(ServerCommandSource src, boolean setByOperator, Supplier<Property> skinSupplier) {
|
||||||
|
if (src.getPlayer() != null) {
|
||||||
|
skinAction(src, Collections.singleton(src.getPlayer().getGameProfile()), setByOperator, skinSupplier);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
package net.lionarius.skinrestorer.mixin;
|
package net.lionarius.skinrestorer.mixin;
|
||||||
|
|
||||||
import net.lionarius.skinrestorer.SkinRestorer;
|
import net.lionarius.skinrestorer.SkinRestorer;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.PlayerManager;
|
import net.minecraft.server.PlayerManager;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
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.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Mixin(PlayerManager.class)
|
@Mixin(PlayerManager.class)
|
||||||
@@ -19,6 +23,8 @@ public abstract class PlayerManagerMixin {
|
|||||||
@Shadow
|
@Shadow
|
||||||
public abstract List<ServerPlayerEntity> getPlayerList();
|
public abstract List<ServerPlayerEntity> getPlayerList();
|
||||||
|
|
||||||
|
@Shadow @Final private MinecraftServer server;
|
||||||
|
|
||||||
@Inject(method = "remove", at = @At("TAIL"))
|
@Inject(method = "remove", at = @At("TAIL"))
|
||||||
private void remove(ServerPlayerEntity player, CallbackInfo ci) {
|
private void remove(ServerPlayerEntity player, CallbackInfo ci) {
|
||||||
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
||||||
@@ -30,4 +36,11 @@ public abstract class PlayerManagerMixin {
|
|||||||
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "onPlayerConnect", at = @At("HEAD"))
|
||||||
|
private void onPlayerConnected(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) {
|
||||||
|
if (player.getClass() != ServerPlayerEntity.class) { // if the player isn't a server player entity, it must be someone's fake player
|
||||||
|
SkinRestorer.setSkinAsync(server, Collections.singleton(player.getGameProfile()), () -> SkinRestorer.getSkinStorage().getSkin(player.getUuid()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public abstract class ServerLoginNetworkHandlerMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyRestoreSkin(ServerPlayerEntity playerEntity, Property skin) {
|
private static void applyRestoredSkin(ServerPlayerEntity playerEntity, Property skin) {
|
||||||
playerEntity.getGameProfile().getProperties().removeAll("textures");
|
playerEntity.getGameProfile().getProperties().removeAll("textures");
|
||||||
playerEntity.getGameProfile().getProperties().put("textures", skin);
|
playerEntity.getGameProfile().getProperties().put("textures", skin);
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ public abstract class ServerLoginNetworkHandlerMixin {
|
|||||||
@Inject(method = "addToServer", at = @At("HEAD"))
|
@Inject(method = "addToServer", at = @At("HEAD"))
|
||||||
public void applyRestoredSkinHook(ServerPlayerEntity player, CallbackInfo ci) {
|
public void applyRestoredSkinHook(ServerPlayerEntity player, CallbackInfo ci) {
|
||||||
if (skinrestorer_pendingSkin != null) {
|
if (skinrestorer_pendingSkin != null) {
|
||||||
applyRestoreSkin(player, skinrestorer_pendingSkin.getNow(SkinStorage.DEFAULT_SKIN));
|
applyRestoredSkin(player, skinrestorer_pendingSkin.getNow(SkinStorage.DEFAULT_SKIN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package net.lionarius.skinrestorer.util;
|
package net.lionarius.skinrestorer.util;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
||||||
public static String readFile(File file) {
|
public static String readFile(File file) {
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
|
||||||
return StringUtils.readString(reader);
|
return StringUtils.readString(reader);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return null;
|
return null;
|
||||||
@@ -21,7 +22,7 @@ public class FileUtils {
|
|||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
}
|
}
|
||||||
try (FileWriter writer = new FileWriter(file)) {
|
try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) {
|
||||||
writer.write(content);
|
writer.write(content);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package net.lionarius.skinrestorer.util;
|
||||||
|
|
||||||
|
import net.lionarius.skinrestorer.SkinRestorer;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class TranslationUtils {
|
||||||
|
public static class Translation {
|
||||||
|
public String skinActionAffectedProfile = "Skin has been saved for %s";
|
||||||
|
public String skinActionAffectedPlayer = "Apply live skin changes for %s";
|
||||||
|
public String skinActionFailed = "Failed to set skin";
|
||||||
|
public String skinActionOk = "Skin changed";
|
||||||
|
}
|
||||||
|
public static Translation translation = new Translation();
|
||||||
|
static {
|
||||||
|
Path path = Path.of("config", "skinrestorer", "translation.json");
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
try {
|
||||||
|
translation = JsonUtils.fromJson(Objects.requireNonNull(FileUtils.readFile(path.toFile())), Translation.class);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
SkinRestorer.LOGGER.error("Failed to load translation", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ public class WebUtils {
|
|||||||
os.write(input.getBytes(StandardCharsets.UTF_8), 0, input.length());
|
os.write(input.getBytes(StandardCharsets.UTF_8), 0, input.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
return StringUtils.readString(br);
|
return StringUtils.readString(br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ public class WebUtils {
|
|||||||
connection.setRequestMethod("GET");
|
connection.setRequestMethod("GET");
|
||||||
connection.setDoOutput(true);
|
connection.setDoOutput(true);
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
return StringUtils.readString(br);
|
return StringUtils.readString(br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user