diff --git a/build.gradle b/build.gradle
index 8722f81..d65ee33 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,22 +18,10 @@ repositories {
 	// for more information about repositories.
 }
 
-loom {
-	splitEnvironmentSourceSets()
-
-	mods {
-		"statssync" {
-			sourceSet sourceSets.main
-			sourceSet sourceSets.client
-		}
-	}
-
-}
-
 dependencies {
 	// To change the versions see the gradle.properties file
 	minecraft "com.mojang:minecraft:${project.minecraft_version}"
-	mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
+	mappings loom.officialMojangMappings()
 	modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
 
 	// Fabric API. This is technically optional, but you probably want it anyway.
diff --git a/src/client/java/com/yusuf007r/statssync/StatsSyncClient.java b/src/client/java/com/yusuf007r/statssync/StatsSyncClient.java
deleted file mode 100644
index 957d53f..0000000
--- a/src/client/java/com/yusuf007r/statssync/StatsSyncClient.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.yusuf007r.statssync;
-
-import net.fabricmc.api.ClientModInitializer;
-
-public class StatsSyncClient implements ClientModInitializer {
-	@Override
-	public void onInitializeClient() {
-		// This entrypoint is suitable for setting up client-specific logic, such as rendering.
-	}
-}
\ No newline at end of file
diff --git a/src/client/java/com/yusuf007r/statssync/mixin/client/ExampleClientMixin.java b/src/client/java/com/yusuf007r/statssync/mixin/client/ExampleClientMixin.java
deleted file mode 100644
index 4fba89b..0000000
--- a/src/client/java/com/yusuf007r/statssync/mixin/client/ExampleClientMixin.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.yusuf007r.statssync.mixin.client;
-
-import net.minecraft.client.MinecraftClient;
-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.CallbackInfo;
-
-@Mixin(MinecraftClient.class)
-public class ExampleClientMixin {
-	@Inject(at = @At("HEAD"), method = "run")
-	private void init(CallbackInfo info) {
-		// This code is injected into the start of MinecraftClient.run()V
-	}
-}
\ No newline at end of file
diff --git a/src/client/resources/statssync.client.mixins.json b/src/client/resources/statssync.client.mixins.json
deleted file mode 100644
index 97fc9d3..0000000
--- a/src/client/resources/statssync.client.mixins.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"required": true,
-	"package": "com.yusuf007r.statssync.mixin.client",
-	"compatibilityLevel": "JAVA_21",
-	"client": [
-		"ExampleClientMixin"
-	],
-	"injectors": {
-		"defaultRequire": 1
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/com/yusuf007r/statssync/StatsSync.java b/src/main/java/com/yusuf007r/statssync/StatsSync.java
index 7c98857..c00ba97 100644
--- a/src/main/java/com/yusuf007r/statssync/StatsSync.java
+++ b/src/main/java/com/yusuf007r/statssync/StatsSync.java
@@ -1,99 +1,29 @@
 package com.yusuf007r.statssync;
 
-import static net.minecraft.server.command.CommandManager.*;
 
-
-import com.mojang.authlib.GameProfile;
+import com.mojang.brigadier.arguments.StringArgumentType;
 import net.fabricmc.api.ModInitializer;
 import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
-import net.minecraft.command.argument.ScoreboardCriterionArgumentType;
-import net.minecraft.command.argument.ScoreboardObjectiveArgumentType;
-import net.minecraft.scoreboard.*;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.command.CommandManager;
-import net.minecraft.server.command.ServerCommandSource;
-import net.minecraft.stat.ServerStatHandler;
-import net.minecraft.stat.Stat;
-import net.minecraft.text.Text;
-import net.minecraft.util.UserCache;
-import net.minecraft.util.WorldSavePath;
-import org.jetbrains.annotations.NotNull;
+import net.minecraft.commands.arguments.ObjectiveArgument;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
-import java.nio.file.Path;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.UUID;
+import static net.minecraft.commands.Commands.argument;
+import static net.minecraft.commands.Commands.literal;
+import static net.minecraft.commands.SharedSuggestionProvider.suggest;
+
 
 public class StatsSync implements ModInitializer {
-    public static final String MOD_ID = "statssync";
+    public static final String MOD_ID = "stats-sync";
     public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
+    public static final UserCacheManager userCacheManager = new UserCacheManager();
 
-    void updateObjective(MinecraftServer server, ScoreboardObjective objective, ScoreHolder scoreHolder) {
-        ScoreboardCriterion criterion = objective.getCriterion();
-        Optional<UUID> playerUUID = getPlayerUUID(server, scoreHolder);
-
-        if (playerUUID.isEmpty()) {
-            LOGGER.warn("Could not find UUID for player: {}", scoreHolder.getNameForScoreboard());
-            return;
-        }
-
-        Path statsPath = getStatsFilePath(server, playerUUID.get());
-        if (!statsPath.toFile().exists()) {
-            LOGGER.warn("Stats file not found for player: {}", scoreHolder.getNameForScoreboard());
-            return;
-        }
-
-        int statValue = getStatValue(server, statsPath, criterion);
-        if (statValue > 0) {
-            updateScore(server, objective, scoreHolder, statValue);
-        }
-    }
-
-    private Optional<UUID> getPlayerUUID(@NotNull MinecraftServer server, ScoreHolder scoreHolder) {
-        return Optional.ofNullable(server.getUserCache()).flatMap(cache -> cache.findByName(scoreHolder.getNameForScoreboard())).map(GameProfile::getId);
-    }
-
-    private @NotNull Path getStatsFilePath(@NotNull MinecraftServer server, UUID playerUUID) {
-        return server.getSavePath(WorldSavePath.STATS).resolve(playerUUID + ".json");
-    }
 
-    private int getStatValue(MinecraftServer server, @NotNull Path statsPath, ScoreboardCriterion criterion) {
-        ServerStatHandler statHandler = new ServerStatHandler(server, statsPath.toFile());
-        return statHandler.getStat((Stat<?>) criterion);
-    }
-
-    private void updateScore(@NotNull MinecraftServer server, ScoreboardObjective objective, ScoreHolder scoreHolder, int value) {
-        server.getScoreboard().getOrCreateScore(scoreHolder, objective).setScore(value);
-    }
-
-
-    @Override
     public void onInitialize() {
-        LOGGER.info("Hello Fabric world!");
-
-        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("statSync").executes(context -> {
-            ServerCommandSource source = context.getSource();
-            MinecraftServer server = source.getServer();
-            ServerScoreboard scoreboard = server.getScoreboard();
-
-
-            source.sendFeedback(()-> Text.literal("Found " + scoreboard.getObjectives().size() + " Objectives, will try updating them with player stats"), false);
-            scoreboard.getObjectives().forEach((obj) -> {
-                try {
-                    source.sendFeedback(()-> Text.literal("trying to update: " + obj.getDisplayName().getString()), false);
-                    scoreboard.getKnownScoreHolders().forEach((scoreHolder -> {
-                        updateObjective(server, obj, scoreHolder);
-                    }));
-
-                } catch (Exception e) {
-                    LOGGER.info("Error while updating {}, {} the error was {}", obj.getDisplayName().getString(), obj.getCriterion().getName(), e.getMessage());
-                    source.sendFeedback(()-> Text.literal("Error while updating: " + obj.getDisplayName().getString()), false);
-                }
-            });
-            return 1;
-        })));
+        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("statSync").executes((c) -> new StatsSyncCommand(c).executeAllObjectivesAllPlayers())
+                .then(argument("objective", new ObjectiveArgument()).executes(c -> new StatsSyncCommand(c).executeSpecificObjectiveAllPlayers())
+                        .then(argument("player", StringArgumentType.word()).suggests((c, b) -> suggest(userCacheManager.getUserCache()
+                                        .stream().map(user -> user.profile().getName()), b))
+                                .executes(c -> new StatsSyncCommand(c).executeSpecificObjectiveSpecificPlayer())))));
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/yusuf007r/statssync/StatsSyncCommand.java b/src/main/java/com/yusuf007r/statssync/StatsSyncCommand.java
new file mode 100644
index 0000000..46a192c
--- /dev/null
+++ b/src/main/java/com/yusuf007r/statssync/StatsSyncCommand.java
@@ -0,0 +1,120 @@
+package com.yusuf007r.statssync;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.arguments.ObjectiveArgument;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.ServerScoreboard;
+import net.minecraft.stats.ServerStatsCounter;
+import net.minecraft.stats.Stat;
+import net.minecraft.world.level.storage.LevelResource;
+import net.minecraft.world.scores.Objective;
+import net.minecraft.world.scores.ScoreAccess;
+import net.minecraft.world.scores.ScoreHolder;
+import net.minecraft.world.scores.criteria.ObjectiveCriteria;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.UUID;
+
+public class StatsSyncCommand {
+
+    final private CommandSourceStack source;
+    final private MinecraftServer server;
+    final private ServerScoreboard scoreboard;
+    final private CommandContext<CommandSourceStack> context;
+    final private UserCacheManager userCacheManager = StatsSync.userCacheManager;
+    public static final Logger LOGGER = StatsSync.LOGGER;
+
+
+    StatsSyncCommand(CommandContext<CommandSourceStack> context) {
+        this.context = context;
+        this.source = context.getSource();
+        this.server = source.getServer();
+        this.scoreboard = server.getScoreboard();
+
+    }
+
+
+    public int executeAllObjectivesAllPlayers() {
+        source.sendSuccess(() -> Component.literal("Updating all objectives for all players"), false);
+        scoreboard.getObjectives().forEach(this::updateObjectiveForAllPlayers);
+
+        return 1;
+    }
+
+    public int executeSpecificObjectiveAllPlayers() throws CommandSyntaxException {
+        Objective objective = ObjectiveArgument.getObjective(context, "objective");
+        source.sendSuccess(() -> Component.literal("Updating objective " + objective.getDisplayName()
+                .getString() + " for all players"), false);
+        updateObjectiveForAllPlayers(objective);
+
+        return 1;
+    }
+
+    public int executeSpecificObjectiveSpecificPlayer() throws CommandSyntaxException {
+        Objective objective = ObjectiveArgument.getObjective(context, "objective");
+        String playerName = StringArgumentType.getString(context, "player");
+        Optional<UserCacheManager.Entry> entry = userCacheManager.getUserByName(playerName);
+        if (entry.isEmpty()) {
+            LOGGER.error("couldn't find user {} in the cache", playerName);
+        }
+        source.sendSuccess(() -> Component.literal("Updating objective " + objective.getDisplayName()
+                .getString() + " for player " + entry.orElseThrow().profile().getName()), false);
+        updateObjective(objective, entry.orElseThrow().profile());
+
+        return 1;
+    }
+
+
+    private void updateObjectiveForAllPlayers(Objective objective) {
+        try {
+            source.sendSuccess(() -> Component.literal("Updating: " + objective.getDisplayName().getString()), false);
+            for (UserCacheManager.Entry entry : userCacheManager.getUserCache()) {
+                updateObjective(objective, entry.profile());
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error while updating {}: {}", objective.getDisplayName().getString(), e.getMessage());
+            source.sendSuccess(() -> Component.literal("Error while updating: " + objective.getDisplayName()
+                    .getString()), false);
+        }
+    }
+
+    void updateObjective(@NotNull Objective objective, GameProfile profile) {
+        ObjectiveCriteria criterion = objective.getCriteria();
+        UUID playerUUID = profile.getId();
+
+        Path statsPath = getStatsFilePath(playerUUID);
+        if (!statsPath.toFile().exists()) {
+            LOGGER.warn("Stats file not found for player: {}", profile.getName());
+            return;
+        }
+
+        int statValue = getStatValue(statsPath, criterion);
+        if (statValue > 0) {
+            updateScore(objective, profile, statValue);
+        }
+    }
+
+
+    private @NotNull Path getStatsFilePath(UUID playerUUID) {
+        return server.getWorldPath(LevelResource.PLAYER_STATS_DIR).resolve(playerUUID + ".json");
+    }
+
+    private int getStatValue(@NotNull Path statsPath, ObjectiveCriteria criterion) {
+        ServerStatsCounter statHandler = new ServerStatsCounter(server, statsPath.toFile());
+        return statHandler.getValue((Stat<?>) criterion);
+    }
+
+    private void updateScore(Objective objective, GameProfile profile, int value) {
+        ScoreAccess scoreAccess = scoreboard.getOrCreatePlayerScore(ScoreHolder.fromGameProfile(profile), objective);
+        scoreAccess.set(value);
+    }
+
+}
diff --git a/src/main/java/com/yusuf007r/statssync/UserCacheManager.java b/src/main/java/com/yusuf007r/statssync/UserCacheManager.java
new file mode 100644
index 0000000..7cce618
--- /dev/null
+++ b/src/main/java/com/yusuf007r/statssync/UserCacheManager.java
@@ -0,0 +1,102 @@
+package com.yusuf007r.statssync;
+
+import com.google.common.collect.Maps;
+import com.google.gson.*;
+import com.mojang.authlib.GameProfile;
+import net.minecraft.util.StringUtil;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class UserCacheManager {
+    private final Map<String, Entry> byName = Maps.newHashMap();
+    public static final Logger LOGGER = StatsSync.LOGGER;
+
+    public record Entry(GameProfile profile, Date expirationDate) {
+
+    }
+
+    public UserCacheManager() {
+        this.init();
+    }
+
+
+    public Collection<Entry> getUserCache() {
+        return byName.values();
+    }
+
+    public Optional<Entry> getUserByName(String name) {
+        return Optional.ofNullable(byName.get(name));
+    }
+
+    private void add(Entry entry) {
+        if (!StringUtil.isValidPlayerName(entry.profile.getName())) return;
+        if ((byName.containsKey(entry.profile.getName()) && byName.get(entry.profile.getName()).expirationDate.after(entry.expirationDate)))
+            return;
+        byName.put(entry.profile.getName(), entry);
+    }
+
+    private void init() {
+        try {
+            Path path = Paths.get("./usercache.json");
+            if (Files.exists(path)) {
+                String content = new String(Files.readAllBytes(path));
+                JsonElement jsonElement = JsonParser.parseString(content);
+                if (jsonElement.isJsonArray()) {
+                    jsonElement.getAsJsonArray().forEach(json -> processJson(json).ifPresent(this::add));
+                }
+
+            }
+        } catch (IOException e) {
+            LOGGER.error(e.getMessage());
+        }
+
+    }
+
+    private Optional<Entry> processJson(JsonElement json) {
+        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.ROOT);
+        if (json.isJsonObject()) {
+            JsonObject jsonObject = json.getAsJsonObject();
+            JsonElement jsonElement = jsonObject.get("name");
+            JsonElement jsonElement2 = jsonObject.get("uuid");
+            JsonElement jsonElement3 = jsonObject.get("expiresOn");
+            if (jsonElement != null && jsonElement2 != null) {
+                String string = jsonElement2.getAsString();
+                String string2 = jsonElement.getAsString();
+                Date date = null;
+                if (jsonElement3 != null) {
+                    try {
+                        date = dateFormat.parse(jsonElement3.getAsString());
+                    } catch (ParseException var12) {
+                        LOGGER.error(var12.getMessage());
+                    }
+                }
+
+                if (string2 != null && string != null && date != null) {
+                    UUID uUID;
+                    try {
+                        uUID = UUID.fromString(string);
+                    } catch (Throwable var11) {
+                        return Optional.empty();
+                    }
+
+                    GameProfile gameProfile = new GameProfile(uUID, string2);
+                    return Optional.of(new Entry(gameProfile, date));
+                } else {
+                    return Optional.empty();
+                }
+            } else {
+                return Optional.empty();
+            }
+        } else {
+            return Optional.empty();
+        }
+    }
+}
diff --git a/src/main/java/com/yusuf007r/statssync/mixin/ExampleMixin.java b/src/main/java/com/yusuf007r/statssync/mixin/ExampleMixin.java
deleted file mode 100644
index b3b0eef..0000000
--- a/src/main/java/com/yusuf007r/statssync/mixin/ExampleMixin.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.yusuf007r.statssync.mixin;
-
-import net.minecraft.server.MinecraftServer;
-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.CallbackInfo;
-
-@Mixin(MinecraftServer.class)
-public class ExampleMixin {
-	@Inject(at = @At("HEAD"), method = "loadWorld")
-	private void init(CallbackInfo info) {
-		// This code is injected into the start of MinecraftServer.loadWorld()V
-	}
-}
\ No newline at end of file
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index d0c9650..b015231 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -17,17 +17,9 @@
 	"entrypoints": {
 		"main": [
 			"com.yusuf007r.statssync.StatsSync"
-		],
-		"client": [
-			"com.yusuf007r.statssync.StatsSyncClient"
 		]
 	},
 	"mixins": [
-		"statssync.mixins.json",
-		{
-			"config": "statssync.client.mixins.json",
-			"environment": "client"
-		}
 	],
 	"depends": {
 		"fabricloader": ">=0.15.11",
diff --git a/src/main/resources/statssync.mixins.json b/src/main/resources/statssync.mixins.json
deleted file mode 100644
index 54fa40a..0000000
--- a/src/main/resources/statssync.mixins.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"required": true,
-	"package": "com.yusuf007r.statssync.mixin",
-	"compatibilityLevel": "JAVA_21",
-	"mixins": [
-		"ExampleMixin"
-	],
-	"injectors": {
-		"defaultRequire": 1
-	}
-}
\ No newline at end of file