mirror of
https://github.com/jie65535/mirai-console-jcf-plugin.git
synced 2025-06-02 17:39:15 +08:00
[重大变化] 插件重构初步完成
移除旧代码 更新版本到v1.0.0
This commit is contained in:
parent
382b485fa7
commit
37a70e211e
24
README.md
24
README.md
@ -1,6 +1,8 @@
|
|||||||
# mirai-console-jcf-plugin
|
# mirai-console-jcf-plugin
|
||||||
基于Mirai Console的Curseforge插件
|
基于Mirai Console的Curseforge插件
|
||||||
|
|
||||||
|
# 请注意:本插件需要申请 [Curseforge Api Key](https://console.curseforge.com/) 才可使用!!
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
允许用户通过`QQ`对[Curseforge](https://www.curseforge.com/)网站进行搜索查询
|
允许用户通过`QQ`对[Curseforge](https://www.curseforge.com/)网站进行搜索查询
|
||||||
@ -10,12 +12,18 @@
|
|||||||
支持查看文件列表与其下载地址,单独查看文件的更新日志。
|
支持查看文件列表与其下载地址,单独查看文件的更新日志。
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
- /jcf id <projectId> # 根据id查找
|
指令
|
||||||
- /jcf help # 帮助
|
- /jcf help # 查看帮助
|
||||||
- /jcf ss \<filter\> # 直接搜索
|
- /jcf setApiKey # 设置Curseforge API Key
|
||||||
- /jcf sspack \<filter\> # 搜索整合包
|
|
||||||
- /jcf ssmod \<filter\> # 搜索模组
|
分类搜索命令(可配置)
|
||||||
- /jcf ssres \<filter\> # 搜索资源包
|
- 搜索模组: cfmod \<filter\>
|
||||||
|
- 搜索整合包: cfpack \<filter\>
|
||||||
|
- 搜索资源包: cfres \<filter\>
|
||||||
|
- 搜索存档: cfword \<filter\>
|
||||||
|
- 搜索水桶服插件: cfbukkit \<filter\>
|
||||||
|
- 搜索附加: cfaddon \<filter\>
|
||||||
|
- 搜索定制: cfcustom \<filter\>
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
@ -33,7 +41,7 @@
|
|||||||
- [x] 搜索整合包
|
- [x] 搜索整合包
|
||||||
- [x] 搜索资源包
|
- [x] 搜索资源包
|
||||||
- [x] ~~搜索存档~~
|
- [x] ~~搜索存档~~
|
||||||
- [x] 根据项目ID搜索
|
- [ ] 根据项目ID搜索
|
||||||
---
|
---
|
||||||
- [x] 分页选择
|
- [x] 分页选择
|
||||||
- [ ] 获取介绍
|
- [ ] 获取介绍
|
||||||
@ -50,5 +58,3 @@
|
|||||||
## 鸣谢
|
## 鸣谢
|
||||||
- [Mirai](https://github.com/mamoe/mirai) 提供机器人平台
|
- [Mirai](https://github.com/mamoe/mirai) 提供机器人平台
|
||||||
- [Mirai Console](https://github.com/mamoe/mirai-console) 开放插件接入
|
- [Mirai Console](https://github.com/mamoe/mirai-console) 开放插件接入
|
||||||
- [Curseforge API](https://github.com/Gaz492/CurseforgeAPI) 提供`Curseforge API`
|
|
||||||
- [Curseforge API Kotlin library](https://github.com/pearxteam/cursekt) 提供`Curseforge API`的`kotlin`封装
|
|
||||||
|
@ -6,7 +6,7 @@ plugins {
|
|||||||
id("net.mamoe.mirai-console") version "2.11.1"
|
id("net.mamoe.mirai-console") version "2.11.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "top.jie65535"
|
group = "top.jie65535.jcf"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -1,229 +0,0 @@
|
|||||||
package me.jie65535.jcf
|
|
||||||
|
|
||||||
import io.ktor.client.*
|
|
||||||
import io.ktor.client.engine.okhttp.*
|
|
||||||
import io.ktor.client.features.*
|
|
||||||
import io.ktor.client.request.*
|
|
||||||
import io.ktor.http.*
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import me.jie65535.jcf.model.addon.*
|
|
||||||
import me.jie65535.jcf.model.addon.file.*
|
|
||||||
import me.jie65535.jcf.model.addon.request.*
|
|
||||||
import me.jie65535.jcf.model.category.*
|
|
||||||
import me.jie65535.jcf.model.fingerprint.*
|
|
||||||
import me.jie65535.jcf.model.fingerprint.request.*
|
|
||||||
import me.jie65535.jcf.model.game.*
|
|
||||||
import me.jie65535.jcf.model.minecraft.*
|
|
||||||
import me.jie65535.jcf.model.minecraft.modloader.*
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
object CurseClient {
|
|
||||||
private val json = Json {
|
|
||||||
isLenient = true
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
serializersModule
|
|
||||||
}
|
|
||||||
private val http = HttpClient(OkHttp) {
|
|
||||||
install(HttpTimeout) {
|
|
||||||
this.requestTimeoutMillis = 30_0000
|
|
||||||
this.connectTimeoutMillis = 30_0000
|
|
||||||
this.socketTimeoutMillis = 30_0000
|
|
||||||
}
|
|
||||||
defaultRequest {
|
|
||||||
url.protocol = URLProtocol.HTTPS
|
|
||||||
url.host = "addons-ecs.forgesvc.net"
|
|
||||||
header("accept", "*/*")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getGames(supportsAddons: Boolean = false): List<Game> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.get("api/v2/game") {
|
|
||||||
parameter("supportsAddons", supportsAddons.toString())
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getGame(gameId: Int): Game {
|
|
||||||
return json.decodeFromString(http.get("api/v2/game/$gameId"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getGameDatabaseTimestamp(): Date {
|
|
||||||
return http.get("api/v2/game/timestamp")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddon(projectId: Int): Addon {
|
|
||||||
return json.decodeFromString(http.get("api/v2/addon/$projectId"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddons(projectIds: Collection<Int>): List<Addon> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.post("api/v2/addon") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
body = json.encodeToString(projectIds)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddons(vararg projectIds: Int): List<Addon> = getAddons(projectIds.toList())
|
|
||||||
|
|
||||||
suspend fun getAddonDescription(projectId: Int): String {
|
|
||||||
return http.get("api/v2/addon/$projectId/description")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddonFiles(projectId: Int): List<AddonFile> {
|
|
||||||
return json.decodeFromString(http.get("api/v2/addon/$projectId/files"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddonFiles(keys: Collection<Int>): Map<Int, List<AddonFile>> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.post("api/v2/addon/files") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
body = json.encodeToString(keys)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddonFiles(vararg keys: Int): Map<Int, List<AddonFile>> = getAddonFiles(keys.toList())
|
|
||||||
|
|
||||||
suspend fun getAddonFileDownloadUrl(projectId: Int, fileId: Int): String {
|
|
||||||
return http.get("api/v2/addon/$projectId/file/$fileId/download-url")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddonFile(projectId: Int, fileId: Int): AddonFile {
|
|
||||||
return json.decodeFromString(http.get("api/v2/addon/$projectId/file/$fileId"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun searchAddons(
|
|
||||||
gameId: Int,
|
|
||||||
sectionId: Int = -1,
|
|
||||||
categoryId: Int = -1,
|
|
||||||
sort: AddonSortMethod = AddonSortMethod.FEATURED,
|
|
||||||
sortDescending: Boolean = true,
|
|
||||||
gameVersion: String? = null,
|
|
||||||
index: Int = 0,
|
|
||||||
pageSize: Int = 10,
|
|
||||||
searchFilter: String? = null
|
|
||||||
): List<Addon> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.get("api/v2/addon/search") {
|
|
||||||
parameter("gameId", gameId)
|
|
||||||
parameter("sectionId", sectionId)
|
|
||||||
parameter("categoryId", categoryId)
|
|
||||||
parameter("gameVersion", gameVersion)
|
|
||||||
parameter("index", index)
|
|
||||||
parameter("pageSize", pageSize)
|
|
||||||
parameter("searchFilter", searchFilter)
|
|
||||||
parameter("sort", sort)
|
|
||||||
parameter("sortDescending", sortDescending)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getFeaturedAddons(
|
|
||||||
gameId: Int,
|
|
||||||
featuredCount: Int = 6,
|
|
||||||
popularCount: Int = 14,
|
|
||||||
updatedCount: Int = 14,
|
|
||||||
excludedAddons: Collection<Int> = listOf()
|
|
||||||
): Map<FeaturedAddonType, List<Addon>> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.post("api/v2/addon/featured") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
body = json.encodeToString(FeaturedAddonsRequest(gameId, featuredCount, popularCount, updatedCount, excludedAddons))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getFeaturedAddons(
|
|
||||||
gameId: Int,
|
|
||||||
featuredCount: Int = 6,
|
|
||||||
popularCount: Int = 14,
|
|
||||||
updatedCount: Int = 14,
|
|
||||||
vararg excludedAddons: Int
|
|
||||||
): Map<FeaturedAddonType, List<Addon>> = getFeaturedAddons(gameId, featuredCount, popularCount, updatedCount, excludedAddons.toList())
|
|
||||||
|
|
||||||
suspend fun getCategory(categoryId: Int): Category {
|
|
||||||
return json.decodeFromString(http.get("api/v2/category/$categoryId"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getCategory(slug: String): List<Category> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.get("api/v2/category") {
|
|
||||||
parameter("slug", slug)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getCategorySection(sectionId: Int): List<Category> {
|
|
||||||
return json.decodeFromString(http.get("api/v2/category/section/$sectionId"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getCategories(): List<Category> {
|
|
||||||
return json.decodeFromString(http.get("api/v2/category"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getCategoryDatabaseTimestamp(): Date {
|
|
||||||
return http.get("api/v2/category/timestamp")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getFingerprintMatches(fingerprints: Collection<Long>): FingerprintMatchResult {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.post("api/v2/fingerprint") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
body = json.encodeToString(fingerprints)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getFingerprintMatches(vararg fingerprints: Long): FingerprintMatchResult = getFingerprintMatches(fingerprints.toList())
|
|
||||||
|
|
||||||
suspend fun getFuzzyFingerprintMatches(gameId: Int, fingerprints: List<FolderFingerprint>): List<FuzzyFingerprintMatch> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.post("api/v2/fingerprint/fuzzy") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
body = json.encodeToString(FuzzyMatchesRequest(gameId, fingerprints))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getModloader(key: String): ModloaderVersion {
|
|
||||||
return json.decodeFromString(http.get("api/v2/minecraft/modloader/$key"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getModloaders(): List<ModloaderIndex> {
|
|
||||||
return json.decodeFromString(http.get("api/v2/minecraft/modloader"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getModloaders(gameVersion: String): List<ModloaderIndex> {
|
|
||||||
return json.decodeFromString(
|
|
||||||
http.get("api/v2/minecraft/modloader") {
|
|
||||||
parameter("version", gameVersion)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getModloadersDatabaseTimestamp(): Date {
|
|
||||||
return http.get("api/v2/minecraft/modloader/timestamp")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getMinecraftVersions(): List<MinecraftVersion> {
|
|
||||||
return json.decodeFromString(http.get("api/v2/minecraft/version"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getMinecraftVersion(gameVersion: String): MinecraftVersion {
|
|
||||||
return json.decodeFromString(http.get("api/v2/minecraft/version/$gameVersion"))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getMinecraftVersionsDatabaseTimestamp(): Date {
|
|
||||||
return http.get("api/v2/minecraft/version/timestamp")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getAddonFileChangeLog(addonId: Int, fileId: Int): String {
|
|
||||||
return http.get("api/v2/addon/${addonId}/file/${fileId}/changelog")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package me.jie65535.jcf
|
|
||||||
|
|
||||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
|
|
||||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregister
|
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
|
||||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
|
||||||
import net.mamoe.mirai.utils.info
|
|
||||||
|
|
||||||
object JCurseforge : KotlinPlugin(
|
|
||||||
JvmPluginDescription(
|
|
||||||
id = "me.jie65535.jcf",
|
|
||||||
name = "J Curseforge Util",
|
|
||||||
version = "0.1.1",
|
|
||||||
) {
|
|
||||||
author("jie65535")
|
|
||||||
info("""
|
|
||||||
MC Curseforge Util
|
|
||||||
https://github.com/jie65535/mirai-console-jcf-plugin
|
|
||||||
""".trimIndent())
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
override fun onEnable() {
|
|
||||||
logger.info { "Plugin loaded" }
|
|
||||||
JcfCommand.register()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisable() {
|
|
||||||
JcfCommand.unregister()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package me.jie65535.jcf
|
|
||||||
|
|
||||||
import net.mamoe.mirai.console.command.CommandSender
|
|
||||||
import net.mamoe.mirai.console.command.CompositeCommand
|
|
||||||
import net.mamoe.mirai.console.command.UserCommandSender
|
|
||||||
import net.mamoe.mirai.console.plugin.author
|
|
||||||
import net.mamoe.mirai.console.plugin.info
|
|
||||||
import net.mamoe.mirai.console.plugin.name
|
|
||||||
import net.mamoe.mirai.console.plugin.version
|
|
||||||
|
|
||||||
object JcfCommand : CompositeCommand(
|
|
||||||
JCurseforge, "jcf",
|
|
||||||
description = "Curseforge Util"
|
|
||||||
) {
|
|
||||||
@SubCommand
|
|
||||||
@Description("帮助")
|
|
||||||
suspend fun CommandSender.help() {
|
|
||||||
sendMessage("${JCurseforge.name} by ${JCurseforge.author} ${JCurseforge.version}\n" +
|
|
||||||
"${JCurseforge.info}\n" + usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubCommand("ss")
|
|
||||||
@Description("直接搜索")
|
|
||||||
suspend fun UserCommandSender.search(filter: String) {
|
|
||||||
MinecraftService.search(this, MinecraftService.ALL, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubCommand("ssmod")
|
|
||||||
@Description("搜索模组")
|
|
||||||
suspend fun UserCommandSender.searchMods(filter: String) {
|
|
||||||
MinecraftService.search(this, MinecraftService.SECTION_ID_MODES, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubCommand("sspack")
|
|
||||||
@Description("搜索整合包")
|
|
||||||
suspend fun UserCommandSender.searchModPacks(filter: String) {
|
|
||||||
MinecraftService.search(this, MinecraftService.SECTION_ID_MODE_PACKS, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubCommand("ssres")
|
|
||||||
@Description("搜索资源包")
|
|
||||||
suspend fun UserCommandSender.searchResourcePacks(filter: String) {
|
|
||||||
MinecraftService.search(this, MinecraftService.SECTION_ID_RESOURCE_PACKS, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 可能用不上,先注释掉,有需要再说
|
|
||||||
// @SubCommand("ssworld")
|
|
||||||
// @Description("搜索存档")
|
|
||||||
// suspend fun UserCommandSender.searchWorlds(filter: String) {
|
|
||||||
// MinecraftService.search(this, MinecraftService.SECTION_ID_WORLDS, filter)
|
|
||||||
// }
|
|
||||||
|
|
||||||
@SubCommand("id")
|
|
||||||
@Description("根据id查找")
|
|
||||||
suspend fun UserCommandSender.getAddonById(projectId: Int) {
|
|
||||||
MinecraftService.searchAddonByProjectId(this, projectId)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
package me.jie65535.jcf
|
|
||||||
|
|
||||||
import me.jie65535.jcf.model.addon.Addon
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFile
|
|
||||||
import me.jie65535.jcf.util.HttpUtil
|
|
||||||
import net.mamoe.mirai.contact.Contact
|
|
||||||
import net.mamoe.mirai.message.data.*
|
|
||||||
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
|
|
||||||
import java.text.DecimalFormat
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
object MessageHandler {
|
|
||||||
|
|
||||||
fun parseSearchResult(addons: List<Addon>, builder: ForwardMessageBuilder, contact: Contact) {
|
|
||||||
for ((index, addon) in addons.withIndex()) {
|
|
||||||
builder.add(contact.bot.id, index.toString(),
|
|
||||||
PlainText("""
|
|
||||||
$index | [${addon.name}] by ${addon.authors[0].name}
|
|
||||||
${formatCount(addon.downloadCount)} Downloads Updated ${addon.dateModified.toLocalDate()}
|
|
||||||
${addon.summary}
|
|
||||||
${addon.websiteUrl}
|
|
||||||
""".trimIndent()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
|
||||||
suspend fun parseAddon(addon: Addon, contact: Contact): ForwardMessageBuilder {
|
|
||||||
val builder = ForwardMessageBuilder(contact)
|
|
||||||
.add(contact.bot, loadImage(addon.attachments.find{ it.isDefault }!!.thumbnailUrl, contact))
|
|
||||||
.add(contact.bot, PlainText("""
|
|
||||||
${addon.name}
|
|
||||||
作者:${addon.authors[0].name}
|
|
||||||
概括:${addon.summary}
|
|
||||||
项目ID:${addon.id}
|
|
||||||
创建时间:${addon.dateCreated.toLocalDate()}
|
|
||||||
最近更新:${addon.dateModified.toLocalDate()}
|
|
||||||
总下载:${addon.downloadCount.toLong()}
|
|
||||||
主页:${addon.websiteUrl}
|
|
||||||
""".trimIndent()))
|
|
||||||
if (addon.latestFiles.isNotEmpty()) {
|
|
||||||
builder.add(contact.bot, PlainText("最新文件列表:"))
|
|
||||||
parseAddonFiles(addon.latestFiles, builder, contact)
|
|
||||||
}
|
|
||||||
// JCurseforge.logger.info(addon.latestFiles.toString())
|
|
||||||
// JCurseforge.logger.info(addon.gameVersionLatestFiles.toString())
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
fun parseAddonFiles(addonFiles: Collection<AddonFile>, builder: ForwardMessageBuilder, contact: Contact) {
|
|
||||||
for ((index, file) in addonFiles.withIndex()) {
|
|
||||||
builder.add(contact.bot.id, index.toString(), PlainText("""
|
|
||||||
$index | ${file.displayName} [${file.releaseType}] [${file.fileDate.toLocalDate()}]
|
|
||||||
${file.downloadUrl}
|
|
||||||
""".trimIndent()))
|
|
||||||
// 暂时只允许构造21项
|
|
||||||
if (index >= 20)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val ONE_GRP_SIZE = 5000
|
|
||||||
private const val ONE_MSG_SIZE = 500
|
|
||||||
suspend fun sendLargeMessage(contact: Contact, message: String) {
|
|
||||||
for (g in message.indices step ONE_GRP_SIZE) {
|
|
||||||
val builder = ForwardMessageBuilder(contact)
|
|
||||||
for (i in g until g + min(ONE_GRP_SIZE, message.length-g) step ONE_MSG_SIZE) {
|
|
||||||
builder.add(contact.bot, PlainText(message.subSequence(i, i+(min(ONE_MSG_SIZE, message.length-i)))))
|
|
||||||
}
|
|
||||||
contact.sendMessage(builder.build())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val singleDecimalFormat = DecimalFormat("0.#")
|
|
||||||
private fun formatCount(count: Double): String = when {
|
|
||||||
count < 1000000 -> singleDecimalFormat.format(count / 1000) + "K"
|
|
||||||
count < 1000000000 -> singleDecimalFormat.format(count / 1000000) + "M"
|
|
||||||
else -> count.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
|
||||||
private suspend fun loadImage(url: String, contact: Contact): Image {
|
|
||||||
val imgFileName = url.substringAfterLast("/")
|
|
||||||
val file = JCurseforge.resolveDataFile("cache/$imgFileName")
|
|
||||||
val res = if (file.exists()) {
|
|
||||||
file.readBytes().toExternalResource()
|
|
||||||
} else {
|
|
||||||
HttpUtil.downloadImage(url, file).toExternalResource()
|
|
||||||
}
|
|
||||||
val image = contact.uploadImage(res)
|
|
||||||
res.close()
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
package me.jie65535.jcf
|
|
||||||
|
|
||||||
import io.ktor.client.features.*
|
|
||||||
import io.ktor.http.*
|
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
|
||||||
import me.jie65535.jcf.model.addon.Addon
|
|
||||||
import me.jie65535.jcf.model.addon.AddonSortMethod
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFile
|
|
||||||
import net.mamoe.mirai.console.command.UserCommandSender
|
|
||||||
import net.mamoe.mirai.event.events.MessageEvent
|
|
||||||
import net.mamoe.mirai.event.nextEventAsync
|
|
||||||
import net.mamoe.mirai.message.data.ForwardMessageBuilder
|
|
||||||
import net.mamoe.mirai.message.data.PlainText
|
|
||||||
import net.mamoe.mirai.message.data.content
|
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
|
||||||
import java.lang.Exception
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
@OptIn(MiraiExperimentalApi::class)
|
|
||||||
object MinecraftService {
|
|
||||||
private val curseClient = CurseClient
|
|
||||||
|
|
||||||
private const val GAME_ID_MINECRAFT = 432
|
|
||||||
const val SECTION_ID_MODES = 6
|
|
||||||
const val SECTION_ID_RESOURCE_PACKS = 12
|
|
||||||
const val SECTION_ID_WORLDS = 17
|
|
||||||
const val SECTION_ID_MODE_PACKS = 4471
|
|
||||||
const val ALL = -1
|
|
||||||
|
|
||||||
private const val WAIT_REPLY_TIMEOUT_MS = 60000L
|
|
||||||
private const val PAGE_SIZE = 10
|
|
||||||
private const val NEXT_PAGE_KEYWORD = "n"
|
|
||||||
private const val SHOW_FILES_KEYWORD = "files"
|
|
||||||
|
|
||||||
suspend fun search(sender: UserCommandSender, sectionId: Int, filter: String) {
|
|
||||||
val addon: Addon
|
|
||||||
var pageIndex = 0
|
|
||||||
while (true) {
|
|
||||||
val searchResult = doSearch(sectionId, filter, pageIndex++, PAGE_SIZE)
|
|
||||||
val hasNextPage = searchResult.size == PAGE_SIZE
|
|
||||||
|
|
||||||
if (searchResult.isEmpty()) {
|
|
||||||
sender.sendMessage("未搜索到结果,请更换关键字重试。")
|
|
||||||
return
|
|
||||||
} else if (searchResult.size == 1) {
|
|
||||||
addon = searchResult[0]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
val builder = ForwardMessageBuilder(sender.subject)
|
|
||||||
builder.add(sender.bot, PlainText("${WAIT_REPLY_TIMEOUT_MS/1000}秒内回复编号查看"))
|
|
||||||
MessageHandler.parseSearchResult(searchResult, builder, sender.subject)
|
|
||||||
if (hasNextPage) builder.add(sender.bot, PlainText("回复[$NEXT_PAGE_KEYWORD]下一页"))
|
|
||||||
sender.sendMessage(builder.build())
|
|
||||||
|
|
||||||
try {
|
|
||||||
val nextEvent = sender.nextEventAsync<MessageEvent>(
|
|
||||||
WAIT_REPLY_TIMEOUT_MS,
|
|
||||||
coroutineContext = sender.coroutineContext
|
|
||||||
) { it.sender == sender.user } .await()
|
|
||||||
if (hasNextPage && nextEvent.message.contentEquals(NEXT_PAGE_KEYWORD, true))
|
|
||||||
continue
|
|
||||||
addon = searchResult[nextEvent.message.content.toInt()]
|
|
||||||
break
|
|
||||||
} catch (e: TimeoutCancellationException) {
|
|
||||||
sender.sendMessage("等待回复超时,请重新查询。")
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
sender.sendMessage("请正确回复序号,此次查询已取消,请重新查询。")
|
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
|
||||||
sender.sendMessage("请回复正确的序号,此次查询已取消,请重新查询。")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
sender.sendMessage("内部发生异常,此次查询已取消,请重新查询。")
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// addon handle
|
|
||||||
showAddon(sender, addon)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据项目ID搜索资源
|
|
||||||
*/
|
|
||||||
suspend fun searchAddonByProjectId(sender: UserCommandSender, projectId: Int) {
|
|
||||||
try {
|
|
||||||
val addon = curseClient.getAddon(projectId)
|
|
||||||
|
|
||||||
showAddon(sender, addon)
|
|
||||||
} catch (e: ClientRequestException) {
|
|
||||||
if (e.response.status == HttpStatusCode.NotFound) {
|
|
||||||
sender.sendMessage("未搜索到指定项目ID的资源,请使用正确的项目ID")
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("请求异常,错误代码:" + e.response.status)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
sender.sendMessage("内部发生异常,此次查询已取消,请重新查询。")
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun showAddon(sender: UserCommandSender, addon: Addon) {
|
|
||||||
val builder = MessageHandler.parseAddon(addon, sender.subject)
|
|
||||||
if (addon.latestFiles.isNotEmpty())
|
|
||||||
builder.add(sender.bot, PlainText("${WAIT_REPLY_TIMEOUT_MS/1000}秒内回复[${SHOW_FILES_KEYWORD}]查看所有文件,回复文件序号查看更新日志"))
|
|
||||||
sender.sendMessage(builder.build())
|
|
||||||
|
|
||||||
try {
|
|
||||||
val nextEvent = sender.nextEventAsync<MessageEvent>(
|
|
||||||
WAIT_REPLY_TIMEOUT_MS,
|
|
||||||
coroutineContext = sender.coroutineContext
|
|
||||||
) { it.sender == sender.user } .await()
|
|
||||||
if (nextEvent.message.contentEquals(SHOW_FILES_KEYWORD, true)) {
|
|
||||||
showAllFiles(sender, addon)
|
|
||||||
} else {
|
|
||||||
val file = addon.latestFiles[nextEvent.message.content.toInt()]
|
|
||||||
showChangedLog(sender, addon.id, file)
|
|
||||||
}
|
|
||||||
} catch (e: TimeoutCancellationException) {
|
|
||||||
sender.sendMessage("等待回复超时,请重新查询。")
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
sender.sendMessage("请正确回复序号,此次查询已取消,请重新查询。")
|
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
|
||||||
sender.sendMessage("请回复正确的序号,此次查询已取消,请重新查询。")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
sender.sendMessage("内部发生异常,此次查询已取消,请重新查询。")
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun showAllFiles(sender: UserCommandSender, addon: Addon) {
|
|
||||||
val files = CurseClient.getAddonFiles(addon.id).sortedByDescending { f -> f.fileDate }
|
|
||||||
if (files.isEmpty()) {
|
|
||||||
sender.sendMessage("没有任何文件 :(")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val builder = ForwardMessageBuilder(sender.subject)
|
|
||||||
builder.add(sender.bot, PlainText("${WAIT_REPLY_TIMEOUT_MS/1000}秒内回复文件序号查看更新日志"))
|
|
||||||
MessageHandler.parseAddonFiles(files, builder, sender.subject)
|
|
||||||
sender.sendMessage(builder.build())
|
|
||||||
|
|
||||||
try { // cv大法好,回复功能有功夫再封装,先复制粘贴用着 XD
|
|
||||||
val nextEvent = sender.nextEventAsync<MessageEvent>(
|
|
||||||
WAIT_REPLY_TIMEOUT_MS,
|
|
||||||
coroutineContext = sender.coroutineContext
|
|
||||||
) { it.sender == sender.user } .await()
|
|
||||||
val file = files[nextEvent.message.content.toInt()]
|
|
||||||
showChangedLog(sender, addon.id, file)
|
|
||||||
} catch (e: TimeoutCancellationException) {
|
|
||||||
sender.sendMessage("等待回复超时,请重新查询。")
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
sender.sendMessage("请正确回复序号,此次查询已取消,请重新查询。")
|
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
|
||||||
sender.sendMessage("请回复正确的序号,此次查询已取消,请重新查询。")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val HTMLPattern = Pattern.compile("<[^>]+>", Pattern.CASE_INSENSITIVE)
|
|
||||||
private suspend fun showChangedLog(sender: UserCommandSender, addonId: Int, addonFile: AddonFile) {
|
|
||||||
val changeLogHTML = curseClient.getAddonFileChangeLog(addonId, addonFile.id)
|
|
||||||
val changeLog = HTMLPattern.matcher(changeLogHTML).replaceAll("")
|
|
||||||
MessageHandler.sendLargeMessage(sender.subject, changeLog)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun doSearch(sectionId: Int, filter: String, pageIndex: Int, pageSize: Int): List<Addon> {
|
|
||||||
return curseClient.searchAddons(
|
|
||||||
gameId = GAME_ID_MINECRAFT,
|
|
||||||
sectionId = sectionId,
|
|
||||||
categoryId = -1,
|
|
||||||
sort = AddonSortMethod.POPULARITY,
|
|
||||||
sortDescending = true,
|
|
||||||
gameVersion = null,
|
|
||||||
index = pageIndex * pageSize,
|
|
||||||
pageSize = pageSize,
|
|
||||||
searchFilter = filter,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFile
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFileLatestForGameVersion
|
|
||||||
import me.jie65535.jcf.model.category.CategorySection
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Addon(
|
|
||||||
val id: Int,
|
|
||||||
val name: String,
|
|
||||||
val authors: List<AddonAuthor>,
|
|
||||||
val attachments: List<AddonAttachment>,
|
|
||||||
val websiteUrl: String,
|
|
||||||
val gameId: Int,
|
|
||||||
val summary: String,
|
|
||||||
val defaultFileId: Int,
|
|
||||||
val downloadCount: Double,
|
|
||||||
val latestFiles: List<AddonFile>,
|
|
||||||
val categories: List<AddonCategory>,
|
|
||||||
val status: AddonStatus,
|
|
||||||
val primaryCategoryId: Int,
|
|
||||||
val categorySection: CategorySection,
|
|
||||||
val slug: String,
|
|
||||||
val gameVersionLatestFiles: List<AddonFileLatestForGameVersion>,
|
|
||||||
val isFeatured: Boolean,
|
|
||||||
val popularityScore: Double,
|
|
||||||
val gamePopularityRank: Int,
|
|
||||||
val primaryLanguage: String,
|
|
||||||
val gameSlug: String,
|
|
||||||
val gameName: String,
|
|
||||||
val portalName: String,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateModified: Date,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateCreated: Date,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateReleased: Date,
|
|
||||||
val isAvailable: Boolean,
|
|
||||||
@SerialName("isExperiemental")
|
|
||||||
val isExperimental: Boolean
|
|
||||||
)
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonAttachment(
|
|
||||||
val id: Int,
|
|
||||||
val projectId: Int,
|
|
||||||
val description: String,
|
|
||||||
val isDefault: Boolean,
|
|
||||||
val thumbnailUrl: String,
|
|
||||||
val title: String,
|
|
||||||
val url: String,
|
|
||||||
val status: AddonAttachmentStatus
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
|
|
||||||
@Serializable(with = AddonAttachmentStatus.Ser::class)
|
|
||||||
enum class AddonAttachmentStatus {
|
|
||||||
NORMAL,
|
|
||||||
DELETED,
|
|
||||||
UPLOADING,
|
|
||||||
BANNED,
|
|
||||||
PENDING_MODERATION;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonAttachmentStatus>("$MODEL_PACKAGE.addon.AttachmentStatus", values())
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonAuthor(
|
|
||||||
val name: String,
|
|
||||||
val url: String,
|
|
||||||
val projectId: Int,
|
|
||||||
val id: Int,
|
|
||||||
val projectTitleId: Int?,
|
|
||||||
val projectTitleTitle: String?,
|
|
||||||
val userId: Int,
|
|
||||||
val twitchId: Int?
|
|
||||||
)
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonCategory(
|
|
||||||
val categoryId: Int,
|
|
||||||
val name: String,
|
|
||||||
val url: String,
|
|
||||||
val avatarUrl: String?,
|
|
||||||
val parentId: Int?,
|
|
||||||
val rootId: Int?,
|
|
||||||
val projectId: Int,
|
|
||||||
val avatarId: Int?,
|
|
||||||
val gameId: Int
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonPackageType.Ser::class)
|
|
||||||
enum class AddonPackageType {
|
|
||||||
FOLDER,
|
|
||||||
CTOC,
|
|
||||||
SINGLE_FILE,
|
|
||||||
CMOD2,
|
|
||||||
MOD_PACK,
|
|
||||||
MOD;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonPackageType>("$MODEL_PACKAGE.addon.AddonPackageType", values())
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFile
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonRepositoryMatch(
|
|
||||||
val id: Int,
|
|
||||||
val latestFiles: List<AddonFile>
|
|
||||||
)
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonRestrictFileAccess.Ser::class)
|
|
||||||
enum class AddonRestrictFileAccess {
|
|
||||||
NONE,
|
|
||||||
ALPHA,
|
|
||||||
ALPHA_AND_BETA;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonRestrictFileAccess>("$MODEL_PACKAGE.addon.AddonRestrictFileAccess", values())
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 附加排序方法
|
|
||||||
*/
|
|
||||||
enum class AddonSortMethod {
|
|
||||||
/**
|
|
||||||
* 精选
|
|
||||||
*/
|
|
||||||
FEATURED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人气
|
|
||||||
*/
|
|
||||||
POPULARITY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最后更新时间
|
|
||||||
*/
|
|
||||||
LAST_UPDATED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 名称
|
|
||||||
*/
|
|
||||||
NAME,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 作者
|
|
||||||
*/
|
|
||||||
AUTHOR,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总下载数
|
|
||||||
*/
|
|
||||||
TOTAL_DOWNLOADS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类别
|
|
||||||
*/
|
|
||||||
CATEGORY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 游戏版本
|
|
||||||
*/
|
|
||||||
GAME_VERSION
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonStatus.Ser::class)
|
|
||||||
enum class AddonStatus {
|
|
||||||
NEW,
|
|
||||||
CHANGES_REQUIRED,
|
|
||||||
UNDER_SOFT_REVIEW,
|
|
||||||
APPROVED,
|
|
||||||
REJECTED,
|
|
||||||
CHANGES_MADE,
|
|
||||||
INACTIVE,
|
|
||||||
ABANDONED,
|
|
||||||
DELETED,
|
|
||||||
UNDER_REVIEW;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonStatus>("$MODEL_PACKAGE.addon.AddonStatus", values())
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
enum class FeaturedAddonType {
|
|
||||||
@SerialName("Featured")
|
|
||||||
FEATURED,
|
|
||||||
@SerialName("Popular")
|
|
||||||
POPULAR,
|
|
||||||
@SerialName("RecentlyUpdated")
|
|
||||||
RECENTLY_UPDATED;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SortableGameVersion(
|
|
||||||
val gameVersionPadded: String,
|
|
||||||
val gameVersion: String,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val gameVersionReleaseDate: Date,
|
|
||||||
val gameVersionName: String
|
|
||||||
)
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.addon.AddonPackageType
|
|
||||||
import me.jie65535.jcf.model.addon.AddonRestrictFileAccess
|
|
||||||
import me.jie65535.jcf.model.addon.AddonStatus
|
|
||||||
import me.jie65535.jcf.model.addon.SortableGameVersion
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonFile(
|
|
||||||
val id: Int,
|
|
||||||
val displayName: String,
|
|
||||||
val fileName: String,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val fileDate: Date,
|
|
||||||
val fileLength: Long,
|
|
||||||
val releaseType: AddonFileReleaseType,
|
|
||||||
val fileStatus: AddonFileStatus,
|
|
||||||
val downloadUrl: String,
|
|
||||||
val isAlternate: Boolean,
|
|
||||||
val alternateFileId: Int,
|
|
||||||
val dependencies: List<AddonFileDependency>,
|
|
||||||
val isAvailable: Boolean,
|
|
||||||
val modules: List<AddonFileModule>,
|
|
||||||
val packageFingerprint: Long,
|
|
||||||
val gameVersion: List<String>,
|
|
||||||
val sortableGameVersion: List<SortableGameVersion>? = null,
|
|
||||||
val installMetadata: String?,
|
|
||||||
val changelog: String? = null,
|
|
||||||
val hasInstallScript: Boolean,
|
|
||||||
val isCompatibleWithClient: Boolean? = null,
|
|
||||||
val categorySectionPackageType: AddonPackageType? = null,
|
|
||||||
val restrictProjectFileAccess: AddonRestrictFileAccess? = null,
|
|
||||||
val projectStatus: AddonStatus? = null,
|
|
||||||
val renderCacheId: Int? = null,
|
|
||||||
val fileLegacyMappingId: Int? = null,
|
|
||||||
val projectId: Int? = null,
|
|
||||||
val parentProjectFileId: Int? = null,
|
|
||||||
val parentFileLegacyMappingId: Int? = null,
|
|
||||||
val fileTypeId: Int? = null,
|
|
||||||
val exposeAsAlternative: Boolean? = null,
|
|
||||||
val packageFingerprintId: Int? = null,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val gameVersionDateReleased: Date?,
|
|
||||||
val gameVersionMappingId: Int? = null,
|
|
||||||
val gameVersionId: Int? = null,
|
|
||||||
val gameId: Int? = null,
|
|
||||||
val isServerPack: Boolean = false,
|
|
||||||
val serverPackFileId: Int?,
|
|
||||||
val gameVersionFlavor: String?
|
|
||||||
)
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonFileDependency(
|
|
||||||
val id: Int? = null,
|
|
||||||
val addonId: Int,
|
|
||||||
val type: AddonFileRelationType,
|
|
||||||
val fileId: Int? = null
|
|
||||||
)
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonFileFingerprintType.Ser::class)
|
|
||||||
enum class AddonFileFingerprintType {
|
|
||||||
PACKAGE,
|
|
||||||
MODULE,
|
|
||||||
MAIN_MODULE,
|
|
||||||
FILE,
|
|
||||||
REFERRENCED_FILE;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonFileFingerprintType>("$MODEL_PACKAGE.addon.file.AddonFileFingerprintType", values())
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonFileLatestForGameVersion(
|
|
||||||
val gameVersion: String,
|
|
||||||
val projectFileId: Int,
|
|
||||||
val projectFileName: String,
|
|
||||||
val fileType: AddonFileReleaseType,
|
|
||||||
val gameVersionFlavor: String?
|
|
||||||
)
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AddonFileModule(
|
|
||||||
@SerialName("foldername")
|
|
||||||
val folderName: String,
|
|
||||||
val fingerprint: Long,
|
|
||||||
val type: AddonFileFingerprintType? = null
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonFileRelationType.Ser::class)
|
|
||||||
enum class AddonFileRelationType {
|
|
||||||
EMBEDDED_LIBRARY,
|
|
||||||
OPTIONAL_DEPENDENCY,
|
|
||||||
REQUIRED_DEPENDENCY,
|
|
||||||
TOOL,
|
|
||||||
INCOMPATIBLE,
|
|
||||||
INCLUDE;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonFileRelationType>("$MODEL_PACKAGE.addon.file.AddonFileRelationType", values())
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonFileReleaseType.Ser::class)
|
|
||||||
enum class AddonFileReleaseType {
|
|
||||||
RELEASE,
|
|
||||||
BETA,
|
|
||||||
ALPHA;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonFileReleaseType>("$MODEL_PACKAGE.addon.file.AddonFileReleaseType", values())
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.addon.file
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = AddonFileStatus.Ser::class)
|
|
||||||
enum class AddonFileStatus {
|
|
||||||
PROCESSING,
|
|
||||||
CHANGES_REQUIRED,
|
|
||||||
UNDER_REVIEW,
|
|
||||||
APPROVED,
|
|
||||||
REJECTED,
|
|
||||||
MALWARE_DETECTED,
|
|
||||||
DELETED,
|
|
||||||
ARCHIVED,
|
|
||||||
TESTING,
|
|
||||||
RELEASED,
|
|
||||||
READY_FOR_REVIEW,
|
|
||||||
DEPRECATED,
|
|
||||||
BAKING,
|
|
||||||
AWAITING_FOR_PUBLISHING,
|
|
||||||
FAILED_PUBLISHING;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<AddonFileStatus>("$MODEL_PACKAGE.addon.file.AddonFileStatus", values())
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
package me.jie65535.jcf.model.addon.request
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class FeaturedAddonsRequest(
|
|
||||||
val gameId: Int,
|
|
||||||
val featuredCount: Int,
|
|
||||||
val popularCount: Int,
|
|
||||||
val updatedCount: Int,
|
|
||||||
val excludedAddons: Collection<Int>
|
|
||||||
)
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.category
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Category(
|
|
||||||
val id: Int,
|
|
||||||
val name: String,
|
|
||||||
val slug: String,
|
|
||||||
val avatarUrl: String?,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateModified: Date,
|
|
||||||
val parentGameCategoryId: Int?,
|
|
||||||
val rootGameCategoryId: Int?,
|
|
||||||
val gameId: Int
|
|
||||||
)
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.category
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.addon.AddonPackageType
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CategorySection(
|
|
||||||
val extraIncludePattern: String?,
|
|
||||||
val gameCategoryId: Int,
|
|
||||||
val gameId: Int,
|
|
||||||
val id: Int,
|
|
||||||
val initialInclusionPattern: String,
|
|
||||||
val name: String,
|
|
||||||
val packageType: AddonPackageType,
|
|
||||||
val path: String
|
|
||||||
)
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.fingerprint
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFile
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class FingerprintMatch(
|
|
||||||
val id: Int,
|
|
||||||
val file: AddonFile,
|
|
||||||
val latestFiles: List<AddonFile>
|
|
||||||
)
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.fingerprint
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class FingerprintMatchResult(
|
|
||||||
val isCacheBuilt: Boolean,
|
|
||||||
val exactMatches: List<FingerprintMatch>,
|
|
||||||
val exactFingerprints: List<Long>,
|
|
||||||
val partialMatches: List<FingerprintMatch>,
|
|
||||||
val partialMatchFingerprints: Map<String, List<Long>>,
|
|
||||||
val installedFingerprints: List<Long>,
|
|
||||||
val unmatchedFingerprints: List<Long>
|
|
||||||
)
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.fingerprint
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class FolderFingerprint(
|
|
||||||
@SerialName("foldername")
|
|
||||||
val folderName: String,
|
|
||||||
val fingerprints: List<Long>
|
|
||||||
)
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.fingerprint
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.addon.file.AddonFile
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class FuzzyFingerprintMatch(
|
|
||||||
val id: Int,
|
|
||||||
val file: AddonFile,
|
|
||||||
val latestFiles: List<AddonFile>,
|
|
||||||
val fingerprints: List<Long>
|
|
||||||
)
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.fingerprint.request
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.fingerprint.FolderFingerprint
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class FuzzyMatchesRequest(
|
|
||||||
val gameId: Int,
|
|
||||||
val fingerprints: List<FolderFingerprint>
|
|
||||||
)
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.category.CategorySection
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Game(
|
|
||||||
val id: Int,
|
|
||||||
val name: String,
|
|
||||||
val slug: String,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateModified: Date,
|
|
||||||
val gameFiles: List<GameFile>,
|
|
||||||
val gameDetectionHints: List<GameDetectionHint>,
|
|
||||||
val fileParsingRules: List<GameFileParsingRule>,
|
|
||||||
val categorySections: List<CategorySection>,
|
|
||||||
val maxFreeStorage: Long,
|
|
||||||
val maxPremiumStorage: Long,
|
|
||||||
val maxFileSize: Long,
|
|
||||||
val addonSettingsFolderFilter: String?,
|
|
||||||
val addonSettingsStartingFolder: String?,
|
|
||||||
val addonSettingsFileFilter: String?,
|
|
||||||
val addonSettingsFileRemovalFilter: String?,
|
|
||||||
val supportsAddons: Boolean,
|
|
||||||
val supportsPartnerAddons: Boolean,
|
|
||||||
@Serializable(with = SupportedClientConfiguration.Ser::class)
|
|
||||||
val supportedClientConfiguration: Set<SupportedClientConfiguration>,
|
|
||||||
val supportsNotifications: Boolean,
|
|
||||||
val profilerAddonId: Int,
|
|
||||||
val twitchGameId: Int,
|
|
||||||
val clientGameSettingsId: Int
|
|
||||||
)
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class GameDetectionHint(
|
|
||||||
val id: Int,
|
|
||||||
val hintType: GameDetectionHintType,
|
|
||||||
val hintPath: String,
|
|
||||||
val hintKey: String?,
|
|
||||||
@Serializable(with = GameDetectionHintOption.Ser::class)
|
|
||||||
val hintOptions: Set<GameDetectionHintOption>,
|
|
||||||
val gameId: Int
|
|
||||||
)
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import me.jie65535.jcf.util.internal.FlagSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
enum class GameDetectionHintOption {
|
|
||||||
NONE,
|
|
||||||
INCLUDE_SUB_FOLDERS,
|
|
||||||
FOLDER_ONLY;
|
|
||||||
|
|
||||||
internal object Ser : FlagSerializer<GameDetectionHintOption>("$MODEL_PACKAGE.game.GameDetectionHintOption", NONE to 0x1, INCLUDE_SUB_FOLDERS to 0x2, FOLDER_ONLY to 0x4)
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = GameDetectionHintType.Ser::class)
|
|
||||||
enum class GameDetectionHintType {
|
|
||||||
REGISTRY,
|
|
||||||
FILE_PATH;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<GameDetectionHintType>("$MODEL_PACKAGE.game.GameDetectionHintType", values())
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class GameFile(
|
|
||||||
val id: Int,
|
|
||||||
val gameId: Int,
|
|
||||||
val isRequired: Boolean,
|
|
||||||
val fileName: String,
|
|
||||||
val fileType: GameFileType,
|
|
||||||
val platformType: GamePlatformType
|
|
||||||
)
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class GameFileParsingRule(
|
|
||||||
val commentStripPattern: String,
|
|
||||||
val fileExtension: String,
|
|
||||||
val inclusionPattern: String,
|
|
||||||
val gameId: Int,
|
|
||||||
val id: Int
|
|
||||||
)
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = GameFileType.Ser::class)
|
|
||||||
enum class GameFileType {
|
|
||||||
GENERIC,
|
|
||||||
GAME,
|
|
||||||
LAUNCHER,
|
|
||||||
PROFILER_LOCK_CHECK;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<GameFileType>("$MODEL_PACKAGE.game.GameFileType", values())
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = GamePlatformType.Ser::class)
|
|
||||||
enum class GamePlatformType {
|
|
||||||
GENERIC,
|
|
||||||
WINDOWS_32,
|
|
||||||
WINDOWS_64,
|
|
||||||
WINDOWS,
|
|
||||||
OSX;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<GamePlatformType>("$MODEL_PACKAGE.game.GamePlatformType", values())
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.game
|
|
||||||
|
|
||||||
import me.jie65535.jcf.util.internal.FlagSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
enum class SupportedClientConfiguration {
|
|
||||||
DEBUG,
|
|
||||||
BETA,
|
|
||||||
RELEASE;
|
|
||||||
|
|
||||||
internal object Ser : FlagSerializer<SupportedClientConfiguration>("$MODEL_PACKAGE.game.SupportedClientConfiguration", DEBUG to 0x1, BETA to 0x2, RELEASE to 0x4)
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class MinecraftVersion(
|
|
||||||
val id: Int,
|
|
||||||
val gameVersionId: Int,
|
|
||||||
val versionString: String,
|
|
||||||
val jarDownloadUrl: String,
|
|
||||||
val jsonDownloadUrl: String,
|
|
||||||
val approved: Boolean,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateModified: Date,
|
|
||||||
val gameVersionTypeId: Int,
|
|
||||||
val gameVersionStatus: MinecraftVersionStatus,
|
|
||||||
val gameVersionTypeStatus: MinecraftVersionTypeStatus
|
|
||||||
)
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = MinecraftVersionStatus.Ser::class)
|
|
||||||
enum class MinecraftVersionStatus {
|
|
||||||
APPROVED,
|
|
||||||
DELETED,
|
|
||||||
NEW;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<MinecraftVersionStatus>("$MODEL_PACKAGE.game.MinecraftVersionStatus", values())
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = MinecraftVersionTypeStatus.Ser::class)
|
|
||||||
enum class MinecraftVersionTypeStatus {
|
|
||||||
NORMAL,
|
|
||||||
DELETED;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<MinecraftVersionTypeStatus>("$MODEL_PACKAGE.game.MinecraftVersionTypeStatus", values())
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft.modloader
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ModloaderIndex(
|
|
||||||
val name: String,
|
|
||||||
val gameVersion: String,
|
|
||||||
val latest: Boolean,
|
|
||||||
val recommended: Boolean,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateModified: Date
|
|
||||||
)
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft.modloader
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = ModloaderInstallMethod.Ser::class)
|
|
||||||
enum class ModloaderInstallMethod {
|
|
||||||
ANY,
|
|
||||||
FORGE,
|
|
||||||
CAULDRON,
|
|
||||||
LITE_LOADER;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<ModloaderInstallMethod>("$MODEL_PACKAGE.game.ModloaderInstallMethod", values())
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft.modloader
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.util.internal.EnumIntSerializer
|
|
||||||
import me.jie65535.jcf.util.internal.MODEL_PACKAGE
|
|
||||||
|
|
||||||
@Serializable(with = ModloaderType.Ser::class)
|
|
||||||
enum class ModloaderType {
|
|
||||||
ANY,
|
|
||||||
FORGE,
|
|
||||||
CAULDRON,
|
|
||||||
LITE_LOADER;
|
|
||||||
|
|
||||||
internal object Ser : EnumIntSerializer<ModloaderType>("$MODEL_PACKAGE.game.ModloaderType", values(), 0)
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.model.minecraft.modloader
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import me.jie65535.jcf.model.minecraft.MinecraftVersionStatus
|
|
||||||
import me.jie65535.jcf.model.minecraft.MinecraftVersionTypeStatus
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import me.jie65535.jcf.util.internal.DateSerializer
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ModloaderVersion(
|
|
||||||
val id: Int,
|
|
||||||
val gameVersionId: Int,
|
|
||||||
val minecraftGameVersionId: Int,
|
|
||||||
val forgeVersion: String,
|
|
||||||
val name: String,
|
|
||||||
val type: ModloaderType,
|
|
||||||
val downloadUrl: String,
|
|
||||||
@SerialName("filename")
|
|
||||||
val fileName: String,
|
|
||||||
val installMethod: ModloaderInstallMethod,
|
|
||||||
val latest: Boolean,
|
|
||||||
val recommended: Boolean,
|
|
||||||
val approved: Boolean,
|
|
||||||
@Serializable(with = DateSerializer::class)
|
|
||||||
val dateModified: Date,
|
|
||||||
val mavenVersionString: String,
|
|
||||||
val versionJson: String,
|
|
||||||
val librariesInstallLocation: String,
|
|
||||||
val minecraftVersion: String,
|
|
||||||
val additionalFilesJson: String,
|
|
||||||
val modLoaderGameVersionId: Int,
|
|
||||||
val modLoaderGameVersionTypeId: Int,
|
|
||||||
val modLoaderGameVersionStatus: MinecraftVersionStatus,
|
|
||||||
val modLoaderGameVersionTypeStatus: MinecraftVersionTypeStatus,
|
|
||||||
val mcGameVersionId: Int,
|
|
||||||
val mcGameVersionTypeId: Int,
|
|
||||||
val mcGameVersionStatus: MinecraftVersionStatus,
|
|
||||||
val mcGameVersionTypeStatus: MinecraftVersionTypeStatus,
|
|
||||||
val installProfileJson: String
|
|
||||||
)
|
|
@ -1,5 +0,0 @@
|
|||||||
package me.jie65535.jcf.util
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime
|
|
||||||
|
|
||||||
typealias Date = OffsetDateTime
|
|
@ -1,29 +0,0 @@
|
|||||||
package me.jie65535.jcf.util
|
|
||||||
|
|
||||||
//import okhttp3.MediaType
|
|
||||||
//import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import java.io.File
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
object HttpUtil {
|
|
||||||
// private val JSON: MediaType? = "application/json; charset=utf-8".toMediaTypeOrNull()
|
|
||||||
private val okHttpClient: OkHttpClient by lazy {
|
|
||||||
OkHttpClient.Builder()
|
|
||||||
.readTimeout(10, TimeUnit.SECONDS)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ### 下载图片
|
|
||||||
*/
|
|
||||||
fun downloadImage(url: String, file: File): ByteArray {
|
|
||||||
val request = Request.Builder().url(url).build()
|
|
||||||
val imageByte = okHttpClient.newCall(request).execute().body!!.bytes()
|
|
||||||
val fileParent = file.parentFile
|
|
||||||
if (!fileParent.exists()) fileParent.mkdirs()
|
|
||||||
file.writeBytes(imageByte)
|
|
||||||
return imageByte
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.util.internal
|
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
|
||||||
import kotlinx.serialization.descriptors.*
|
|
||||||
import kotlinx.serialization.encoding.*
|
|
||||||
import me.jie65535.jcf.util.Date
|
|
||||||
import java.time.OffsetDateTime
|
|
||||||
|
|
||||||
internal object DateSerializer : KSerializer<Date> {
|
|
||||||
override val descriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Date {
|
|
||||||
return OffsetDateTime.parse(decoder.decodeString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: Date) {
|
|
||||||
encoder.encodeString(value.toString())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.util.internal
|
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
|
||||||
import kotlinx.serialization.descriptors.*
|
|
||||||
import kotlinx.serialization.encoding.*
|
|
||||||
|
|
||||||
internal open class EnumIntSerializer<T>(private val serialName: String, private val values: Array<T>, private val startFrom: Int = 1) : KSerializer<T> {
|
|
||||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(serialName, PrimitiveKind.INT)
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): T {
|
|
||||||
val value = decoder.decodeInt()
|
|
||||||
return values[value - startFrom] ?: throw NoSuchElementException("Can't find $serialName with key $value")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: T) {
|
|
||||||
encoder.encodeInt(values.indexOf(value) + startFrom)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2020, PearX Team
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.jie65535.jcf.util.internal
|
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
|
||||||
import kotlinx.serialization.descriptors.*
|
|
||||||
import kotlinx.serialization.encoding.*
|
|
||||||
|
|
||||||
internal open class FlagSerializer<T : Enum<T>>(serialName: String, private val map: Map<T, Int>) : KSerializer<Set<T>> {
|
|
||||||
constructor(serialName: String, vararg pairs: Pair<T, Int>) : this(serialName, mapOf(*pairs))
|
|
||||||
|
|
||||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(serialName, PrimitiveKind.INT)
|
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: Set<T>) {
|
|
||||||
var bits = 0
|
|
||||||
for(flag in value) {
|
|
||||||
bits = bits or (map[flag] ?: error(""))
|
|
||||||
}
|
|
||||||
encoder.encodeInt(bits)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Set<T> {
|
|
||||||
val set = mutableSetOf<T>()
|
|
||||||
val bits = decoder.decodeInt()
|
|
||||||
for((flag, shift) in map) {
|
|
||||||
if(bits and shift == shift)
|
|
||||||
set += flag
|
|
||||||
}
|
|
||||||
return set
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
package me.jie65535.jcf.util.internal
|
|
||||||
|
|
||||||
internal const val MODEL_PACKAGE = "me.jie65535.jcf.model"
|
|
@ -22,9 +22,6 @@ import top.jie65535.jcf.model.response.*
|
|||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
class CurseforgeApi(apiKey: String) {
|
class CurseforgeApi(apiKey: String) {
|
||||||
companion object {
|
|
||||||
private const val GAME_ID_MINECRAFT = 432
|
|
||||||
}
|
|
||||||
|
|
||||||
private val json = Json {
|
private val json = Json {
|
||||||
isLenient = true
|
isLenient = true
|
||||||
@ -34,9 +31,9 @@ class CurseforgeApi(apiKey: String) {
|
|||||||
|
|
||||||
private val http = HttpClient(OkHttp) {
|
private val http = HttpClient(OkHttp) {
|
||||||
install(HttpTimeout) {
|
install(HttpTimeout) {
|
||||||
this.requestTimeoutMillis = 30_0000
|
this.requestTimeoutMillis = 300_000
|
||||||
this.connectTimeoutMillis = 30_0000
|
this.connectTimeoutMillis = 300_000
|
||||||
this.socketTimeoutMillis = 30_0000
|
this.socketTimeoutMillis = 300_000
|
||||||
}
|
}
|
||||||
defaultRequest {
|
defaultRequest {
|
||||||
url.protocol = URLProtocol.HTTPS
|
url.protocol = URLProtocol.HTTPS
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package top.jie65535.jcf
|
package top.jie65535.jcf
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.withContext
|
import net.mamoe.mirai.event.*
|
||||||
import net.mamoe.mirai.event.Event
|
|
||||||
import net.mamoe.mirai.event.EventChannel
|
|
||||||
import net.mamoe.mirai.event.events.MessageEvent
|
import net.mamoe.mirai.event.events.MessageEvent
|
||||||
import net.mamoe.mirai.event.subscribeMessages
|
|
||||||
import net.mamoe.mirai.message.data.*
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.message.data.MessageSource.Key.quote
|
import net.mamoe.mirai.message.data.MessageSource.Key.quote
|
||||||
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
|
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
|
||||||
@ -35,14 +32,15 @@ class MessageHandler(
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
val pagedList = service.search(modClass, filter)
|
val pagedList = service.search(modClass, filter)
|
||||||
val msg = with(pagedList.current()) {
|
with(pagedList.current()) {
|
||||||
if (size == 1) {
|
if (isEmpty()) {
|
||||||
|
subject.sendMessage("未搜索到关键字\"$filter\"相关结果")
|
||||||
|
} else if (size == 1) {
|
||||||
handleShowMod(get(0))
|
handleShowMod(get(0))
|
||||||
} else {
|
} else {
|
||||||
handleModsSearchResult(pagedList)
|
handleModsSearchResult(pagedList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subject.sendMessage(msg)
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
subject.sendMessage(message.quote() + "发生内部错误,请稍后重试")
|
subject.sendMessage(message.quote() + "发生内部错误,请稍后重试")
|
||||||
logger.error("消息\"$message\"引发异常", e)
|
logger.error("消息\"$message\"引发异常", e)
|
||||||
@ -53,37 +51,79 @@ class MessageHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理分页列表选择功能,返回用户选中项,返回null表示未选中任何项
|
||||||
|
* @param pagedList 分页的列表
|
||||||
|
* @param format 格式化方法
|
||||||
|
* @return 用户选中项,null表示未选择任何项
|
||||||
|
*/
|
||||||
|
private suspend fun <T> MessageEvent.handlePagedList(pagedList: PagedList<T>, format: (T)->Message): T? {
|
||||||
|
do {
|
||||||
|
var isContinue = false
|
||||||
|
val list = pagedList.current()
|
||||||
|
val listMessage = subject.sendMessage(buildForwardMessage {
|
||||||
|
for ((i, it) in list.withIndex()) {
|
||||||
|
bot.id named i.toString() says format(it)
|
||||||
|
}
|
||||||
|
var msg = "$WAIT_REPLY_TIMEOUT_S 秒内回复编号查看"
|
||||||
|
if (pagedList.hasPrev)
|
||||||
|
msg += "\n回复 $PAGE_UP_KEYWORD 上一页"
|
||||||
|
if (pagedList.hasNext)
|
||||||
|
msg += "\n回复 $PAGE_DOWN_KEYWORD 下一页"
|
||||||
|
bot says msg
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
// 获取用户回复
|
||||||
|
val next = withTimeout(WAIT_REPLY_TIMEOUT_S * 1000L) {
|
||||||
|
eventChannel.nextEvent<MessageEvent>(EventPriority.MONITOR) { it.sender == sender }
|
||||||
|
}
|
||||||
|
val nextMessage = next.message.content
|
||||||
|
if (nextMessage.equals(PAGE_DOWN_KEYWORD, true)) {
|
||||||
|
pagedList.next()
|
||||||
|
} else if (nextMessage.equals(PAGE_UP_KEYWORD, true)) {
|
||||||
|
pagedList.prev()
|
||||||
|
} else {
|
||||||
|
return list[nextMessage.toInt()]
|
||||||
|
}
|
||||||
|
isContinue = true
|
||||||
|
} catch (e: TimeoutCancellationException) {
|
||||||
|
sender.sendMessage("等待回复超时,请重新查询。")
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
sender.sendMessage("请回复正确的选项,此次查询已取消,请重新查询。")
|
||||||
|
} catch (e: IndexOutOfBoundsException) {
|
||||||
|
sender.sendMessage("请回复正确的序号,此次查询已取消,请重新查询。")
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
subject.sendMessage(message.quote() + "发生内部错误,请稍后重试")
|
||||||
|
logger.warning("回复消息\"$message\"引发意外的异常", e)
|
||||||
|
} finally {
|
||||||
|
listMessage.recall()
|
||||||
|
}
|
||||||
|
} while (isContinue)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理mod搜索结果
|
* 处理mod搜索结果
|
||||||
*/
|
*/
|
||||||
private suspend fun MessageEvent.handleModsSearchResult(pagedList: PagedList<Mod>): Message {
|
private suspend fun MessageEvent.handleModsSearchResult(pagedList: PagedList<Mod>) {
|
||||||
val list = pagedList.current() // mod list
|
val selectedMod = handlePagedList(pagedList) { mod ->
|
||||||
val hasNext = pagedList.hasNext // 是否有下一页
|
PlainText(
|
||||||
val hasPrev = pagedList.hasPrev // 是否有上一页
|
|
||||||
return buildForwardMessage {
|
|
||||||
bot says "30秒内回复编号查看"
|
|
||||||
for ((x, mod) in list.withIndex()) {
|
|
||||||
bot.id named x.toString() says PlainText(
|
|
||||||
"""
|
"""
|
||||||
[${mod.name}] by ${mod.authors[0].name}
|
[${mod.name}] by ${mod.authors[0].name}
|
||||||
${formatCount(mod.downloadCount)} Downloads Updated ${mod.dateModified.toLocalDate()}
|
${formatCount(mod.downloadCount)} Downloads Updated ${mod.dateModified.toLocalDate()}
|
||||||
${mod.summary}
|
${mod.summary}
|
||||||
${mod.links.websiteUrl}
|
${mod.links.websiteUrl}
|
||||||
""".trimIndent()
|
""".trimIndent())
|
||||||
)
|
|
||||||
}
|
|
||||||
var tmp = "回复:"
|
|
||||||
if (hasPrev) tmp += "[P]上一页 "
|
|
||||||
if (hasNext) tmp += "[N]下一页"
|
|
||||||
bot says tmp
|
|
||||||
}
|
}
|
||||||
|
selectedMod?.let { handleShowMod(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理展示单个mod
|
* 处理展示单个mod
|
||||||
*/
|
*/
|
||||||
private suspend fun MessageEvent.handleShowMod(mod: Mod): Message {
|
private suspend fun MessageEvent.handleShowMod(mod: Mod) {
|
||||||
return buildForwardMessage {
|
subject.sendMessage(
|
||||||
|
buildForwardMessage {
|
||||||
// logo
|
// logo
|
||||||
mod.logo.thumbnailUrl?.let {
|
mod.logo.thumbnailUrl?.let {
|
||||||
if (it.isNotBlank()) bot says loadImage(it)
|
if (it.isNotBlank()) bot says loadImage(it)
|
||||||
@ -92,47 +132,79 @@ class MessageHandler(
|
|||||||
bot says PlainText(with(mod) {
|
bot says PlainText(with(mod) {
|
||||||
"""
|
"""
|
||||||
$name
|
$name
|
||||||
作者:${authors[0].name}
|
作者:${authors.joinToString { it.name }}
|
||||||
概括:$summary
|
概括:$summary
|
||||||
项目ID:$id
|
项目ID:$id
|
||||||
创建时间:${dateCreated.toLocalDate()}
|
创建时间:${dateCreated.toLocalDate()}
|
||||||
最近更新:${dateModified.toLocalDate()}
|
最近更新:${dateModified.toLocalDate()}
|
||||||
总下载:$downloadCount
|
总下载:$downloadCount
|
||||||
|
主页:${mod.links.websiteUrl}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
})
|
})
|
||||||
// links
|
var msg = "$WAIT_REPLY_TIMEOUT_S 秒内回复 $SUBSCRIBE_KEYWORD 订阅模组更新(TODO)"
|
||||||
bot says PlainText(with(mod.links) {
|
if (mod.latestFiles.isNotEmpty()) {
|
||||||
"""
|
msg += "\n回复编号查看文件详细信息\n" +
|
||||||
主页:$websiteUrl
|
"回复 $VIEW_FILES_KEYWORD 查看全部历史文件"
|
||||||
支持页:$issuesUrl
|
|
||||||
wiki:$wikiUrl
|
|
||||||
开源页:$sourceUrl
|
|
||||||
""".trimIndent()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
bot says msg
|
||||||
|
for ((i, file) in mod.latestFiles.withIndex()) {
|
||||||
/**
|
bot.id named i.toString() says PlainText(
|
||||||
* 处理模组文件列表
|
|
||||||
*/
|
|
||||||
private suspend fun MessageEvent.handleModFileList(pagedList: PagedList<File>): Message {
|
|
||||||
val list = pagedList.current() // mod list
|
|
||||||
val hasNext = pagedList.hasNext // 是否有下一页
|
|
||||||
val hasPrev = pagedList.hasPrev // 是否有上一页
|
|
||||||
return buildForwardMessage {
|
|
||||||
bot says "30秒内回复编号查看"
|
|
||||||
for ((x, file) in list.withIndex()) {
|
|
||||||
bot.id named x.toString() says PlainText(
|
|
||||||
"""
|
"""
|
||||||
${file.displayName} [${file.releaseType}] [${file.fileDate.toLocalDate()}]
|
${file.displayName} [${file.releaseType}] [${file.fileDate.toLocalDate()}]
|
||||||
${file.downloadUrl}
|
${file.downloadUrl}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var tmp = "回复:"
|
}
|
||||||
if (hasPrev) tmp += "[P]上一页 "
|
)
|
||||||
if (hasNext) tmp += "[N]下一页"
|
try {
|
||||||
bot says tmp
|
// 获取用户回复
|
||||||
|
val next = withTimeout(WAIT_REPLY_TIMEOUT_S * 1000L) {
|
||||||
|
eventChannel.nextEvent<MessageEvent>(EventPriority.MONITOR) { it.sender == sender }
|
||||||
|
}
|
||||||
|
val nextMessage = next.message.content
|
||||||
|
if (nextMessage.equals(SUBSCRIBE_KEYWORD, true)) {
|
||||||
|
// TODO 实现订阅模组更新功能
|
||||||
|
subject.sendMessage("订阅更新功能暂未完成,敬请期待")
|
||||||
|
} else if (mod.latestFiles.isNotEmpty()) {
|
||||||
|
if (nextMessage.equals(VIEW_FILES_KEYWORD, true)) {
|
||||||
|
// 查看所有文件
|
||||||
|
handleModFileList(service.getModFiles(mod.id))
|
||||||
|
} else {
|
||||||
|
// 查看文件详情
|
||||||
|
handleModFile(mod.latestFiles[nextMessage.toInt()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// 忽略因回复引发的异常,无论是超时、越界还是格式不正确,不提示错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理模组文件列表
|
||||||
|
*/
|
||||||
|
private suspend fun MessageEvent.handleModFileList(pagedList: PagedList<File>) {
|
||||||
|
val selectedFile = handlePagedList(pagedList) { file ->
|
||||||
|
PlainText(
|
||||||
|
"""
|
||||||
|
${file.displayName} [${file.releaseType}] [${file.fileDate.toLocalDate()}]
|
||||||
|
${file.downloadUrl}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
selectedFile?.let { handleModFile(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理模组文件具体信息展示
|
||||||
|
*/
|
||||||
|
private suspend fun MessageEvent.handleModFile(file: File) {
|
||||||
|
try {
|
||||||
|
// 暂时仅展示文件更改日志,可以添加文件依赖相关信息的显示
|
||||||
|
subject.sendMessage(handleModFileChangelog(service.getModFileChangelog(file.modId, file.id)))
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
logger.warning("获取文件[${file.fileName}]更改日志时异常", e)
|
||||||
|
subject.sendMessage("获取文件更改日志时异常,请稍后重试")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +217,14 @@ class MessageHandler(
|
|||||||
return sendLargeMessage(logs)
|
return sendLargeMessage(logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val WAIT_REPLY_TIMEOUT_S = 60
|
||||||
|
private const val PAGE_UP_KEYWORD = "P"
|
||||||
|
private const val PAGE_DOWN_KEYWORD = "N"
|
||||||
|
private const val VIEW_FILES_KEYWORD = "ALL"
|
||||||
|
private const val SUBSCRIBE_KEYWORD = "订阅"
|
||||||
|
private const val ONE_GRP_SIZE = 5000
|
||||||
|
private const val ONE_MSG_SIZE = 500
|
||||||
private val singleDecimalFormat = DecimalFormat("0.#")
|
private val singleDecimalFormat = DecimalFormat("0.#")
|
||||||
|
|
||||||
private fun formatCount(count: Long): String = when {
|
private fun formatCount(count: Long): String = when {
|
||||||
@ -169,8 +249,6 @@ class MessageHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val HTMLPattern = Pattern.compile("<[^>]+>", Pattern.CASE_INSENSITIVE)
|
private val HTMLPattern = Pattern.compile("<[^>]+>", Pattern.CASE_INSENSITIVE)
|
||||||
private val ONE_GRP_SIZE = 5000
|
|
||||||
private val ONE_MSG_SIZE = 500
|
|
||||||
fun MessageEvent.sendLargeMessage(message: String): Message {
|
fun MessageEvent.sendLargeMessage(message: String): Message {
|
||||||
return buildForwardMessage {
|
return buildForwardMessage {
|
||||||
for (g in message.indices step ONE_GRP_SIZE) {
|
for (g in message.indices step ONE_GRP_SIZE) {
|
||||||
@ -181,3 +259,4 @@ class MessageHandler(
|
|||||||
}
|
}
|
||||||
}// fun
|
}// fun
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -9,48 +9,48 @@ import top.jie65535.jcf.util.PagedList
|
|||||||
class MinecraftService(apiKey: String) {
|
class MinecraftService(apiKey: String) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val GAME_ID_MINECRAFT = 432
|
private const val GAME_ID_MINECRAFT = 432
|
||||||
private const val DEFAULT_PAGE_SIZE = 20
|
private const val DEFAULT_PAGE_SIZE = 10
|
||||||
private val DEFAULT_SORT_FIELD = ModsSearchSortField.Popularity
|
private val DEFAULT_SORT_FIELD = ModsSearchSortField.Popularity
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mod分类
|
* mod分类
|
||||||
*/
|
*/
|
||||||
enum class ModClass(val classId: Int) {
|
enum class ModClass(val className: String, val classId: Int) {
|
||||||
/**
|
/**
|
||||||
* 存档
|
* 存档
|
||||||
*/
|
*/
|
||||||
WORLDS(17),
|
WORLDS("存档",17),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 水桶服插件
|
* 水桶服插件
|
||||||
*/
|
*/
|
||||||
BUKKIT_PLUGINS(5),
|
BUKKIT_PLUGINS("水桶服插件", 5),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义
|
* 自定义
|
||||||
*/
|
*/
|
||||||
CUSTOMIZATION(4546),
|
CUSTOMIZATION("定制", 4546),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 整合包
|
* 整合包
|
||||||
*/
|
*/
|
||||||
MODPACKS(4471),
|
MODPACKS("整合包", 4471),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 资源包
|
* 资源包
|
||||||
*/
|
*/
|
||||||
RESOURCE_PACKS(12),
|
RESOURCE_PACKS("资源包", 12),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 附加
|
* 附加
|
||||||
*/
|
*/
|
||||||
ADDONS(4559),
|
ADDONS("附加", 4559),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模组
|
* 模组
|
||||||
*/
|
*/
|
||||||
MODS(6);
|
MODS("模组", 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
23
src/main/kotlin/top/jie65535/jcf/PluginCommands.kt
Normal file
23
src/main/kotlin/top/jie65535/jcf/PluginCommands.kt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package top.jie65535.jcf
|
||||||
|
|
||||||
|
import net.mamoe.mirai.console.command.CommandSender
|
||||||
|
import net.mamoe.mirai.console.command.CompositeCommand
|
||||||
|
|
||||||
|
object PluginCommands : CompositeCommand(PluginMain, "jcf") {
|
||||||
|
@SubCommand
|
||||||
|
@Description("设置Curseforge API Key")
|
||||||
|
suspend fun CommandSender.setApiKey(apiKey: String) {
|
||||||
|
PluginConfig.apiKey = apiKey
|
||||||
|
sendMessage("OK! 重启插件生效")
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubCommand
|
||||||
|
@Description("查看插件帮助")
|
||||||
|
suspend fun CommandSender.help() {
|
||||||
|
val msg = StringBuilder()
|
||||||
|
for ((modClass, cmd) in PluginConfig.searchCommands) {
|
||||||
|
msg.appendLine("搜索${modClass.className}: $cmd")
|
||||||
|
}
|
||||||
|
sendMessage(msg.toString())
|
||||||
|
}
|
||||||
|
}
|
@ -4,20 +4,20 @@ import net.mamoe.mirai.console.data.AutoSavePluginConfig
|
|||||||
import net.mamoe.mirai.console.data.ValueDescription
|
import net.mamoe.mirai.console.data.ValueDescription
|
||||||
import net.mamoe.mirai.console.data.value
|
import net.mamoe.mirai.console.data.value
|
||||||
|
|
||||||
object PluginConfig : AutoSavePluginConfig("jcf") {
|
object PluginConfig : AutoSavePluginConfig("JCurseforgeConfig") {
|
||||||
@ValueDescription("Curseforge API KEY")
|
@ValueDescription("Curseforge API KEY")
|
||||||
val apiKey: String by value()
|
var apiKey: String by value()
|
||||||
|
|
||||||
@ValueDescription("搜索命令 (MODS,MODPACKS,RESOURCE_PACKS,WORLDS,BUKKIT_PLUGINS,ADDONS,CUSTOMIZATION)")
|
@ValueDescription("搜索命令 (MODS,MODPACKS,RESOURCE_PACKS,WORLDS,BUKKIT_PLUGINS,ADDONS,CUSTOMIZATION)")
|
||||||
val searchCommands: MutableMap<MinecraftService.ModClass, String> by value(
|
val searchCommands: MutableMap<MinecraftService.ModClass, String> by value(
|
||||||
mutableMapOf(
|
mutableMapOf(
|
||||||
MinecraftService.ModClass.MODS to "jcfmod ",
|
MinecraftService.ModClass.MODS to "cfmod ",
|
||||||
MinecraftService.ModClass.MODPACKS to "jcfpack ",
|
MinecraftService.ModClass.MODPACKS to "cfpack ",
|
||||||
MinecraftService.ModClass.RESOURCE_PACKS to "jcfres ",
|
MinecraftService.ModClass.RESOURCE_PACKS to "cfres ",
|
||||||
MinecraftService.ModClass.WORLDS to "jcfword ",
|
MinecraftService.ModClass.WORLDS to "cfword ",
|
||||||
MinecraftService.ModClass.BUKKIT_PLUGINS to "jcfbukkit ",
|
MinecraftService.ModClass.BUKKIT_PLUGINS to "cfbukkit ",
|
||||||
MinecraftService.ModClass.ADDONS to "jcfaddon ",
|
MinecraftService.ModClass.ADDONS to "cfaddon ",
|
||||||
MinecraftService.ModClass.CUSTOMIZATION to "jcfcustom ",
|
MinecraftService.ModClass.CUSTOMIZATION to "cfcustom ",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package top.jie65535.jcf
|
package top.jie65535.jcf
|
||||||
|
|
||||||
|
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||||
import net.mamoe.mirai.event.GlobalEventChannel
|
import net.mamoe.mirai.event.GlobalEventChannel
|
||||||
@ -19,9 +20,12 @@ object PluginMain: KotlinPlugin(
|
|||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
logger.info { "Plugin loaded" }
|
logger.info { "Plugin loaded" }
|
||||||
PluginConfig.reload()
|
PluginConfig.reload()
|
||||||
|
PluginCommands.register()
|
||||||
|
|
||||||
if (PluginConfig.apiKey.isBlank()) {
|
if (PluginConfig.apiKey.isBlank()) {
|
||||||
logger.error("必须配置 Curseforge Api Key 才可以使用本插件!")
|
logger.error("必须配置 Curseforge Api Key 才可以使用本插件!\n" +
|
||||||
|
"请使用 /jcf setApiKey <apiKey> 命令来设置key\n" +
|
||||||
|
"Api key 可以在开发者控制台生成:https://console.curseforge.com/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val service = MinecraftService(PluginConfig.apiKey)
|
val service = MinecraftService(PluginConfig.apiKey)
|
||||||
|
Loading…
Reference in New Issue
Block a user