Skip to content

Commit 3d5cafc

Browse files
committed
Added modifyPlayer and the ability to change the looped player's name and skin
Introduced a PlayerData class to encapsulate player attributes such as name, nickname, and skin. Updated all relevant methods and data structures in TimeLoop, LoopSceneManager, and TimeLoopConfig to use PlayerData, replacing simple string-based representations. Added new functionality to modify player attributes and validated configuration for improved robustness.
1 parent b4f6bf1 commit 3d5cafc

5 files changed

Lines changed: 144 additions & 32 deletions

File tree

src/main/java/com/vltno/timeloop/Commands.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.mojang.brigadier.CommandDispatcher;
44
import com.mojang.brigadier.arguments.BoolArgumentType;
55
import com.mojang.brigadier.arguments.IntegerArgumentType;
6+
import com.mojang.brigadier.arguments.StringArgumentType;
67
import net.minecraft.command.CommandRegistryAccess;
78
import net.minecraft.server.command.CommandManager;
89
import net.minecraft.server.command.ServerCommandSource;
@@ -137,6 +138,20 @@ public void register(CommandDispatcher<ServerCommandSource> dispatcher, CommandR
137138
LOGGER.info("Time of day set to {}", newTime);
138139
return 1;
139140
})))
141+
142+
.then(CommandManager.literal("modifyPlayer")
143+
.requires(source -> source.hasPermissionLevel(2))
144+
.then(CommandManager.argument("targetPlayer", StringArgumentType.string())
145+
.then(CommandManager.argument("newName", StringArgumentType.string())
146+
.then(CommandManager.argument("newSkin", StringArgumentType.string())
147+
.executes(context -> {
148+
String targetPlayer = StringArgumentType.getString(context, "targetPlayer");
149+
String newName = StringArgumentType.getString(context, "newName");
150+
String newSkin = StringArgumentType.getString(context, "newSkin");
151+
152+
mod.modifyPlayerAttributes(targetPlayer, newName, newSkin);
153+
return 1;
154+
})))))
140155

141156
// TOGGLES
142157
.then(CommandManager.literal("toggles")
Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,48 @@
11
package com.vltno.timeloop;
22

33
import java.util.ArrayList;
4+
import java.util.HashMap;
45
import java.util.List;
6+
import java.util.Map;
57
import java.util.function.Consumer;
68

79
public class LoopSceneManager {
810
private TimeLoopConfig config;
911
private String scenePrefix;
10-
private List<String> recordingPlayers;
12+
private Map<String, PlayerData> recordingPlayers;
13+
14+
1115

12-
// Constructor to initialize recordingPlayers
16+
// Constructor to initialize recordingPlayers map
1317
public LoopSceneManager(TimeLoopConfig config) {
1418
this.config = config;
1519
this.scenePrefix = config.scenePrefix;
16-
this.recordingPlayers = new ArrayList<>();
20+
this.recordingPlayers = new HashMap<>();
1721
}
1822

19-
// Method to add a player to the recordingPlayers list
20-
public void addPlayer(String playerName) {
23+
// Method to add a player to the recordingPlayers map
24+
public void addPlayer(List<String> args) {
25+
String playerName = args.get(0);
26+
List<String> nickname = args.size() > 1 ? args.subList(1, args.size()) : null;
27+
List<String> skin = args.size() > 2 ? args.subList(2, args.size()) : null;
28+
2129
if (playerName != null && !playerName.isEmpty()) {
22-
recordingPlayers.add(playerName);
30+
String tempNickname = (nickname == null || nickname.isEmpty()) ? playerName : nickname.getFirst();
31+
String tempSkin = (skin == null || skin.isEmpty()) ? playerName : skin.getFirst();
32+
33+
// Use player name as the key and store a PlayerData object
34+
recordingPlayers.put(playerName, new PlayerData(playerName, tempNickname, tempSkin));
2335
} else {
24-
System.out.println("Invalid player name. Player not added.");
36+
System.out.println("Invalid player data. Player not added.");
2537
}
2638
}
2739

28-
// Method to remove a specific player from the recordingPlayers list
40+
41+
// Method to remove a specific player from the recordingPlayers map
2942
public void removePlayer(String playerName) {
3043
if (playerName != null && !playerName.isEmpty()) {
31-
boolean removed = recordingPlayers.remove(playerName);
32-
if (removed) {
44+
PlayerData removed = recordingPlayers.remove(playerName);
45+
if (removed != null) {
3346
System.out.println("Player '" + playerName + "' removed successfully.");
3447
} else {
3548
System.out.println("Player '" + playerName + "' not found in the list.");
@@ -39,6 +52,7 @@ public void removePlayer(String playerName) {
3952
}
4053
}
4154

55+
4256
// Method to generate playerSceneName for a given player
4357
public String getPlayerSceneName(String playerName) {
4458
return (playerName.startsWith(scenePrefix)) ? playerName : (scenePrefix + "_" + playerName).toLowerCase();
@@ -47,25 +61,27 @@ public String getPlayerSceneName(String playerName) {
4761
// Method to get all playerSceneNames for recordingPlayers
4862
public List<String> getAllPlayerSceneNames() {
4963
List<String> playerSceneNames = new ArrayList<>();
50-
for (String player : recordingPlayers) {
51-
playerSceneNames.add(getPlayerSceneName(player));
64+
for (PlayerData player : recordingPlayers.values()) {
65+
playerSceneNames.add(getPlayerSceneName(player.getName()));
5266
}
5367
return playerSceneNames;
5468
}
5569

5670
public void forEachPlayerSceneName(Consumer<String> action) {
5771
getAllPlayerSceneNames().forEach(action);
5872
}
59-
60-
public void forEachRecordingPlayer(Consumer<String> action) {
61-
recordingPlayers.forEach(action);
73+
74+
// Method to perform an action for each recording player
75+
public void forEachRecordingPlayer(Consumer<PlayerData> action) {
76+
recordingPlayers.values().forEach(action);
6277
}
6378

64-
public void setRecordingPlayers(List<String> recordingPlayers) {
79+
// Method to set recording players with a new map
80+
public void setRecordingPlayers(Map<String, PlayerData> recordingPlayers) {
6581
this.recordingPlayers = recordingPlayers;
6682
}
67-
83+
6884
public void saveRecordingPlayers() {
69-
config.recordingPlayers = this.recordingPlayers;
85+
config.recordingPlayers = new HashMap<>(recordingPlayers);
7086
}
7187
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.vltno.timeloop;
2+
3+
public class PlayerData {
4+
private String name;
5+
private String nickname;
6+
private String skin;
7+
8+
public PlayerData(String name, String nickname, String skin) {
9+
this.name = name;
10+
this.nickname = nickname;
11+
this.skin = skin;
12+
}
13+
14+
// Getters and setters for player attributes
15+
public String getName() {
16+
return name;
17+
}
18+
19+
public void setName(String name) {
20+
this.name = name;
21+
}
22+
23+
public String getNickname() {
24+
return nickname;
25+
}
26+
27+
public void setNickname(String nickname) {
28+
this.nickname = nickname;
29+
}
30+
31+
public String getSkin() {
32+
return skin;
33+
}
34+
35+
public void setSkin(String skin) {
36+
this.skin = skin;
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return "PlayerData{" +
42+
"name='" + name + '\'' +
43+
", nickname='" + nickname + '\'' +
44+
", skin='" + skin + '\'' +
45+
'}';
46+
}
47+
}

src/main/java/com/vltno/timeloop/TimeLoop.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.nio.file.Files;
2626
import java.nio.file.Path;
2727
import java.util.ArrayList;
28+
import java.util.Arrays;
2829
import java.util.List;
2930

3031
public class TimeLoop implements ModInitializer {
@@ -144,7 +145,7 @@ public void onInitialize() {
144145
ServerPlayerEntity player = handler.getPlayer();
145146
String playerName = player.getName().getString();
146147

147-
loopSceneManager.addPlayer(playerName);
148+
loopSceneManager.addPlayer(Arrays.asList(playerName));
148149
loopBossBar.addPlayer(player);
149150

150151
executeCommand(String.format("mocap scenes add %s", loopSceneManager.getPlayerSceneName(playerName)));
@@ -248,9 +249,13 @@ private void runLoopIteration() {
248249
if (trackTimeOfDay) { serverWorld.setTimeOfDay(startTimeOfDay); }
249250
executeCommand("mocap playback stop_all including_others");
250251

251-
loopSceneManager.forEachRecordingPlayer(playerName -> {
252+
loopSceneManager.forEachRecordingPlayer(playerData -> {
253+
String playerName = playerData.getName();
254+
String playerNickname = playerData.getNickname();
255+
String playerSkin = playerData.getSkin();
256+
252257
String playerSceneName = loopSceneManager.getPlayerSceneName(playerName);
253-
executeCommand(String.format("mocap playback start .%s %s skin_from_player %s", playerSceneName, playerName, playerName));
258+
executeCommand(String.format("mocap playback start .%s %s skin_from_player %s", playerSceneName, playerNickname, playerSkin));
254259
});
255260

256261
loopIteration++;
@@ -264,7 +269,8 @@ private void runLoopIteration() {
264269
*/
265270
private void startRecordings() {
266271
// Start recording for every player
267-
loopSceneManager.forEachRecordingPlayer(playerName -> {
272+
loopSceneManager.forEachRecordingPlayer(playerData -> {
273+
String playerName = playerData.getName();
268274
executeCommand(String.format("mocap recording start %s", playerName));
269275
});
270276
}
@@ -274,7 +280,8 @@ private void startRecordings() {
274280
*/
275281
public void saveRecordings() {
276282
// Stop and save recordings for each player
277-
loopSceneManager.forEachRecordingPlayer(playerName -> {
283+
loopSceneManager.forEachRecordingPlayer(playerData -> {
284+
String playerName = playerData.getName();
278285
String recordingName = playerName + "_" + System.currentTimeMillis();
279286

280287
String playerSceneName = loopSceneManager.getPlayerSceneName(playerName);
@@ -361,7 +368,8 @@ private void removeOldSceneEntries() {
361368
Path sceneDir = worldFolder.resolve("mocap_files").resolve("scenes");
362369

363370
List<Path> sceneFiles = new ArrayList<>();
364-
loopSceneManager.forEachRecordingPlayer(playerSceneName -> {
371+
loopSceneManager.forEachRecordingPlayer(playerData -> {
372+
String playerSceneName = loopSceneManager.getPlayerSceneName(playerData.getName());
365373
if (playerSceneName != null && !playerSceneName.isBlank()) {
366374
sceneFiles.add(sceneDir.resolve(playerSceneName + ".mcmocap_scene"));
367375
} else {
@@ -425,6 +433,19 @@ public String convertTicksToTime(int ticksLeft) {
425433
int seconds = timeLeft % 60;
426434
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
427435
}
436+
437+
public void modifyPlayerAttributes(String targetPlayerName, String newPlayerNickname, String newSkin) {
438+
String playerSceneName = loopSceneManager.getPlayerSceneName(targetPlayerName);
439+
executeCommand(String.format("mocap scenes modify .%s %s player_skin skin_from_player %s", playerSceneName, newPlayerNickname, newSkin));
440+
441+
loopSceneManager.forEachRecordingPlayer(playerData -> {
442+
if (playerData.getName().equals(targetPlayerName)) {
443+
playerData.setNickname(newPlayerNickname);
444+
playerData.setSkin(newSkin);
445+
LOOP_LOGGER.info("Modified loop attributes for player '{}' -> '{}' with skin '{}'", targetPlayerName, newPlayerNickname, newSkin);
446+
}
447+
});
448+
}
428449
}
429450

430451
// use this in the future

src/main/java/com/vltno/timeloop/TimeLoopConfig.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import java.nio.file.Files;
1010
import java.nio.file.Path;
1111
import java.util.ArrayList;
12+
import java.util.HashMap;
1213
import java.util.List;
14+
import java.util.Map;
1315

1416
public class TimeLoopConfig {
1517
// These values will be loaded/saved from/to the JSON config file.bossbar set minecraft:loop_info
@@ -28,8 +30,8 @@ public class TimeLoopConfig {
2830
public boolean displayTimeInTicks = false;
2931
public boolean trackItems = false;
3032
public LoopTypes loopType = LoopTypes.TICKS;
31-
32-
public List<String> recordingPlayers = new ArrayList<>();
33+
34+
public Map<String, PlayerData> recordingPlayers = new HashMap<>();
3335

3436
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
3537
private static Path configPath;
@@ -43,17 +45,28 @@ public class TimeLoopConfig {
4345
*/
4446
public static TimeLoopConfig load(Path configDir) {
4547
configPath = configDir.resolve("timeloop.json");
48+
TimeLoopConfig config = null;
49+
4650
if (Files.exists(configPath)) {
4751
try (Reader reader = Files.newBufferedReader(configPath)) {
48-
TimeLoopConfig config = GSON.fromJson(reader, TimeLoopConfig.class);
49-
return config;
50-
} catch (IOException e) {
52+
config = GSON.fromJson(reader, TimeLoopConfig.class);
53+
} catch (Exception e) {
54+
System.err.println("Failed to load config file: " + e.getMessage());
5155
e.printStackTrace();
5256
}
5357
}
54-
// Create default config if none exists
55-
TimeLoopConfig config = new TimeLoopConfig();
56-
// config.recordingPlayers.add("stufffffffffffff");
58+
59+
if (config == null) {
60+
config = new TimeLoopConfig();
61+
System.err.println("Config file not found or invalid. Generating a default configuration.");
62+
}
63+
64+
// Validate recordingPlayers field and provide defaults if necessary
65+
if (config.recordingPlayers == null || !(config.recordingPlayers instanceof Map)) {
66+
System.err.println("Invalid or missing recordingPlayers data in config. Initializing with an empty map.");
67+
config.recordingPlayers = new HashMap<>();
68+
}
69+
5770
config.save();
5871
return config;
5972
}

0 commit comments

Comments
 (0)