Skip to content

Commit cb97e62

Browse files
committed
Added config migration and fixed friends config
1 parent ddcb723 commit cb97e62

File tree

7 files changed

+471
-70
lines changed

7 files changed

+471
-70
lines changed

src/main/kotlin/com/lambda/Lambda.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import com.lambda.config.serializer.ItemStackCodec
2828
import com.lambda.config.serializer.KeyCodeCodec
2929
import com.lambda.config.serializer.OptionalCodec
3030
import com.lambda.config.serializer.TextCodec
31+
import com.lambda.config.serializer.UUIDCodec
3132
import com.lambda.core.Loader
3233
import com.lambda.event.events.ClientEvent
3334
import com.lambda.event.listener.UnsafeListener.Companion.listenOnceUnsafe
@@ -72,6 +73,7 @@ object Lambda : ClientModInitializer {
7273

7374
val gson: Gson = GsonBuilder()
7475
.setPrettyPrinting()
76+
.registerTypeAdapter(UUID::class.java, UUIDCodec)
7577
.registerTypeAdapter(KeyCode::class.java, KeyCodeCodec)
7678
.registerTypeAdapter(Color::class.java, ColorSerializer)
7779
.registerTypeAdapter(BlockPos::class.java, BlockPosCodec)

src/main/kotlin/com/lambda/command/commands/FriendCommand.kt

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.lambda.command.LambdaCommand
3131
import com.lambda.config.configurations.FriendConfig
3232
import com.lambda.friend.FriendManager
3333
import com.lambda.network.mojang.getProfile
34+
import com.lambda.threading.runIO
3435
import com.lambda.util.Communication.info
3536
import com.lambda.util.extension.CommandBuilder
3637
import com.lambda.util.text.ClickEvents
@@ -39,42 +40,48 @@ import com.lambda.util.text.literal
3940
import com.lambda.util.text.styled
4041
import kotlinx.coroutines.runBlocking
4142
import java.awt.Color
43+
import java.util.UUID
4244

4345
object FriendCommand : LambdaCommand(
4446
name = "friends",
45-
usage = "friends <add <name> | add-uuid <uuid> | remove <name>>",
47+
usage = "friends <add <name> | add-uuid <uuid> | remove <name> | remove-uuid <uuid>>",
4648
description = "Add or remove a friend"
4749
) {
4850
override fun CommandBuilder.create() {
4951
execute {
50-
info(
51-
buildText {
52-
if (FriendManager.friends.isEmpty()) {
53-
literal("You have no friends yet. Go make some! :3\n")
54-
} else {
55-
literal("Your friends (${FriendManager.friends.size}):\n")
56-
57-
FriendManager.friends.forEachIndexed { index, gameProfile ->
58-
literal(" ${index + 1}. ${gameProfile.name} ")
59-
styled(
60-
color = Color.RED,
61-
clickEvent = ClickEvents.suggestCommand(";friends remove ${gameProfile.name}")
62-
) {
63-
literal("x\n")
52+
runIO {
53+
info(
54+
buildText {
55+
if (FriendManager.friends.isEmpty()) {
56+
literal("You have no friends yet. Go make some! :3\n")
57+
} else {
58+
literal("Your friends (${FriendManager.friends.size}):\n")
59+
60+
FriendManager.friends.forEachIndexed { index, uuid ->
61+
val profile = FriendManager.latestGameProfile(uuid)
62+
val displayName = profile?.name ?: uuid.toString()
63+
64+
literal(" ${index + 1}. $displayName ")
65+
styled(
66+
color = Color.RED,
67+
clickEvent = ClickEvents.suggestCommand(";friends remove $displayName")
68+
) {
69+
literal("x\n")
70+
}
6471
}
6572
}
66-
}
6773

68-
literal("\n")
69-
styled(
70-
color = Color.CYAN,
71-
underlined = true,
72-
clickEvent = ClickEvents.openFile(FriendConfig.primary.path),
73-
) {
74-
literal("Click to open your friends list as a file")
74+
literal("\n")
75+
styled(
76+
color = Color.CYAN,
77+
underlined = true,
78+
clickEvent = ClickEvents.openFile(FriendConfig.primary.path),
79+
) {
80+
literal("Click to open your friends list as a file")
81+
}
7582
}
76-
}
77-
)
83+
)
84+
}
7885
}
7986

8087
required(literal("add")) {
@@ -92,19 +99,15 @@ object FriendCommand : LambdaCommand(
9299
executeWithResult {
93100
val name = player().value()
94101

95-
if (FriendManager.isFriend(name))
96-
return@executeWithResult failure("This player is already in your friend list")
102+
runBlocking {
103+
val profile = FriendManager.latestGameProfile(name)
104+
?: return@runBlocking failure("Could not find the player")
97105

98-
if (mc.gameProfile.name == name)
99-
return@executeWithResult failure("You can't befriend yourself")
106+
if (mc.gameProfile.id == profile.id)
107+
return@runBlocking failure("You can't befriend yourself")
100108

101-
runBlocking {
102-
val profile = mc.networkHandler
103-
?.playerList
104-
?.map { it.profile }
105-
?.firstOrNull { it.name == name }
106-
?: getProfile(name)
107-
.getOrElse { return@runBlocking failure("Could not find the player") }
109+
if (FriendManager.isFriend(profile.id))
110+
return@runBlocking failure("This player is already in your friend list")
108111

109112
FriendManager.befriend(profile)
110113

@@ -130,23 +133,23 @@ object FriendCommand : LambdaCommand(
130133
executeWithResult {
131134
val uuid = player().value()
132135

133-
if (FriendManager.isFriend(uuid))
134-
return@executeWithResult failure("This player is already in your friend list")
135-
136136
if (mc.gameProfile.id == uuid)
137137
return@executeWithResult failure("You can't befriend yourself")
138138

139-
runBlocking {
140-
val profile = mc.networkHandler
141-
?.playerList
142-
?.map { it.profile }
143-
?.firstOrNull { it.id == uuid }
144-
?: getProfile(uuid)
145-
.getOrElse { return@runBlocking failure("Could not find the player") }
139+
if (FriendManager.isFriend(uuid))
140+
return@executeWithResult failure("This player is already in your friend list")
146141

147-
FriendManager.befriend(profile)
142+
runBlocking {
143+
val profile = FriendManager.latestGameProfile(uuid)
144+
145+
if (profile != null) {
146+
FriendManager.befriend(profile)
147+
info(FriendManager.befriendedText(profile.name))
148+
} else {
149+
FriendManager.befriend(uuid)
150+
info(FriendManager.befriendedText(uuid.toString()))
151+
}
148152

149-
info(FriendManager.befriendedText(profile.name))
150153
success()
151154
}
152155
}
@@ -156,20 +159,46 @@ object FriendCommand : LambdaCommand(
156159
required(literal("remove")) {
157160
required(string("player name")) { player ->
158161
suggests { _, builder ->
159-
FriendManager.friends.map { it.name }
162+
FriendManager.friends
163+
.map { FriendManager.friendDisplayName(it) }
160164
.forEach { builder.suggest(it) }
161165

162166
builder.buildFuture()
163167
}
164168

165169
executeWithResult {
166170
val name = player().value()
167-
val profile = FriendManager.gameProfile(name)
168-
?: return@executeWithResult failure("This player is not in your friend list")
169171

170-
FriendManager.unfriend(profile)
172+
runBlocking {
173+
val uuid = FriendManager.gameProfile(name)?.id
174+
?: getProfile(name).getOrNull()?.id
175+
?: runCatching { UUID.fromString(name) }.getOrNull()
176+
?: return@runBlocking failure("Could not resolve the player name")
177+
178+
if (!FriendManager.isFriend(uuid))
179+
return@runBlocking failure("This player is not in your friend list")
180+
181+
FriendManager.unfriend(uuid)
182+
183+
info(FriendManager.unfriendedText(name))
184+
success()
185+
}
186+
}
187+
}
188+
}
189+
190+
required(literal("remove-uuid")) {
191+
required(uuid("player uuid")) { player ->
192+
executeWithResult {
193+
val uuid = player().value()
194+
195+
if (!FriendManager.isFriend(uuid))
196+
return@executeWithResult failure("This player is not in your friend list")
197+
198+
val displayName = FriendManager.friendDisplayName(uuid)
199+
FriendManager.unfriend(uuid)
171200

172-
info(FriendManager.unfriendedText(name))
201+
info(FriendManager.unfriendedText(displayName))
173202
success()
174203
}
175204
}

src/main/kotlin/com/lambda/config/Configuration.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.google.gson.JsonSyntaxException
2525
import com.lambda.Lambda.LOG
2626
import com.lambda.Lambda.gson
2727
import com.lambda.config.Configuration.Companion.configurables
28+
import com.lambda.config.migration.ConfigMigrations
2829
import com.lambda.config.configurations.ModuleConfigs
2930
import com.lambda.core.Loadable
3031
import com.lambda.event.events.ClientEvent
@@ -87,13 +88,22 @@ abstract class Configuration : Jsonable, Loadable {
8788

8889
override fun toJson() =
8990
JsonObject().apply {
91+
val latestSchemaVersion = ConfigMigrations.latestVersion(configName)
92+
if (latestSchemaVersion > 1) {
93+
addProperty(
94+
ConfigMigrations.schemaVersionKey(configName) ?: ConfigMigrations.DEFAULT_SCHEMA_VERSION_KEY,
95+
latestSchemaVersion
96+
)
97+
}
9098
configurables.forEach {
9199
add(it.name, it.toJson())
92100
}
93101
}
94102

95103
override fun loadFromJson(serialized: JsonElement) {
104+
val schemaKey = ConfigMigrations.schemaVersionKey(configName) ?: ConfigMigrations.DEFAULT_SCHEMA_VERSION_KEY
96105
serialized.asJsonObject.entrySet().forEach { (name, value) ->
106+
if (name == schemaKey) return@forEach
97107
configurableByName(name)
98108
?.loadFromJson(value)
99109
?: LOG.warn("No matching setting found for saved setting $name with $value in ${configName.capitalize()} config")
@@ -128,7 +138,17 @@ abstract class Configuration : Jsonable, Loadable {
128138
*/
129139
private fun load(file: File) = runCatching {
130140
file.ifNotExists { LOG.warn("No configuration file found for ${configName.capitalize()}. Creating new file when saving.") }
131-
.ifExists { loadFromJson(JsonParser.parseReader(it.reader()).asJsonObject) }
141+
.ifExists {
142+
val parsed = JsonParser.parseReader(it.reader()).asJsonObject
143+
val migrationResult = ConfigMigrations.migrate(configName, parsed)
144+
145+
if (migrationResult.migrated && file == primary) {
146+
file.writeText(gson.toJson(migrationResult.json))
147+
file.copyTo(backup, true)
148+
}
149+
150+
loadFromJson(migrationResult.json)
151+
}
132152
}
133153

134154
protected open fun internalTryLoad() {

0 commit comments

Comments
 (0)