mirror of
				https://github.com/earthjasonlin/zzz-signal-search-export.git
				synced 2025-11-04 14:10:10 +08:00 
			
		
		
		
	Compare commits
	
		
			8 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					3dbb746a38 | ||
| 
						 | 
					b88b57ae62 | ||
| 
						 | 
					677ab3750d | ||
| 
						 | 
					f95470504d | ||
| 
						 | 
					8d45af5089 | ||
| 
						 | 
					8a9c7a3b56 | ||
| 
						 | 
					2a670c7023 | ||
| 
						 | 
					d732d523a8 | 
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "star-rail-warp-export",
 | 
					  "name": "star-rail-warp-export",
 | 
				
			||||||
  "version": "0.0.4",
 | 
					  "version": "0.0.8",
 | 
				
			||||||
  "main": "./dist/electron/main/main.js",
 | 
					  "main": "./dist/electron/main/main.js",
 | 
				
			||||||
  "author": "biuuu <https://github.com/biuuu>",
 | 
					  "author": "biuuu <https://github.com/biuuu>",
 | 
				
			||||||
  "license": "MIT",
 | 
					  "license": "MIT",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
const { readJSON, saveJSON, decipherAes, cipherAes, detectLocale } = require('./utils')
 | 
					const { readJSON, saveJSON, decipherAes, cipherAes, detectLocale, userDataPath, globalUserDataPath } = require('./utils')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const config = {
 | 
					const config = {
 | 
				
			||||||
  urls: [],
 | 
					  urls: [],
 | 
				
			||||||
@@ -13,7 +13,10 @@ const config = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getLocalConfig = async () => {
 | 
					const getLocalConfig = async () => {
 | 
				
			||||||
  const localConfig = await readJSON('config.json')
 | 
					  let localConfig = await readJSON(userDataPath, 'config.json')
 | 
				
			||||||
 | 
					  if (!localConfig) {
 | 
				
			||||||
 | 
					    localConfig = await readJSON(globalUserDataPath, 'config.json')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (!localConfig) return
 | 
					  if (!localConfig) return
 | 
				
			||||||
  const configTemp = {}
 | 
					  const configTemp = {}
 | 
				
			||||||
  for (let key in localConfig) {
 | 
					  for (let key in localConfig) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ const util = require('util')
 | 
				
			|||||||
const path = require('path')
 | 
					const path = require('path')
 | 
				
			||||||
const { URL } = require('url')
 | 
					const { URL } = require('url')
 | 
				
			||||||
const { app, ipcMain, shell } = require('electron')
 | 
					const { app, ipcMain, shell } = require('electron')
 | 
				
			||||||
const { sleep, request, sendMsg, readJSON, saveJSON, detectLocale, userDataPath, userPath, localIp, langMap } = require('./utils')
 | 
					const { sleep, request, sendMsg, readJSON, saveJSON, detectLocale, userDataPath, userPath, localIp, langMap, globalUserDataPath } = require('./utils')
 | 
				
			||||||
const config = require('./config')
 | 
					const config = require('./config')
 | 
				
			||||||
const i18n = require('./i18n')
 | 
					const i18n = require('./i18n')
 | 
				
			||||||
const { enableProxy, disableProxy } = require('./module/system-proxy')
 | 
					const { enableProxy, disableProxy } = require('./module/system-proxy')
 | 
				
			||||||
@@ -29,25 +29,42 @@ const defaultTypeMap = new Map([
 | 
				
			|||||||
  ['2', '始发跃迁']
 | 
					  ['2', '始发跃迁']
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const findDataFiles = async (dataPath, fileMap) => {
 | 
				
			||||||
 | 
					  const files = await readdir(dataPath)
 | 
				
			||||||
 | 
					  if (files?.length) {
 | 
				
			||||||
 | 
					    for (let name of files) {
 | 
				
			||||||
 | 
					      if (/^gacha-list-\d+\.json$/.test(name) && !fileMap.has(name)) {
 | 
				
			||||||
 | 
					        fileMap.set(name, dataPath)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const collectDataFiles = async () => {
 | 
				
			||||||
 | 
					  await fs.ensureDir(userDataPath)
 | 
				
			||||||
 | 
					  await fs.ensureDir(globalUserDataPath)
 | 
				
			||||||
 | 
					  const fileMap = new Map()
 | 
				
			||||||
 | 
					  await findDataFiles(userDataPath, fileMap)
 | 
				
			||||||
 | 
					  await findDataFiles(globalUserDataPath, fileMap)
 | 
				
			||||||
 | 
					  return fileMap
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let localDataReaded = false
 | 
					let localDataReaded = false
 | 
				
			||||||
const readdir = util.promisify(fs.readdir)
 | 
					const readdir = util.promisify(fs.readdir)
 | 
				
			||||||
const readData = async () => {
 | 
					const readData = async () => {
 | 
				
			||||||
  if (localDataReaded) return
 | 
					  if (localDataReaded) return
 | 
				
			||||||
  localDataReaded = true
 | 
					  localDataReaded = true
 | 
				
			||||||
  await fs.ensureDir(userDataPath)
 | 
					  const fileMap = await collectDataFiles()
 | 
				
			||||||
  const files = await readdir(userDataPath)
 | 
					  for (let [name, dataPath] of fileMap) {
 | 
				
			||||||
  for (let name of files) {
 | 
					    try {
 | 
				
			||||||
    if (/^gacha-list-\d+\.json$/.test(name)) {
 | 
					      const data = await readJSON(dataPath, name)
 | 
				
			||||||
      try {
 | 
					      data.typeMap = new Map(data.typeMap) || defaultTypeMap
 | 
				
			||||||
        const data = await readJSON(name)
 | 
					      data.result = new Map(data.result)
 | 
				
			||||||
        data.typeMap = new Map(data.typeMap) || defaultTypeMap
 | 
					      if (data.uid) {
 | 
				
			||||||
        data.result = new Map(data.result)
 | 
					        dataMap.set(data.uid, data)
 | 
				
			||||||
        if (data.uid) {
 | 
					 | 
				
			||||||
          dataMap.set(data.uid, data)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      } catch (e) {
 | 
					 | 
				
			||||||
        sendMsg(e, 'ERROR')
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      sendMsg(e, 'ERROR')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if ((!config.current && dataMap.size) || (config.current && dataMap.size && !dataMap.has(config.current))) {
 | 
					  if ((!config.current && dataMap.size) || (config.current && dataMap.size && !dataMap.has(config.current))) {
 | 
				
			||||||
@@ -115,9 +132,12 @@ const readLog = async () => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const promises = logPaths.map(async logpath => {
 | 
					    const promises = logPaths.map(async logpath => {
 | 
				
			||||||
      const logText = await fs.readFile(logpath, 'utf8')
 | 
					      const logText = await fs.readFile(logpath, 'utf8')
 | 
				
			||||||
      const gamePathMch = logText.match(/\w:\/.*?(Star\sRail\/Game\/StarRail_Data)/)
 | 
					      const gamePathMch = logText.match(/\w:\/.*?\/StarRail_Data\//)
 | 
				
			||||||
      if (gamePathMch) {
 | 
					      if (gamePathMch) {
 | 
				
			||||||
        const cacheText = await fs.readFile(path.join(gamePathMch[0], '/webCaches/Cache/Cache_Data/data_2'), 'utf8')
 | 
					        let cacheText = ''
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          cacheText = await fs.readFile(path.join(gamePathMch[0], '/webCaches/Cache/Cache_Data/data_2'), 'utf8')
 | 
				
			||||||
 | 
					        } catch (e) {}
 | 
				
			||||||
        const urlMch = cacheText.match(/https.+?&auth_appid=webview_gacha&.+?authkey=.+?&game_biz=hkrpg_.+?&plat_type=pc/g)
 | 
					        const urlMch = cacheText.match(/https.+?&auth_appid=webview_gacha&.+?authkey=.+?&game_biz=hkrpg_.+?&plat_type=pc/g)
 | 
				
			||||||
        if (urlMch) {
 | 
					        if (urlMch) {
 | 
				
			||||||
          cacheFolder = path.join(gamePathMch[0], '/webCaches/Cache/')
 | 
					          cacheFolder = path.join(gamePathMch[0], '/webCaches/Cache/')
 | 
				
			||||||
@@ -235,7 +255,6 @@ const tryGetUid = async (queryString) => {
 | 
				
			|||||||
  try {
 | 
					  try {
 | 
				
			||||||
    for (let [key] of defaultTypeMap) {
 | 
					    for (let [key] of defaultTypeMap) {
 | 
				
			||||||
      const res = await request(`${url}&gacha_type=${key}&page=1&size=6`)
 | 
					      const res = await request(`${url}&gacha_type=${key}&page=1&size=6`)
 | 
				
			||||||
      checkResStatus(res)
 | 
					 | 
				
			||||||
      if (res.data.list && res.data.list.length) {
 | 
					      if (res.data.list && res.data.list.length) {
 | 
				
			||||||
        return res.data.list[0].uid
 | 
					        return res.data.list[0].uid
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -333,10 +352,7 @@ const tryRequest = async (url, retry = false) => {
 | 
				
			|||||||
  const gachaTypeUrl = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}&page=1&size=5&gacha_type=1&end_id=0`
 | 
					  const gachaTypeUrl = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}&page=1&size=5&gacha_type=1&end_id=0`
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    const res = await request(gachaTypeUrl)
 | 
					    const res = await request(gachaTypeUrl)
 | 
				
			||||||
    if (res.retcode !== 0) {
 | 
					    checkResStatus(res)
 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  } catch (e) {
 | 
					  } catch (e) {
 | 
				
			||||||
    if (e.code === 'ERR_PROXY_CONNECTION_FAILED' && !retry) {
 | 
					    if (e.code === 'ERR_PROXY_CONNECTION_FAILED' && !retry) {
 | 
				
			||||||
      await disableProxy()
 | 
					      await disableProxy()
 | 
				
			||||||
@@ -351,11 +367,6 @@ const getUrl = async () => {
 | 
				
			|||||||
  let url = await readLog()
 | 
					  let url = await readLog()
 | 
				
			||||||
  if (!url && config.proxyMode) {
 | 
					  if (!url && config.proxyMode) {
 | 
				
			||||||
    url = await useProxy()
 | 
					    url = await useProxy()
 | 
				
			||||||
  } else if (url) {
 | 
					 | 
				
			||||||
    const result = await tryRequest(url)
 | 
					 | 
				
			||||||
    if (!result && config.proxyMode) {
 | 
					 | 
				
			||||||
      url = await useProxy()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return url
 | 
					  return url
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -372,6 +383,9 @@ const fetchData = async (urlOverride) => {
 | 
				
			|||||||
    sendMsg(message)
 | 
					    sendMsg(message)
 | 
				
			||||||
    throw new Error(message)
 | 
					    throw new Error(message)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await tryRequest(url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const searchParams = getQuerystring(url)
 | 
					  const searchParams = getQuerystring(url)
 | 
				
			||||||
  if (!searchParams) {
 | 
					  if (!searchParams) {
 | 
				
			||||||
    const message = text.url.incorrect
 | 
					    const message = text.url.incorrect
 | 
				
			||||||
@@ -456,7 +470,7 @@ ipcMain.handle('READ_DATA', async () => {
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ipcMain.handle('CHANGE_UID', (event, uid) => {
 | 
					ipcMain.handle('CHANGE_UID', (event, uid) => {
 | 
				
			||||||
  config.current = uid
 | 
					  changeCurrent(uid)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ipcMain.handle('GET_CONFIG', () => {
 | 
					ipcMain.handle('GET_CONFIG', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,14 +42,24 @@ const parseData = (data) => {
 | 
				
			|||||||
  return result
 | 
					  return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const assignData = (objA, objB) => {
 | 
				
			||||||
 | 
					  const temp = { ...objA }
 | 
				
			||||||
 | 
					  for (let key in objB) {
 | 
				
			||||||
 | 
					    if (objB[key]) {
 | 
				
			||||||
 | 
					      temp[key] = objB[key]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return temp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const i18nMap = new Map()
 | 
					const i18nMap = new Map()
 | 
				
			||||||
const prepareData = () => {
 | 
					const prepareData = () => {
 | 
				
			||||||
  for (let key in raw) {
 | 
					  for (let key in raw) {
 | 
				
			||||||
    let temp = {}
 | 
					    let temp = {}
 | 
				
			||||||
    if (key === 'zh-tw') {
 | 
					    if (key === 'zh-tw') {
 | 
				
			||||||
      Object.assign(temp, raw['zh-cn'], raw[key])
 | 
					      temp = assignData(raw['zh-cn'], raw[key])
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      Object.assign(temp, raw['zh-cn'], raw['en-us'], raw[key])
 | 
					      temp = assignData(raw['zh-cn'], assignData(raw['en-us'], raw[key]))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    i18nMap.set(key, parseData(temp))
 | 
					    i18nMap.set(key, parseData(temp))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,9 @@ const Registry = require('winreg')
 | 
				
			|||||||
const isDev = !app.isPackaged
 | 
					const isDev = !app.isPackaged
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const userPath = app.getPath('userData')
 | 
					const userPath = app.getPath('userData')
 | 
				
			||||||
const appRoot = isDev ? path.resolve(__dirname, '..', '..') : userPath
 | 
					const appRoot = isDev ? path.resolve(__dirname, '..', '..') : path.resolve(app.getAppPath(), '..', '..')
 | 
				
			||||||
const userDataPath = path.resolve(appRoot, 'userData')
 | 
					const userDataPath = path.resolve(appRoot, 'userData')
 | 
				
			||||||
 | 
					const globalUserDataPath = path.resolve(userPath, 'userData')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let win = null
 | 
					let win = null
 | 
				
			||||||
const initWindow = () => {
 | 
					const initWindow = () => {
 | 
				
			||||||
@@ -56,7 +57,7 @@ const saveLog = () => {
 | 
				
			|||||||
    const text = item[2]
 | 
					    const text = item[2]
 | 
				
			||||||
    return `[${type}][${time}]${text}`
 | 
					    return `[${type}][${time}]${text}`
 | 
				
			||||||
  }).join('\r\n')
 | 
					  }).join('\r\n')
 | 
				
			||||||
  fs.outputFileSync(path.join(userDataPath, 'log.txt'), text)
 | 
					  fs.outputFile(path.join(userDataPath, 'log.txt'), text)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const authkeyMask = (text = '') => {
 | 
					const authkeyMask = (text = '') => {
 | 
				
			||||||
@@ -144,19 +145,20 @@ const detectLocale = (value) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const saveJSON = async (name, data) => {
 | 
					const saveJSON = async (name, data) => {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    await fs.outputJSON(path.join(userDataPath, name), data, {
 | 
					    await fs.outputJSON(path.join(userDataPath, name), data)
 | 
				
			||||||
      spaces: 2
 | 
					    if (!isDev) {
 | 
				
			||||||
    })
 | 
					      await fs.outputJSON(path.join(globalUserDataPath, name), data)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  } catch (e) {
 | 
					  } catch (e) {
 | 
				
			||||||
    sendMsg(e, 'ERROR')
 | 
					    sendMsg(e, 'ERROR')
 | 
				
			||||||
    await sleep(3)
 | 
					    await sleep(3)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const readJSON = async (name) => {
 | 
					const readJSON = async (dataPath, name) => {
 | 
				
			||||||
  let data = null
 | 
					  let data = null
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    data = await fs.readJSON(path.join(userDataPath, name))
 | 
					    data = await fs.readJSON(path.join(dataPath, name))
 | 
				
			||||||
  } catch (e) {}
 | 
					  } catch (e) {}
 | 
				
			||||||
  return data
 | 
					  return data
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -203,5 +205,5 @@ const localIp = () => {
 | 
				
			|||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
  sleep, request, hash, cipherAes, decipherAes, saveLog,
 | 
					  sleep, request, hash, cipherAes, decipherAes, saveLog,
 | 
				
			||||||
  sendMsg, readJSON, saveJSON, initWindow, getWin, localIp, userPath, detectLocale, langMap,
 | 
					  sendMsg, readJSON, saveJSON, initWindow, getWin, localIp, userPath, detectLocale, langMap,
 | 
				
			||||||
  appRoot, userDataPath
 | 
					  appRoot, userDataPath, globalUserDataPath
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -55,10 +55,12 @@
 | 
				
			|||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </el-dialog>
 | 
					    </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <el-dialog :title="ui.button.solution" v-model="state.showCacheCleanDlg" width="90%" custom-class="max-w-md">
 | 
					    <el-dialog :title="ui.button.solution" v-model="state.showCacheCleanDlg" width="90%" custom-class="max-w-md cache-clean-dialog">
 | 
				
			||||||
      <el-button plain icon="folder" type="primary" @click="openCacheFolder">{{ui.button.cacheFolder}}</el-button>
 | 
					      <el-button plain icon="folder" type="success" @click="openCacheFolder">{{ui.button.cacheFolder}}</el-button>
 | 
				
			||||||
      <p class="my-4 leading-2 text-gray-600 text-sm whitespace-pre-line">{{ui.extra.cacheClean}}</p>
 | 
					      <p class="my-2 flex flex-col text-teal-800 text-[13px]">
 | 
				
			||||||
      <p class="my-2 text-gray-400 text-xs">{{ui.extra.findCacheFolder}}</p>
 | 
					        <span class="my-1" v-for="txt of cacheCleanTextList">{{ txt }}</span>
 | 
				
			||||||
 | 
					      </p>
 | 
				
			||||||
 | 
					      <p class="my-2 text-gray-500 text-xs">{{ui.extra.findCacheFolder}}</p>
 | 
				
			||||||
      <template #footer>
 | 
					      <template #footer>
 | 
				
			||||||
        <div class="dialog-footer text-center">
 | 
					        <div class="dialog-footer text-center">
 | 
				
			||||||
          <el-button  type="primary" @click="state.showCacheCleanDlg = false" class="focus:outline-none">{{ui.common.ok}}</el-button>
 | 
					          <el-button  type="primary" @click="state.showCacheCleanDlg = false" class="focus:outline-none">{{ui.common.ok}}</el-button>
 | 
				
			||||||
@@ -99,6 +101,13 @@ const ui = computed(() => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cacheCleanTextList = computed(() => {
 | 
				
			||||||
 | 
					  if (ui.value) {
 | 
				
			||||||
 | 
					    return ui.value.extra?.cacheClean?.split('\n')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return []
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const gachaData = computed(() => {
 | 
					const gachaData = computed(() => {
 | 
				
			||||||
  return state.dataMap.get(state.current)
 | 
					  return state.dataMap.get(state.current)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,4 +13,10 @@
 | 
				
			|||||||
  body::-webkit-scrollbar-thumb {
 | 
					  body::-webkit-scrollbar-thumb {
 | 
				
			||||||
    @apply rounded-full bg-gray-300;
 | 
					    @apply rounded-full bg-gray-300;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@layer utilities {
 | 
				
			||||||
 | 
					  .cache-clean-dialog .el-dialog__body {
 | 
				
			||||||
 | 
					    padding: 0 20px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
import * as IconComponents from '@element-plus/icons-vue'
 | 
					import * as IconComponents from '@element-plus/icons-vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const weaponTypeNames = new Set([
 | 
					const weaponTypeNames = new Set([
 | 
				
			||||||
  '光锥', 'Light Cone', '光錐', 'Lichtkegel', 'Conos de luz', 'cônes de lumière', '光円錐', '광추', 'Cones de Luz', 'Световые конусы', 'Nón Ánh Sáng'
 | 
					  '光锥', '光錐', 'Lichtkegel', 'Light Cone', 'Conos de luz', 'cônes de lumière', '光円錐', '광추', 'Cones de Luz', 'Световые конусы', 'Nón Ánh Sáng'
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const characterTypeNames = new Set([
 | 
					const characterTypeNames = new Set([
 | 
				
			||||||
  '角色', 'Character', '캐릭터', 'キャラクター', 'Personaje', 'Personnage', 'Персонажи', 'ตัวละคร', 'Nhân Vật', 'Figur', 'Karakter', 'Personagem'
 | 
					  '角色', 'Figur', 'Character', 'Personajes', 'Personnages', 'Karakter', 'キャラクター', '캐릭터', 'Personagens', 'Персонажи', 'ตัวละคร', 'Nhân Vật'
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isCharacter = (name) => characterTypeNames.has(name)
 | 
					const isCharacter = (name) => characterTypeNames.has(name)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user