diff --git a/README.md b/README.md index d109bd8..7ff29ab 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,7 @@ After you boot the server a new file will be generated in the path | `"pause_unloaded_chunks"` |

If an area of chunks is being recorded and the area is unloaded and this is set to `true` then the replay will pause the recording until the chunks are loaded again.

If set to false the chunks will be recorded as if they were loaded.

| | `"pause_notify_players"` |

If `pause_unloaded_chunks` is enabled and this is enabled then when the recording for the chunk area is paused or resumed all online players will be notified.

| | `"restart_after_max_file_size"` |

If a max file size is set and this limit is reached then the replay recording will automatically restart creating a new replay file.

| +| `"include_compressed_in_status"` |

Includes the compressed file size of the replays when you do `/replay status`, for long replays this may cause the status message to take a while to be displayed, so you can disable it.

| | `"fix_carpet_bot_view_distance"` |

If you are recording carpet bots you want to enable this as it sets the view distance to the server view distance. Otherwise it will only record a distance of 2 chunks around the bot. | | `"ignore_sound_packets"` |

If you are recording a large area for a timelapse it's unlikely you'll want to record any sounds, these can eat up significant storage space.

| | `"ignore_light_packets"` |

Light is calculated on the client as well as on the server so light packets are mostly redundant.

| diff --git a/gradle.properties b/gradle.properties index a915a70..d242a66 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,6 +15,6 @@ permissions_version=0.3-SNAPSHOT fabric_version=0.91.0+1.20.1 carpet_version=1.4.112 -mod_version=1.0.3 +mod_version=1.0.4 org.gradle.jvmargs=-Xmx4000m \ No newline at end of file diff --git a/src/main/kotlin/me/senseiwells/replay/commands/ReplayCommand.kt b/src/main/kotlin/me/senseiwells/replay/commands/ReplayCommand.kt index 6c6ae00..17845eb 100644 --- a/src/main/kotlin/me/senseiwells/replay/commands/ReplayCommand.kt +++ b/src/main/kotlin/me/senseiwells/replay/commands/ReplayCommand.kt @@ -25,6 +25,7 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.ChunkPos import org.apache.commons.lang3.builder.StandardToStringStyle import org.apache.commons.lang3.builder.ToStringBuilder +import java.util.concurrent.CompletableFuture object ReplayCommand { @JvmStatic @@ -300,22 +301,44 @@ object ReplayCommand { .append(if (ServerReplay.config.enabled) "enabled" else "disabled") .append("\n") - this.appendRecorders(builder, "Players", PlayerRecorders.all(), style) - this.appendRecorders(builder, "Chunks", ChunkRecorders.all(), style) + val players = this.getStatusFuture("Players", PlayerRecorders.all(), style) + val chunks = this.getStatusFuture("Chunks", ChunkRecorders.all(), style) - context.source.sendSystemMessage(Component.literal(builder.removeSuffix("\n").toString())) + CompletableFuture.runAsync { + for (player in players) { + builder.append(player.join()) + } + for (chunk in chunks) { + builder.append(chunk.join()) + } + + context.source.server.execute { + context.source.sendSuccess( + { Component.literal(builder.removeSuffix("\n").toString()) }, + true + ) + } + } + + context.source.sendSuccess({ + var message = "Generating replay status..." + if (ServerReplay.config.includeCompressedReplaySizeInStatus) { + message += "\nCalculating compressed sizes of replays (this may take a while)" + } + Component.literal(message) + }, true) return 1 } - private fun appendRecorders( - builder: StringBuilder, + private fun getStatusFuture( type: String, recorders: Collection, style: StandardToStringStyle, - ) { + ): List> { if (recorders.isNotEmpty()) { - builder.append("Currently Recording $type:").append("\n") - for ((recorder, compressed) in recorders.map { it to it.getCompressedRecordingSize() }) { + val futures = ArrayList>() + futures.add(CompletableFuture.completedFuture("Currently Recording $type:\n")) + for (recorder in recorders) { val seconds = recorder.getTotalRecordingTime() / 1000 val hours = seconds / 3600 val minutes = seconds % 3600 / 60 @@ -326,15 +349,18 @@ object ReplayCommand { .append("name", recorder.getName()) .append("time", time) .append("raw", FileUtils.formatSize(recorder.getRawRecordingSize())) - .append("compressed", FileUtils.formatSize(compressed.join())) - if (ServerReplay.config.debug) { - sub.append("debug", recorder.getDebugPacketData()) + if (ServerReplay.config.includeCompressedReplaySizeInStatus) { + val compressed = recorder.getCompressedRecordingSize() + futures.add(compressed.thenApplyAsync { + "${sub.append("compressed", FileUtils.formatSize(it))}\n" + }) + } else { + futures.add(CompletableFuture.completedFuture("$sub\n")) } - builder.append(sub.toString()).append("\n") } - } else { - builder.append("Not Currently Recording $type").append("\n") + return futures } + return listOf(CompletableFuture.completedFuture("Not Currently Recording $type\n")) } private fun suggestChunkX(): SuggestionProvider { diff --git a/src/main/kotlin/me/senseiwells/replay/config/ReplayConfig.kt b/src/main/kotlin/me/senseiwells/replay/config/ReplayConfig.kt index d26bb78..e5ac30a 100644 --- a/src/main/kotlin/me/senseiwells/replay/config/ReplayConfig.kt +++ b/src/main/kotlin/me/senseiwells/replay/config/ReplayConfig.kt @@ -56,6 +56,9 @@ class ReplayConfig { @SerialName("restart_after_max_file_size") var restartAfterMaxFileSize = false + @SerialName("include_compressed_in_status") + var includeCompressedReplaySizeInStatus = true + @SerialName("pause_unloaded_chunks") var skipWhenChunksUnloaded = false @SerialName("pause_notify_players") diff --git a/src/main/kotlin/me/senseiwells/replay/config/serialization/ResourceLocationSerializer.kt b/src/main/kotlin/me/senseiwells/replay/config/serialization/ResourceLocationSerializer.kt index 3cf83ad..a3d19b1 100644 --- a/src/main/kotlin/me/senseiwells/replay/config/serialization/ResourceLocationSerializer.kt +++ b/src/main/kotlin/me/senseiwells/replay/config/serialization/ResourceLocationSerializer.kt @@ -14,6 +14,7 @@ object ResourceLocationSerializer: KSerializer { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("dimension", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: ResourceLocation) { + encoder.encodeString(value.toString()) }