Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions ZalithLauncher/src/main/assets/home_page/doc_page_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@ In addition to standard Markdown, you can also use the following extension compo

---

### Random Text Block
Place multiple text segments within a block. When the homepage loads, one of the segments will be randomly displayed.

**Syntax**
...random-start
This is a piece of text, weight defaults to 1.0
weight(2.0): This is the second piece of text, weight is set to 2.0
This is the third piece of text
...random-end

**Parameter description:**
- Unlike other components, this component uses inline parameters, embedded directly at the beginning of the actual value line.
- `weight`:
- Specifies the weight value for this piece of text. Supports integers and decimals. Optional.
- The homepage will randomly select a piece of text according to the weights.

> This component is only supported within standard Markdown.
> This component will NOT take effect inside standard Markdown containers or other extension components.

---

### Card Component
Used to wrap content inside a container with a background and rounded corners.

Expand Down Expand Up @@ -86,9 +107,11 @@ Creates a clickable button.
- `event`: The event to trigger, optional. The value must be wrapped in double quotes, and event data is wrapped in curly braces.
- `url{...}`: Opens a link in the browser.
- `check_update`: Triggers the launcher to check for updates.
- `launch_game`: Launches the currently selected version.
- `launch_game{server=...}`: Launches the currently selected version.
- Parameter `server`: Specifies the server to quick-join after launch, optional.
- `copy{...}`: Copies the specified content.
- For more events, please refer to the launcher's actual supported list.
- `refresh_page`: Refreshes the current homepage.
- `share_game_log`: Shares the log of the current game version.
- `width`: The width of the button, optional.
- You can use a percentage width, calculated based on the actual width of the homepage and the containing layout component: `50%` (only integer percentages supported).
- You can use DP units to set a more specific width: `200dp` (supports integers and decimals).
Expand Down
27 changes: 25 additions & 2 deletions ZalithLauncher/src/main/assets/home_page/doc_page_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@

---

### 随机文本块
在一个区块内填入多段文本,主页在加载时,将随机显示其中的一段文本

**语法**
...random-start
这是一段文本,权重默认为 1.0
weight(2.0): 这是第二段文本,权重被配置为 2.0
这是第三段文本
...random-end

**参数说明:**
- 与其他组件不同,该组件的参数为内嵌参数,直接嵌入到实际值行首
- `weight`:
- 可填写该段文本的具体的权重值,支持整数、小数,可选
- 主页将按权重随机抽取文本

> 该组件仅支持在基础的 Markdown 内使用
> 该组件不会生效于标准 Markdown 容器或其他扩展组件内

---

### 卡片组件
用于将内容包裹在一个有背景和圆角的容器中

Expand Down Expand Up @@ -86,9 +107,11 @@ contentPadding=(4, 4, 12, 12)
- `event`: 触发的事件,可选,值需使用双引号包裹,使用花括号包裹事件数据
- `url{...}`: 在浏览器中打开链接
- `check_update`: 触发启动器检查更新
- `launch_game`: 启动当前选中的版本
- `launch_game{server=...}`: 启动当前选中的版本
- 参数 `server`:指定快速启动并加入的服务器,可选
- `copy{...}`: 复制指定内容
- 更多事件请参考启动器的实际支持列表
- `refresh_page`: 刷新当前主页
- `share_game_log`: 分享当前游戏版本的日志
- `width`: 按钮的宽度,可选
- 可使用百分比宽度,会根据主页的实际宽度、所在布局组件的宽度计算:`50%`,仅支持整数百分比
- 可使用 DP 单位来设置更具体的宽度:`200dp`,支持整数、小数
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.movtery.zalithlauncher.context.COPY_LABEL_LINK
import com.movtery.zalithlauncher.coroutine.Task
import com.movtery.zalithlauncher.coroutine.TaskSystem
import com.movtery.zalithlauncher.game.control.ControlManager
import com.movtery.zalithlauncher.game.version.installed.VersionsManager
import com.movtery.zalithlauncher.notification.NotificationManager
import com.movtery.zalithlauncher.path.URL_SUPPORT
import com.movtery.zalithlauncher.setting.AllSettings
Expand All @@ -67,6 +68,7 @@ import com.movtery.zalithlauncher.utils.festival.getTodayFestivals
import com.movtery.zalithlauncher.utils.file.shareFile
import com.movtery.zalithlauncher.utils.isChinese
import com.movtery.zalithlauncher.utils.logging.Logger.lInfo
import com.movtery.zalithlauncher.utils.logging.Logger.lWarning
import com.movtery.zalithlauncher.utils.network.openLink
import com.movtery.zalithlauncher.utils.network.openLinkInternal
import com.movtery.zalithlauncher.utils.string.getMessageOrToString
Expand Down Expand Up @@ -469,15 +471,34 @@ class MainActivity : BaseAppCompatActivity() {
data: String?
) {
when (key) {
//浏览器内打开指定链接
"url" -> {
if (data != null) {
withContext(Dispatchers.Main) {
this@MainActivity.openLink(data)
}
}
}
//检查启动器更新
"check_update" -> checkUpdate()
"launch_game" -> launchGameViewModel.tryLaunch()
//启动当前选中的游戏版本
"launch_game" -> {
if (data != null) {
runCatching {
val parms = data.split("=")
if (parms.size == 2 && parms[0] == "server") {
//指定快速启动的服务器ip
val serverIp = parms[1].trim()
launchGameViewModel.tryPlayServer(serverIp)
return
}
}.onFailure { e ->
lWarning("Failed to parse quick join server parameters: $data", e)
}
}
launchGameViewModel.tryLaunch()
}
//复制指定文本
"copy" -> {
if (data != null) {
withContext(Dispatchers.Main) {
Expand All @@ -490,7 +511,17 @@ class MainActivity : BaseAppCompatActivity() {
}
}
}
//刷新主页
"refresh_page" -> homePageViewModel.reloadPage(true)
//分享游戏日志
"share_game_log" -> {
VersionsManager.currentVersion.value?.let { version ->
VersionsManager.getLatestLog(version).takeIf { it.exists() }
}?.let { logFile ->
logsUploadViewModel.check(logFile)
logShareViewModel.openMenu(logFile)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.halilibo.richtext.ui.RichTextStyle
import com.movtery.zalithlauncher.ui.components.MarkdownView
import com.movtery.zalithlauncher.ui.components.defaultRichTextStyle
import com.movtery.zalithlauncher.ui.theme.itemColor
import kotlin.random.Random

fun LazyListScope.customHomePage(
blocks: List<MarkdownBlock>,
Expand Down Expand Up @@ -399,17 +400,19 @@ private fun parseMarkdownBlocksInternal(
if (match == null) {
//没有更多匹配,添加剩余内容
val remaining = cleared.substring(lastIndex).trim('\n')
if (remaining.isNotEmpty()) {
blocks.add(MarkdownBlock.Normal(astNode = parseMarkdown(remaining)))
val processedRemaining = processRandomBlocksInText(remaining)
if (processedRemaining.isNotEmpty()) {
blocks.add(MarkdownBlock.Normal(astNode = parseMarkdown(processedRemaining)))
}
break
}

//处理匹配项之前的普通文本
if (match.range.first > lastIndex) {
val text = cleared.substring(lastIndex, match.range.first).trim('\n')
if (text.isNotEmpty()) {
blocks.add(MarkdownBlock.Normal(astNode = parseMarkdown(text)))
val processedText = processRandomBlocksInText(text)
if (processedText.isNotEmpty()) {
blocks.add(MarkdownBlock.Normal(astNode = parseMarkdown(processedText)))
}
}

Expand Down Expand Up @@ -793,4 +796,101 @@ private fun parseWeight(params: String): Pair<Float, Boolean>? {
val weight = match.groupValues[1].toFloatOrNull() ?: return null
val fill = match.groupValues[2] != "noFill"
return Pair(weight, fill)
}

private const val randomStartTag = "...random-start"
private const val randomEndTag = "...random-end"
private val randomOptionRegex = Regex("""^weight\((\d+(?:\.\d+)?)\)\s*:\s*(.*)$""")

private data class RandomOption(
val text: String,
val weight: Double
)

/**
* 处理文本中的随机文本块,自动将其替换为随机选中的文本
* 语法:
* ```
* ...random-start
* weight(N): 文本内容
* 默认权重的文本内容
* ...random-end
* ```
* - 以 `weight(N): ` 开头可指定权重,否则权重默认为 1
* - 随机抽取后的结果中不包含换行符
*/
private fun processRandomBlocksInText(text: String): String {
if (!text.contains(randomStartTag)) return text

val lines = text.lines()
val result = mutableListOf<String>()
var inRandomBlock = false
var randomStartLine: String? = null
val randomLines = mutableListOf<String>()

for (line in lines) {
val trimmed = line.trimStart()

if (inRandomBlock) {
if (trimmed.startsWith(randomEndTag)) {
val selected = pickRandomText(randomLines)
result.add(selected)
randomLines.clear()
inRandomBlock = false
randomStartLine = null
} else {
randomLines.add(line)
}
} else {
if (trimmed.startsWith(randomStartTag)) {
inRandomBlock = true
randomStartLine = line
} else {
result.add(line)
}
}
}

//如果文本结束但随机块未闭合,则忽略此随机文本块
if (inRandomBlock) {
randomStartLine?.let { result.add(it) }
result.addAll(randomLines)
}

return result.joinToString("\n")
}

/**
* 从随机文本候选项中根据权重抽取一个文本
*/
private fun pickRandomText(lines: List<String>): String {
val options = lines.mapNotNull { line ->
val trimmed = line.trim()
if (trimmed.isEmpty()) return@mapNotNull null

//读取权重值
val match = randomOptionRegex.find(trimmed)
if (match != null) {
val weight = match.groupValues[1].toDoubleOrNull() ?: 1.0
val text = match.groupValues[2]
RandomOption(text, weight)
} else {
//未配置权重时,默认为 1
RandomOption(trimmed, 1.0)
}
}

if (options.isEmpty()) return ""

val totalWeight = options.sumOf { it.weight }
var randomValue = Random.nextDouble() * totalWeight

for (option in options) {
randomValue -= option.weight
if (randomValue <= 0) {
return option.text
}
}

return options.last().text
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ class LaunchGameViewModel : ViewModel() {
}
}

/**
* 尝试启动游戏快速游玩服务器
* @param address 服务器地址
*/
fun tryPlayServer(address: String) {
val version = VersionsManager.currentVersion.value ?: return
quickPlayServer(version, address)
}

/**
* 通过服务器列表快速游玩服务器
* @param address 服务器地址
Expand Down
Loading