diff --git a/packages/webgal/package.json b/packages/webgal/package.json index 7a216c9f4..aa6c608cb 100644 --- a/packages/webgal/package.json +++ b/packages/webgal/package.json @@ -13,6 +13,7 @@ "@icon-park/react": "^1.4.2", "@reduxjs/toolkit": "^1.8.1", "angular-expressions": "^1.4.3", + "ani-cursor.js": "^1.0.3", "axios": "^1.13.5", "cloudlogjs": "^1.0.9", "gifuct-js": "^2.1.2", diff --git a/packages/webgal/src/Core/util/coreInitialFunction/infoFetcher.ts b/packages/webgal/src/Core/util/coreInitialFunction/infoFetcher.ts index 7a239ff32..2c5e23b23 100644 --- a/packages/webgal/src/Core/util/coreInitialFunction/infoFetcher.ts +++ b/packages/webgal/src/Core/util/coreInitialFunction/infoFetcher.ts @@ -9,6 +9,7 @@ import { getFastSaveFromStorage, getSavesFromStorage } from '@/Core/controller/s import { logger } from '@/Core/util/logger'; import axios from 'axios'; import { IGameVar } from '@/Core/Modules/stage/stageInterface'; +import { setANICursor } from 'ani-cursor.js'; /** * 获取游戏信息 @@ -21,7 +22,7 @@ export const infoFetcher = (url: string): Promise => { let gameConfig = WebgalParser.parseConfig(gameConfigRaw); logger.info('获取到游戏信息', gameConfig); // 先把 key 找到并设置了 - const keyItem = gameConfig.find((e) => e.command === 'Game_key'); + const keyItem = gameConfig.find((e: any) => e.command === 'Game_key'); WebGAL.gameKey = (keyItem?.args?.[0] as string) ?? ''; initKey(); await getStorageAsync(); @@ -30,7 +31,7 @@ export const infoFetcher = (url: string): Promise => { // 存储 config.txt 中的配置,用于清除所有数据时还原配置 const gameConfigInit: IGameVar = {}; // 按照游戏的配置开始设置对应的状态 - gameConfig.forEach((e) => { + gameConfig.forEach((e: any) => { const { command, args } = e; if (args.length > 0) { if (args.length > 1) { @@ -67,6 +68,53 @@ export const infoFetcher = (url: string): Promise => { const appId = String(res); WebGAL.steam.initialize(appId); } + // 自定义光标 + const customCorsurSize = { width: 32, height: 32 }; + if (command === 'Custom_Corsur_Ani_Size') { + const corsurSize = String(res) + .split(/\s+/) + .filter((e) => e); + if (corsurSize.length === 2) { + const width = parseInt(corsurSize[0]); + const height = parseInt(corsurSize[1]); + // see to https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/cursor#icon_size_limits + if (width > 32 || height > 32) { + logger.warn('size to large, we suggest set to 32x32 size'); + } + if (width > 0 && height > 0) { + customCorsurSize.width = width; + customCorsurSize.height = height; + } + } + } + if (command === 'Custom_Corsur') { + const group = String(res) + .split(/\s+/) + .filter((e) => e); + for (const token of group) { + const arr = token.split(',').map((e) => e.trim()); + const safeUrl = `/game/${arr[0]}`.replace(/\\/g, '\\\\'); + const type = arr?.[1] ?? 'auto'; + if (String(safeUrl).endsWith('.ani')) { + const hotspotX = parseInt(arr?.[2]); + const hotspotY = parseInt(arr?.[3]); + setANICursor( + 'html *', + safeUrl, + type, + customCorsurSize.width, + customCorsurSize.height, + hotspotX > 0 ? hotspotX : undefined, + hotspotY > 0 ? hotspotY : undefined, + ); + } else { + const hotspot = `${arr?.[2] ?? ''} ${arr?.[3] ?? ''}`; + const cursorCss = document.createElement('style'); + cursorCss.textContent = `html * { cursor: url(${safeUrl}) ${hotspot}, ${type} !important; }`; + document.head.appendChild(cursorCss); + } + } + } } } }); diff --git a/yarn.lock b/yarn.lock index 9ef0a5ec1..174fde5cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1723,6 +1723,14 @@ angular-expressions@^1.4.3: resolved "https://registry.yarnpkg.com/angular-expressions/-/angular-expressions-1.4.3.tgz#24fb9e8e9e0278885dd0f7e28512ac88a74037f6" integrity sha512-r7j+dqOuHy0OYiR5AazDixU/Us3TDN2FfuxGX4Dq6d61Y2MhBQHMdUNBfkkLPjDqVm2Is394h31gC3bcBwy9zw== +ani-cursor.js@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ani-cursor.js/-/ani-cursor.js-1.0.3.tgz#a0b390a887f2692da83c69c9251a043c7c17888f" + integrity sha512-asDn4Ts+iSSTHIQxyqn3iYQtf2FLk3Njid1aOb03QnSsEPY9qT9aDeuJUlzt+cc5LRTw6D+1vBp9WzBOceS+LQ== + dependencies: + buffer "^6.0.3" + riff-file "^1.0.3" + ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -2056,11 +2064,28 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + builtin-modules@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== +byte-data@^18.0.3: + version "18.1.1" + resolved "https://registry.npmmirror.com/byte-data/-/byte-data-18.1.1.tgz#4eed09970921bf7d786b250e56615d8314bb6746" + integrity sha512-Kv/B0r7adgnCcrs/y703sac2XFLdHW5kPfis1j8+Ij/hmEcWhBKf+1pNTv+vsNqXb207Uiyri8bpnogNxR/4Lg== + dependencies: + endianness "^8.0.2" + ieee754-buffer "^2.0.0" + utf8-buffer "^1.0.0" + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -2594,6 +2619,11 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +endianness@^8.0.2: + version "8.0.2" + resolved "https://registry.npmmirror.com/endianness/-/endianness-8.0.2.tgz#e35d16bbe80b6ff94fbc199168dd234d9f78168e" + integrity sha512-IU+77+jJ7lpw2qZ3NUuqBZFy3GuioNgXUdsL1L9tooDNTaw0TgOnwNuc+8Ns+haDaTifK97QLzmOANJtI/rGvw== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3606,7 +3636,12 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13: +ieee754-buffer@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/ieee754-buffer/-/ieee754-buffer-2.0.0.tgz#5648050d1a037df59a6cc68f441c6b0b467314f8" + integrity sha512-AXUAT0nMEi7h1Is8HXGXof3eejl/GabZFKSj8Ym6kVRUSwrAb52EkAXywiCQYSHGQMRn7lvfY7vhPMjVc+Kybg== + +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5231,6 +5266,13 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== +riff-file@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/riff-file/-/riff-file-1.0.3.tgz#95589f787e0c5fb2fa2937fc0a0e5e5d3131242b" + integrity sha512-Vv8wwGr0BCks7VMI3Lv0houZee4DaHFjjTT0LMhMJKio2YmLncLeIVpK63ydSverngNk8XQPU3fbeP3bWgSIig== + dependencies: + byte-data "^18.0.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -6079,6 +6121,11 @@ use-sync-external-store@^1.0.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== +utf8-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/utf8-buffer/-/utf8-buffer-1.0.0.tgz#457e7d848d4d9cd873772b710d150565f6e543d9" + integrity sha512-ueuhzvWnp5JU5CiGSY4WdKbiN/PO2AZ/lpeLiz2l38qwdLy/cW40XobgyuIWucNyum0B33bVB0owjFCeGBSLqg== + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"