mirror of
https://github.com/Suiranoil/SkinRestorer.git
synced 2026-01-16 04:42:12 +00:00
Compare commits
14 Commits
v1.2.6+1.2
...
v1.2.6+1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
0c9b4d44cb
|
|||
|
2fca98e0f2
|
|||
|
3cba252b5b
|
|||
|
592cfb6ca4
|
|||
|
|
decad54884 | ||
|
3dd75626a1
|
|||
|
d720fc52ef
|
|||
|
b3a618f50b
|
|||
|
8724d6dd41
|
|||
|
baa1228f23
|
|||
|
16dc4bdc50
|
|||
|
ed3bc666db
|
|||
|
694aca9825
|
|||
|
7e38f06a84
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
java: [
|
||||
17,
|
||||
21,
|
||||
]
|
||||
os: [ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: build
|
||||
run: ./gradlew build
|
||||
- name: capture build artifacts
|
||||
if: ${{ runner.os == 'Linux' && matrix.java == '17' }}
|
||||
if: ${{ runner.os == 'Linux' && matrix.java == '21' }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Artifacts
|
||||
|
||||
42
README.md
42
README.md
@@ -6,8 +6,44 @@
|
||||
[](https://modrinth.com/mod/skinrestorer)
|
||||
|
||||
|
||||
This is a server-side only mod for fabric.
|
||||
SkinRestorer is a **server-side** only mod for Fabric that allows players to use and change skins on servers running in offline/insecure mode.
|
||||
|
||||
It allows you to use and change skins on servers that are in offline/insecure mode.
|
||||
## Features
|
||||
- **Set Skins from Mojang Account**: Fetch and apply skins using a valid Minecraft account name.
|
||||
- **Set Skins from URL**: Apply skins from any image URL, supporting both classic (Steve) and slim (Alex) skin models.
|
||||
|
||||
After installation on server use /skin command to change skin.
|
||||
## Command Usage Guide
|
||||
|
||||
### Set Mojang Skin
|
||||
```
|
||||
/skin set mojang <skin_name> [<targets>]
|
||||
```
|
||||
- **Parameters:**
|
||||
- `<skin_name>`: Minecraft account name to fetch the skin from.
|
||||
- `[<targets>]`: (Optional, server operators only) Player(s) to apply the skin to.
|
||||
|
||||
### Set Web Skin
|
||||
```
|
||||
/skin set web (classic|slim) "<url>" [<targets>]
|
||||
```
|
||||
- **Parameters:**
|
||||
- `(classic|slim)`: Type of the skin model (`classic` for Steve model, `slim` for Alex model).
|
||||
- `"<url>"`: URL pointing to the skin image file (ensure it follows Minecraft's skin size and format requirements).
|
||||
- `[<targets>]`: (Optional, server operators only) Player(s) to apply the skin to.
|
||||
|
||||
### Clear Skin
|
||||
```
|
||||
/skin clear [<targets>]
|
||||
```
|
||||
- **Parameters:**
|
||||
- `[<targets>]`: (Optional, server operators only) Player(s) to clear the skin for.
|
||||
|
||||
### Notes:
|
||||
- If `targets` is not specified, the command will apply to the player executing the command.
|
||||
|
||||
### Examples:
|
||||
```
|
||||
/skin set mojang Notch
|
||||
/skin set web classic "http://example.com/skin.png"
|
||||
/skin clear @a
|
||||
```
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
plugins {
|
||||
id 'fabric-loom' version '1.3-SNAPSHOT'
|
||||
id 'fabric-loom' version '1.7-SNAPSHOT'
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
archivesBaseName = project.archives_base_name
|
||||
version = "${project.mod_version}+${project.minecraft_version}"
|
||||
group = project.maven_group
|
||||
@@ -30,7 +27,7 @@ processResources {
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
it.options.encoding = "UTF-8"
|
||||
|
||||
it.options.release.set(17)
|
||||
it.options.release.set(21)
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -4,11 +4,11 @@ org.gradle.parallel=true
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/versions.html
|
||||
minecraft_version=1.20.3
|
||||
yarn_mappings=1.20.3+build.1
|
||||
minecraft_version=1.21
|
||||
yarn_mappings=1.21+build.2
|
||||
loader_version=0.15.11
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.2.5
|
||||
mod_version=1.2.6
|
||||
maven_group=net.lionarius
|
||||
archives_base_name=skin-restorer
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.lionarius.skinrestorer;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
@@ -8,12 +7,12 @@ import com.mojang.authlib.properties.Property;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.fabricmc.api.DedicatedServerModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.packet.s2c.play.*;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerChunkManager;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -40,50 +39,32 @@ public class SkinRestorer implements DedicatedServerModInitializer {
|
||||
}
|
||||
|
||||
public static void refreshPlayer(ServerPlayerEntity player) {
|
||||
List<com.mojang.datafixers.util.Pair<EquipmentSlot, ItemStack>> equipment = Lists.newArrayList();
|
||||
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||
ItemStack itemStack = player.getEquippedStack(slot);
|
||||
if (!itemStack.isEmpty()) {
|
||||
equipment.add(com.mojang.datafixers.util.Pair.of(slot, itemStack.copy()));
|
||||
}
|
||||
}
|
||||
ServerWorld serverWorld = player.getServerWorld();
|
||||
PlayerManager playerManager = serverWorld.getServer().getPlayerManager();
|
||||
ServerChunkManager chunkManager = serverWorld.getChunkManager();
|
||||
|
||||
for (ServerPlayerEntity observer : player.server.getPlayerManager().getPlayerList()) {
|
||||
observer.networkHandler.sendPacket(new PlayerRemoveS2CPacket(List.of(player.getUuid())));
|
||||
observer.networkHandler.sendPacket(PlayerListS2CPacket.entryFromPlayer(Collections.singleton(player)));
|
||||
|
||||
if (observer == player)
|
||||
continue;
|
||||
|
||||
observer.networkHandler.sendPacket(new EntitiesDestroyS2CPacket(player.getId()));
|
||||
observer.networkHandler.sendPacket(new EntitySpawnS2CPacket(player));
|
||||
observer.networkHandler.sendPacket(new EntityPositionS2CPacket(player));
|
||||
observer.networkHandler.sendPacket(new EntityTrackerUpdateS2CPacket(player.getId(), player.getDataTracker().getChangedEntries()));
|
||||
|
||||
if (!equipment.isEmpty())
|
||||
observer.networkHandler.sendPacket(new EntityEquipmentUpdateS2CPacket(player.getId(), equipment));
|
||||
|
||||
if (player.hasVehicle())
|
||||
observer.networkHandler.sendPacket(new EntityPassengersSetS2CPacket(player.getVehicle()));
|
||||
}
|
||||
|
||||
player.networkHandler.sendPacket(new PlayerRespawnS2CPacket(player.createCommonPlayerSpawnInfo(player.getServerWorld()), PlayerRespawnS2CPacket.KEEP_TRACKED_DATA));
|
||||
player.networkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.INITIAL_CHUNKS_COMING, 0));
|
||||
playerManager.sendToAll(new BundleS2CPacket(
|
||||
List.of(
|
||||
new PlayerRemoveS2CPacket(List.of(player.getUuid())),
|
||||
PlayerListS2CPacket.entryFromPlayer(Collections.singleton(player))
|
||||
)
|
||||
));
|
||||
chunkManager.unloadEntity(player);
|
||||
chunkManager.loadEntity(player);
|
||||
player.networkHandler.sendPacket(new BundleS2CPacket(
|
||||
List.of(
|
||||
new PlayerRespawnS2CPacket(player.createCommonPlayerSpawnInfo(serverWorld), PlayerRespawnS2CPacket.KEEP_ALL),
|
||||
new GameStateChangeS2CPacket(GameStateChangeS2CPacket.INITIAL_CHUNKS_COMING, 0)
|
||||
)
|
||||
));
|
||||
player.networkHandler.requestTeleport(player.getX(), player.getY(), player.getZ(), player.getYaw(), player.getPitch());
|
||||
player.networkHandler.sendPacket(new UpdateSelectedSlotS2CPacket(player.getInventory().selectedSlot));
|
||||
player.networkHandler.sendPacket(new EntityTrackerUpdateS2CPacket(player.getId(), player.getDataTracker().getChangedEntries()));
|
||||
|
||||
player.networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(player));
|
||||
player.sendAbilitiesUpdate();
|
||||
player.playerScreenHandler.updateToClient();
|
||||
|
||||
player.networkHandler.sendPacket(new ExperienceBarUpdateS2CPacket(player.experienceProgress, player.totalExperience, player.experienceLevel));
|
||||
player.networkHandler.sendPacket(new HealthUpdateS2CPacket(player.getHealth(), player.getHungerManager().getFoodLevel(), player.getHungerManager().getSaturationLevel()));
|
||||
|
||||
for (StatusEffectInstance instance : player.getStatusEffects())
|
||||
player.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(player.getId(), instance));
|
||||
|
||||
if (player.hasVehicle())
|
||||
player.networkHandler.sendPacket(new EntityPassengersSetS2CPacket(player.getVehicle()));
|
||||
player.addExperience(0);
|
||||
playerManager.sendCommandTree(player);
|
||||
playerManager.sendWorldInfo(player, serverWorld);
|
||||
playerManager.sendPlayerStatus(player);
|
||||
playerManager.sendStatusEffects(player);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>> setSkinAsync(MinecraftServer server, Collection<GameProfile> targets, Supplier<Property> skinSupplier) {
|
||||
|
||||
@@ -32,7 +32,7 @@ public class SkinCommand {
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(),
|
||||
() -> MojangSkinProvider.getSkin(StringArgumentType.getString(context, "skin_name"))))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(3))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(2))
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||
() -> MojangSkinProvider.getSkin(StringArgumentType.getString(context, "skin_name")))))))
|
||||
@@ -42,7 +42,7 @@ public class SkinCommand {
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(),
|
||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.CLASSIC)))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(3))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(2))
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.CLASSIC))))))
|
||||
@@ -51,7 +51,7 @@ public class SkinCommand {
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(),
|
||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.SLIM)))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(3))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(2))
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||
() -> MineskinSkinProvider.getSkin(StringArgumentType.getString(context, "url"), SkinVariant.SLIM))))))))
|
||||
@@ -59,7 +59,7 @@ public class SkinCommand {
|
||||
.executes(context ->
|
||||
skinAction(context.getSource(),
|
||||
() -> DEFAULT_SKIN))
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).executes(context ->
|
||||
.then(argument("targets", GameProfileArgumentType.gameProfile()).requires(source -> source.hasPermissionLevel(2)).executes(context ->
|
||||
skinAction(context.getSource(), GameProfileArgumentType.getProfileArgument(context, "targets"), true,
|
||||
() -> DEFAULT_SKIN))))
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user