Kxs Client - Survev.io Client

A client to enhance the survev.io in-game experience with many features, as well as future features.

目前為 2025-04-06 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Kxs Client - Survev.io Client
  3. // @namespace https://github.com/Kisakay/KxsClient
  4. // @version 1.2.6
  5. // @description A client to enhance the survev.io in-game experience with many features, as well as future features.
  6. // @author Kisakay
  7. // @license AGPL-3.0
  8. // @run-at document-end
  9. // @icon https://kxs.rip/assets/KysClientLogo.png
  10. // @match ://survev.io/
  11. // @match *://66.179.254.36/
  12. // @match ://zurviv.io/
  13. // @match ://expandedwater.online/
  14. // @match ://localhost:3000/
  15. // @match ://surviv.wf/
  16. // @match ://resurviv.biz/
  17. // @match ://82.67.125.203/
  18. // @match ://leia-uwu.github.io/survev/
  19. // @match ://50v50.online/
  20. // @match ://eu-comp.net/
  21. // @match ://survev.leia-is.gay/
  22. // @grant GM_xmlhttpRequest
  23. // @grant GM_info
  24. // @grant GM.getValue
  25. // @grant GM.setValue
  26. // ==/UserScript==
  27. ;
  28. /******/ (() => { // webpackBootstrap
  29. /******/ var __webpack_modules__ = ({
  30.  
  31. /***/ 908:
  32. /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
  33.  
  34. const debug = __webpack_require__(272)
  35. const { MAX_LENGTH, MAX_SAFE_INTEGER } = __webpack_require__(874)
  36. const { safeRe: re, safeSrc: src, t } = __webpack_require__(718)
  37.  
  38. const parseOptions = __webpack_require__(587)
  39. const { compareIdentifiers } = __webpack_require__(123)
  40. class SemVer {
  41. constructor (version, options) {
  42. options = parseOptions(options)
  43.  
  44. if (version instanceof SemVer) {
  45. if (version.loose === !!options.loose &&
  46. version.includePrerelease === !!options.includePrerelease) {
  47. return version
  48. } else {
  49. version = version.version
  50. }
  51. } else if (typeof version !== 'string') {
  52. throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`)
  53. }
  54.  
  55. if (version.length > MAX_LENGTH) {
  56. throw new TypeError(
  57. `version is longer than ${MAX_LENGTH} characters`
  58. )
  59. }
  60.  
  61. debug('SemVer', version, options)
  62. this.options = options
  63. this.loose = !!options.loose
  64. // this isn't actually relevant for versions, but keep it so that we
  65. // don't run into trouble passing this.options around.
  66. this.includePrerelease = !!options.includePrerelease
  67.  
  68. const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])
  69.  
  70. if (!m) {
  71. throw new TypeError(`Invalid Version: ${version}`)
  72. }
  73.  
  74. this.raw = version
  75.  
  76. // these are actually numbers
  77. this.major = +m[1]
  78. this.minor = +m[2]
  79. this.patch = +m[3]
  80.  
  81. if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
  82. throw new TypeError('Invalid major version')
  83. }
  84.  
  85. if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
  86. throw new TypeError('Invalid minor version')
  87. }
  88.  
  89. if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
  90. throw new TypeError('Invalid patch version')
  91. }
  92.  
  93. // numberify any prerelease numeric ids
  94. if (!m[4]) {
  95. this.prerelease = []
  96. } else {
  97. this.prerelease = m[4].split('.').map((id) => {
  98. if (/^[0-9]+$/.test(id)) {
  99. const num = +id
  100. if (num >= 0 && num < MAX_SAFE_INTEGER) {
  101. return num
  102. }
  103. }
  104. return id
  105. })
  106. }
  107.  
  108. this.build = m[5] ? m[5].split('.') : []
  109. this.format()
  110. }
  111.  
  112. format () {
  113. this.version = `${this.major}.${this.minor}.${this.patch}`
  114. if (this.prerelease.length) {
  115. this.version += `-${this.prerelease.join('.')}`
  116. }
  117. return this.version
  118. }
  119.  
  120. toString () {
  121. return this.version
  122. }
  123.  
  124. compare (other) {
  125. debug('SemVer.compare', this.version, this.options, other)
  126. if (!(other instanceof SemVer)) {
  127. if (typeof other === 'string' && other === this.version) {
  128. return 0
  129. }
  130. other = new SemVer(other, this.options)
  131. }
  132.  
  133. if (other.version === this.version) {
  134. return 0
  135. }
  136.  
  137. return this.compareMain(other) || this.comparePre(other)
  138. }
  139.  
  140. compareMain (other) {
  141. if (!(other instanceof SemVer)) {
  142. other = new SemVer(other, this.options)
  143. }
  144.  
  145. return (
  146. compareIdentifiers(this.major, other.major) ||
  147. compareIdentifiers(this.minor, other.minor) ||
  148. compareIdentifiers(this.patch, other.patch)
  149. )
  150. }
  151.  
  152. comparePre (other) {
  153. if (!(other instanceof SemVer)) {
  154. other = new SemVer(other, this.options)
  155. }
  156.  
  157. // NOT having a prerelease is > having one
  158. if (this.prerelease.length && !other.prerelease.length) {
  159. return -1
  160. } else if (!this.prerelease.length && other.prerelease.length) {
  161. return 1
  162. } else if (!this.prerelease.length && !other.prerelease.length) {
  163. return 0
  164. }
  165.  
  166. let i = 0
  167. do {
  168. const a = this.prerelease[i]
  169. const b = other.prerelease[i]
  170. debug('prerelease compare', i, a, b)
  171. if (a === undefined && b === undefined) {
  172. return 0
  173. } else if (b === undefined) {
  174. return 1
  175. } else if (a === undefined) {
  176. return -1
  177. } else if (a === b) {
  178. continue
  179. } else {
  180. return compareIdentifiers(a, b)
  181. }
  182. } while (++i)
  183. }
  184.  
  185. compareBuild (other) {
  186. if (!(other instanceof SemVer)) {
  187. other = new SemVer(other, this.options)
  188. }
  189.  
  190. let i = 0
  191. do {
  192. const a = this.build[i]
  193. const b = other.build[i]
  194. debug('build compare', i, a, b)
  195. if (a === undefined && b === undefined) {
  196. return 0
  197. } else if (b === undefined) {
  198. return 1
  199. } else if (a === undefined) {
  200. return -1
  201. } else if (a === b) {
  202. continue
  203. } else {
  204. return compareIdentifiers(a, b)
  205. }
  206. } while (++i)
  207. }
  208.  
  209. // preminor will bump the version up to the next minor release, and immediately
  210. // down to pre-release. premajor and prepatch work the same way.
  211. inc (release, identifier, identifierBase) {
  212. if (release.startsWith('pre')) {
  213. if (!identifier && identifierBase === false) {
  214. throw new Error('invalid increment argument: identifier is empty')
  215. }
  216. // Avoid an invalid semver results
  217. if (identifier) {
  218. const r = new RegExp(`^${this.options.loose ? src[t.PRERELEASELOOSE] : src[t.PRERELEASE]}$`)
  219. const match = `-${identifier}`.match(r)
  220. if (!match || match[1] !== identifier) {
  221. throw new Error(`invalid identifier: ${identifier}`)
  222. }
  223. }
  224. }
  225.  
  226. switch (release) {
  227. case 'premajor':
  228. this.prerelease.length = 0
  229. this.patch = 0
  230. this.minor = 0
  231. this.major++
  232. this.inc('pre', identifier, identifierBase)
  233. break
  234. case 'preminor':
  235. this.prerelease.length = 0
  236. this.patch = 0
  237. this.minor++
  238. this.inc('pre', identifier, identifierBase)
  239. break
  240. case 'prepatch':
  241. // If this is already a prerelease, it will bump to the next version
  242. // drop any prereleases that might already exist, since they are not
  243. // relevant at this point.
  244. this.prerelease.length = 0
  245. this.inc('patch', identifier, identifierBase)
  246. this.inc('pre', identifier, identifierBase)
  247. break
  248. // If the input is a non-prerelease version, this acts the same as
  249. // prepatch.
  250. case 'prerelease':
  251. if (this.prerelease.length === 0) {
  252. this.inc('patch', identifier, identifierBase)
  253. }
  254. this.inc('pre', identifier, identifierBase)
  255. break
  256. case 'release':
  257. if (this.prerelease.length === 0) {
  258. throw new Error(`version ${this.raw} is not a prerelease`)
  259. }
  260. this.prerelease.length = 0
  261. break
  262.  
  263. case 'major':
  264. // If this is a pre-major version, bump up to the same major version.
  265. // Otherwise increment major.
  266. // 1.0.0-5 bumps to 1.0.0
  267. // 1.1.0 bumps to 2.0.0
  268. if (
  269. this.minor !== 0 ||
  270. this.patch !== 0 ||
  271. this.prerelease.length === 0
  272. ) {
  273. this.major++
  274. }
  275. this.minor = 0
  276. this.patch = 0
  277. this.prerelease = []
  278. break
  279. case 'minor':
  280. // If this is a pre-minor version, bump up to the same minor version.
  281. // Otherwise increment minor.
  282. // 1.2.0-5 bumps to 1.2.0
  283. // 1.2.1 bumps to 1.3.0
  284. if (this.patch !== 0 || this.prerelease.length === 0) {
  285. this.minor++
  286. }
  287. this.patch = 0
  288. this.prerelease = []
  289. break
  290. case 'patch':
  291. // If this is not a pre-release version, it will increment the patch.
  292. // If it is a pre-release it will bump up to the same patch version.
  293. // 1.2.0-5 patches to 1.2.0
  294. // 1.2.0 patches to 1.2.1
  295. if (this.prerelease.length === 0) {
  296. this.patch++
  297. }
  298. this.prerelease = []
  299. break
  300. // This probably shouldn't be used publicly.
  301. // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.
  302. case 'pre': {
  303. const base = Number(identifierBase) ? 1 : 0
  304.  
  305. if (this.prerelease.length === 0) {
  306. this.prerelease = [base]
  307. } else {
  308. let i = this.prerelease.length
  309. while (--i >= 0) {
  310. if (typeof this.prerelease[i] === 'number') {
  311. this.prerelease[i]++
  312. i = -2
  313. }
  314. }
  315. if (i === -1) {
  316. // didn't increment anything
  317. if (identifier === this.prerelease.join('.') && identifierBase === false) {
  318. throw new Error('invalid increment argument: identifier already exists')
  319. }
  320. this.prerelease.push(base)
  321. }
  322. }
  323. if (identifier) {
  324. // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
  325. // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
  326. let prerelease = [identifier, base]
  327. if (identifierBase === false) {
  328. prerelease = [identifier]
  329. }
  330. if (compareIdentifiers(this.prerelease[0], identifier) === 0) {
  331. if (isNaN(this.prerelease[1])) {
  332. this.prerelease = prerelease
  333. }
  334. } else {
  335. this.prerelease = prerelease
  336. }
  337. }
  338. break
  339. }
  340. default:
  341. throw new Error(`invalid increment argument: ${release}`)
  342. }
  343. this.raw = this.format()
  344. if (this.build.length) {
  345. this.raw += `+${this.build.join('.')}`
  346. }
  347. return this
  348. }
  349. }
  350.  
  351. module.exports = SemVer
  352.  
  353.  
  354. /***/ }),
  355.  
  356. /***/ 560:
  357. /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
  358.  
  359. const SemVer = __webpack_require__(908)
  360. const compare = (a, b, loose) =>
  361. new SemVer(a, loose).compare(new SemVer(b, loose))
  362.  
  363. module.exports = compare
  364.  
  365.  
  366. /***/ }),
  367.  
  368. /***/ 580:
  369. /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
  370.  
  371. const compare = __webpack_require__(560)
  372. const gt = (a, b, loose) => compare(a, b, loose) > 0
  373. module.exports = gt
  374.  
  375.  
  376. /***/ }),
  377.  
  378. /***/ 874:
  379. /***/ ((module) => {
  380.  
  381. // Note: this is the semver.org version of the spec that it implements
  382. // Not necessarily the package version of this code.
  383. const SEMVER_SPEC_VERSION = '2.0.0'
  384.  
  385. const MAX_LENGTH = 256
  386. const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
  387. /* istanbul ignore next */ 9007199254740991
  388.  
  389. // Max safe segment length for coercion.
  390. const MAX_SAFE_COMPONENT_LENGTH = 16
  391.  
  392. // Max safe length for a build identifier. The max length minus 6 characters for
  393. // the shortest version with a build 0.0.0+BUILD.
  394. const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
  395.  
  396. const RELEASE_TYPES = [
  397. 'major',
  398. 'premajor',
  399. 'minor',
  400. 'preminor',
  401. 'patch',
  402. 'prepatch',
  403. 'prerelease',
  404. ]
  405.  
  406. module.exports = {
  407. MAX_LENGTH,
  408. MAX_SAFE_COMPONENT_LENGTH,
  409. MAX_SAFE_BUILD_LENGTH,
  410. MAX_SAFE_INTEGER,
  411. RELEASE_TYPES,
  412. SEMVER_SPEC_VERSION,
  413. FLAG_INCLUDE_PRERELEASE: 0b001,
  414. FLAG_LOOSE: 0b010,
  415. }
  416.  
  417.  
  418. /***/ }),
  419.  
  420. /***/ 272:
  421. /***/ ((module) => {
  422.  
  423. const debug = (
  424. typeof process === 'object' &&
  425. process.env &&
  426. process.env.NODE_DEBUG &&
  427. /\bsemver\b/i.test(process.env.NODE_DEBUG)
  428. ) ? (...args) => console.error('SEMVER', ...args)
  429. : () => {}
  430.  
  431. module.exports = debug
  432.  
  433.  
  434. /***/ }),
  435.  
  436. /***/ 123:
  437. /***/ ((module) => {
  438.  
  439. const numeric = /^[0-9]+$/
  440. const compareIdentifiers = (a, b) => {
  441. const anum = numeric.test(a)
  442. const bnum = numeric.test(b)
  443.  
  444. if (anum && bnum) {
  445. a = +a
  446. b = +b
  447. }
  448.  
  449. return a === b ? 0
  450. : (anum && !bnum) ? -1
  451. : (bnum && !anum) ? 1
  452. : a < b ? -1
  453. : 1
  454. }
  455.  
  456. const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)
  457.  
  458. module.exports = {
  459. compareIdentifiers,
  460. rcompareIdentifiers,
  461. }
  462.  
  463.  
  464. /***/ }),
  465.  
  466. /***/ 587:
  467. /***/ ((module) => {
  468.  
  469. // parse out just the options we care about
  470. const looseOption = Object.freeze({ loose: true })
  471. const emptyOpts = Object.freeze({ })
  472. const parseOptions = options => {
  473. if (!options) {
  474. return emptyOpts
  475. }
  476.  
  477. if (typeof options !== 'object') {
  478. return looseOption
  479. }
  480.  
  481. return options
  482. }
  483. module.exports = parseOptions
  484.  
  485.  
  486. /***/ }),
  487.  
  488. /***/ 718:
  489. /***/ ((module, exports, __webpack_require__) => {
  490.  
  491. const {
  492. MAX_SAFE_COMPONENT_LENGTH,
  493. MAX_SAFE_BUILD_LENGTH,
  494. MAX_LENGTH,
  495. } = __webpack_require__(874)
  496. const debug = __webpack_require__(272)
  497. exports = module.exports = {}
  498.  
  499. // The actual regexps go on exports.re
  500. const re = exports.re = []
  501. const safeRe = exports.safeRe = []
  502. const src = exports.src = []
  503. const safeSrc = exports.safeSrc = []
  504. const t = exports.t = {}
  505. let R = 0
  506.  
  507. const LETTERDASHNUMBER = '[a-zA-Z0-9-]'
  508.  
  509. // Replace some greedy regex tokens to prevent regex dos issues. These regex are
  510. // used internally via the safeRe object since all inputs in this library get
  511. // normalized first to trim and collapse all extra whitespace. The original
  512. // regexes are exported for userland consumption and lower level usage. A
  513. // future breaking change could export the safer regex only with a note that
  514. // all input should have extra whitespace removed.
  515. const safeRegexReplacements = [
  516. ['\\s', 1],
  517. ['\\d', MAX_LENGTH],
  518. [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
  519. ]
  520.  
  521. const makeSafeRegex = (value) => {
  522. for (const [token, max] of safeRegexReplacements) {
  523. value = value
  524. .split(`${token}*`).join(`${token}{0,${max}}`)
  525. .split(`${token}+`).join(`${token}{1,${max}}`)
  526. }
  527. return value
  528. }
  529.  
  530. const createToken = (name, value, isGlobal) => {
  531. const safe = makeSafeRegex(value)
  532. const index = R++
  533. debug(name, index, value)
  534. t[name] = index
  535. src[index] = value
  536. safeSrc[index] = safe
  537. re[index] = new RegExp(value, isGlobal ? 'g' : undefined)
  538. safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)
  539. }
  540.  
  541. // The following Regular Expressions can be used for tokenizing,
  542. // validating, and parsing SemVer version strings.
  543.  
  544. // ## Numeric Identifier
  545. // A single `0`, or a non-zero digit followed by zero or more digits.
  546.  
  547. createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*')
  548. createToken('NUMERICIDENTIFIERLOOSE', '\\d+')
  549.  
  550. // ## Non-numeric Identifier
  551. // Zero or more digits, followed by a letter or hyphen, and then zero or
  552. // more letters, digits, or hyphens.
  553.  
  554. createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)
  555.  
  556. // ## Main Version
  557. // Three dot-separated numeric identifiers.
  558.  
  559. createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` +
  560. `(${src[t.NUMERICIDENTIFIER]})\\.` +
  561. `(${src[t.NUMERICIDENTIFIER]})`)
  562.  
  563. createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
  564. `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
  565. `(${src[t.NUMERICIDENTIFIERLOOSE]})`)
  566.  
  567. // ## Pre-release Version Identifier
  568. // A numeric identifier, or a non-numeric identifier.
  569.  
  570. createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER]
  571. }|${src[t.NONNUMERICIDENTIFIER]})`)
  572.  
  573. createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE]
  574. }|${src[t.NONNUMERICIDENTIFIER]})`)
  575.  
  576. // ## Pre-release Version
  577. // Hyphen, followed by one or more dot-separated pre-release version
  578. // identifiers.
  579.  
  580. createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]
  581. }(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`)
  582.  
  583. createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
  584. }(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)
  585.  
  586. // ## Build Metadata Identifier
  587. // Any combination of digits, letters, or hyphens.
  588.  
  589. createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)
  590.  
  591. // ## Build Metadata
  592. // Plus sign, followed by one or more period-separated build metadata
  593. // identifiers.
  594.  
  595. createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER]
  596. }(?:\\.${src[t.BUILDIDENTIFIER]})*))`)
  597.  
  598. // ## Full Version String
  599. // A main version, followed optionally by a pre-release version and
  600. // build metadata.
  601.  
  602. // Note that the only major, minor, patch, and pre-release sections of
  603. // the version string are capturing groups. The build metadata is not a
  604. // capturing group, because it should not ever be used in version
  605. // comparison.
  606.  
  607. createToken('FULLPLAIN', `v?${src[t.MAINVERSION]
  608. }${src[t.PRERELEASE]}?${
  609. src[t.BUILD]}?`)
  610.  
  611. createToken('FULL', `^${src[t.FULLPLAIN]}$`)
  612.  
  613. // like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
  614. // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
  615. // common in the npm registry.
  616. createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE]
  617. }${src[t.PRERELEASELOOSE]}?${
  618. src[t.BUILD]}?`)
  619.  
  620. createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)
  621.  
  622. createToken('GTLT', '((?:<|>)?=?)')
  623.  
  624. // Something like "2.*" or "1.2.x".
  625. // Note that "x.x" is a valid xRange identifer, meaning "any version"
  626. // Only the first item is strictly required.
  627. createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`)
  628. createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`)
  629.  
  630. createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` +
  631. `(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
  632. `(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
  633. `(?:${src[t.PRERELEASE]})?${
  634. src[t.BUILD]}?` +
  635. `)?)?`)
  636.  
  637. createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +
  638. `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
  639. `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
  640. `(?:${src[t.PRERELEASELOOSE]})?${
  641. src[t.BUILD]}?` +
  642. `)?)?`)
  643.  
  644. createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`)
  645. createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`)
  646.  
  647. // Coercion.
  648. // Extract anything that could conceivably be a part of a valid semver
  649. createToken('COERCEPLAIN', `${'(^|[^\\d])' +
  650. '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +
  651. `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
  652. `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)
  653. createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`)
  654. createToken('COERCEFULL', src[t.COERCEPLAIN] +
  655. `(?:${src[t.PRERELEASE]})?` +
  656. `(?:${src[t.BUILD]})?` +
  657. `(?:$|[^\\d])`)
  658. createToken('COERCERTL', src[t.COERCE], true)
  659. createToken('COERCERTLFULL', src[t.COERCEFULL], true)
  660.  
  661. // Tilde ranges.
  662. // Meaning is "reasonably at or greater than"
  663. createToken('LONETILDE', '(?:~>?)')
  664.  
  665. createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true)
  666. exports.tildeTrimReplace = '$1~'
  667.  
  668. createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)
  669. createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)
  670.  
  671. // Caret ranges.
  672. // Meaning is "at least and backwards compatible with"
  673. createToken('LONECARET', '(?:\\^)')
  674.  
  675. createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true)
  676. exports.caretTrimReplace = '$1^'
  677.  
  678. createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)
  679. createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)
  680.  
  681. // A simple gt/lt/eq thing, or just "" to indicate "any version"
  682. createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`)
  683. createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`)
  684.  
  685. // An expression to strip any whitespace between the gtlt and the thing
  686. // it modifies, so that `> 1.2.3` ==> `>1.2.3`
  687. createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT]
  688. }\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)
  689. exports.comparatorTrimReplace = '$1$2$3'
  690.  
  691. // Something like `1.2.3 - 1.2.4`
  692. // Note that these all use the loose form, because they'll be
  693. // checked against either the strict or loose comparator form
  694. // later.
  695. createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` +
  696. `\\s+-\\s+` +
  697. `(${src[t.XRANGEPLAIN]})` +
  698. `\\s*$`)
  699.  
  700. createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
  701. `\\s+-\\s+` +
  702. `(${src[t.XRANGEPLAINLOOSE]})` +
  703. `\\s*$`)
  704.  
  705. // Star ranges basically just allow anything at all.
  706. createToken('STAR', '(<|>)?=?\\s*\\*')
  707. // >=0.0.0 is like a star
  708. createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$')
  709. createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
  710.  
  711.  
  712. /***/ }),
  713.  
  714. /***/ 891:
  715. /***/ ((module) => {
  716.  
  717. "use strict";
  718. module.exports = /*#__PURE__*/JSON.parse('{"base_url":"https://kxs.rip","fileName":"KxsClient.user.js","match":["://survev.io/","*://66.179.254.36/","://zurviv.io/","://expandedwater.online/","://localhost:3000/","://surviv.wf/","://resurviv.biz/","://82.67.125.203/","://leia-uwu.github.io/survev/","://50v50.online/","://eu-comp.net/","://survev.leia-is.gay/"],"grant":["GM_xmlhttpRequest","GM_info","GM.getValue","GM.setValue"]}');
  719.  
  720. /***/ }),
  721.  
  722. /***/ 330:
  723. /***/ ((module) => {
  724.  
  725. "use strict";
  726. module.exports = /*#__PURE__*/JSON.parse('{"name":"kxsclient","version":"1.2.6","main":"index.js","namespace":"https://github.com/Kisakay/KxsClient","icon":"https://kxs.rip/assets/KysClientLogo.png","placeholder":"Kxs Client - Survev.io Client","scripts":{"test":"echo \\"Error: no test specified\\" && exit 1","commits":"oco --yes; npm version patch; git push;"},"keywords":[],"author":"Kisakay","license":"AGPL-3.0","description":"A client to enhance the survev.io in-game experience with many features, as well as future features.","devDependencies":{"@types/semver":"^7.7.0","@types/tampermonkey":"^5.0.4","ts-loader":"^9.5.1","typescript":"^5.7.2","webpack":"^5.97.1","webpack-cli":"^5.1.4"},"dependencies":{"semver":"^7.7.1"}}');
  727.  
  728. /***/ })
  729.  
  730. /******/ });
  731. /************************************************************************/
  732. /******/ // The module cache
  733. /******/ var __webpack_module_cache__ = {};
  734. /******/
  735. /******/ // The require function
  736. /******/ function __webpack_require__(moduleId) {
  737. /******/ // Check if module is in cache
  738. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  739. /******/ if (cachedModule !== undefined) {
  740. /******/ return cachedModule.exports;
  741. /******/ }
  742. /******/ // Create a new module (and put it into the cache)
  743. /******/ var module = __webpack_module_cache__[moduleId] = {
  744. /******/ // no module.id needed
  745. /******/ // no module.loaded needed
  746. /******/ exports: {}
  747. /******/ };
  748. /******/
  749. /******/ // Execute the module function
  750. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  751. /******/
  752. /******/ // Return the exports of the module
  753. /******/ return module.exports;
  754. /******/ }
  755. /******/
  756. /************************************************************************/
  757. /******/ /* webpack/runtime/compat get default export */
  758. /******/ (() => {
  759. /******/ // getDefaultExport function for compatibility with non-harmony modules
  760. /******/ __webpack_require__.n = (module) => {
  761. /******/ var getter = module && module.__esModule ?
  762. /******/ () => (module['default']) :
  763. /******/ () => (module);
  764. /******/ __webpack_require__.d(getter, { a: getter });
  765. /******/ return getter;
  766. /******/ };
  767. /******/ })();
  768. /******/
  769. /******/ /* webpack/runtime/define property getters */
  770. /******/ (() => {
  771. /******/ // define getter functions for harmony exports
  772. /******/ __webpack_require__.d = (exports, definition) => {
  773. /******/ for(var key in definition) {
  774. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  775. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  776. /******/ }
  777. /******/ }
  778. /******/ };
  779. /******/ })();
  780. /******/
  781. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  782. /******/ (() => {
  783. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  784. /******/ })();
  785. /******/
  786. /************************************************************************/
  787. var __webpack_exports__ = {};
  788. // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
  789. (() => {
  790. "use strict";
  791.  
  792. // EXPORTS
  793. __webpack_require__.d(__webpack_exports__, {
  794. h3: () => (/* binding */ background_image),
  795. fW: () => (/* binding */ kxs_logo)
  796. });
  797.  
  798. // UNUSED EXPORTS: background_song, full_logo
  799.  
  800. ;// ./src/ButtonManager.ts
  801. class MenuButton {
  802. constructor(params) {
  803. var _a;
  804. this.isEnabled = (_a = params.initialState) !== null && _a !== void 0 ? _a : false;
  805. this.button = this.createButton(params);
  806. }
  807. createButton(params) {
  808. const button = document.createElement("button");
  809. // Set initial text
  810. this.updateButtonText(button, params.text);
  811. // Set styles
  812. Object.assign(button.style, {
  813. backgroundColor: this.getBackgroundColor(params.color),
  814. border: "none",
  815. color: "#fff",
  816. padding: "10px",
  817. borderRadius: "5px",
  818. width: "100%",
  819. marginBottom: "10px",
  820. fontSize: "14px",
  821. cursor: "pointer",
  822. });
  823. // Set click handler
  824. button.onclick = () => {
  825. this.isEnabled = !this.isEnabled;
  826. params.onClick();
  827. if (params.updateText !== false) {
  828. this.updateButtonText(button, params.text);
  829. this.updateButtonColor(button, params.color);
  830. }
  831. };
  832. return button;
  833. }
  834. updateButtonText(button, baseText) {
  835. button.textContent = `${baseText} ${this.isEnabled ? "✅" : "❌"}`;
  836. }
  837. getBackgroundColor(color) {
  838. if (color)
  839. return color;
  840. return this.isEnabled ? "#4CAF50" : "#FF0000";
  841. }
  842. updateButtonColor(button, color) {
  843. button.style.backgroundColor = this.getBackgroundColor(color);
  844. }
  845. getElement() {
  846. return this.button;
  847. }
  848. setState(enabled) {
  849. this.isEnabled = enabled;
  850. this.updateButtonColor(this.button);
  851. }
  852. }
  853. class MenuManager {
  854. constructor(menu) {
  855. this.buttons = {};
  856. this.menu = menu;
  857. }
  858. addToggleButton(params) {
  859. const button = new MenuButton({
  860. text: params.text,
  861. initialState: params.initialState,
  862. color: params.color,
  863. onClick: params.onClick,
  864. updateText: params.updateText,
  865. });
  866. this.buttons[params.id] = button;
  867. this.menu.appendChild(button.getElement());
  868. return button;
  869. }
  870. addButton(params) {
  871. var _a;
  872. const button = document.createElement("button");
  873. // Set initial text
  874. button.textContent = params.text;
  875. // Set styles
  876. Object.assign(button.style, {
  877. backgroundColor: (_a = params.color) !== null && _a !== void 0 ? _a : "#007BFF", // Default color
  878. border: "none",
  879. color: "#fff",
  880. padding: "10px",
  881. borderRadius: "5px",
  882. width: "100%",
  883. marginBottom: "10px",
  884. fontSize: "14px",
  885. cursor: "pointer",
  886. });
  887. // Set click handler
  888. button.onclick = params.onClick;
  889. this.menu.appendChild(button);
  890. }
  891. getButton(id) {
  892. return this.buttons[id];
  893. }
  894. }
  895.  
  896.  
  897. ;// ./src/DiscordTracking.ts
  898. var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
  899. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  900. return new (P || (P = Promise))(function (resolve, reject) {
  901. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  902. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  903. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  904. step((generator = generator.apply(thisArg, _arguments || [])).next());
  905. });
  906. };
  907. const stuff_emojis = {
  908. main_weapon: "🔫",
  909. secondary_weapon: "🔫",
  910. grenades: "💣",
  911. melees: "🔪",
  912. soda: "🥤",
  913. medkit: "🩹",
  914. bandage: "🩹",
  915. pills: "💊",
  916. backpack: "🎒",
  917. chest: "📦",
  918. helmet: "⛑️"
  919. };
  920. class WebhookValidator {
  921. static isValidWebhookUrl(url) {
  922. return this.DISCORD_WEBHOOK_REGEX.test(url);
  923. }
  924. static isWebhookAlive(webhookUrl) {
  925. return __awaiter(this, void 0, void 0, function* () {
  926. try {
  927. // First check if the URL format is valid
  928. if (!this.isValidWebhookUrl(webhookUrl)) {
  929. throw new Error("Invalid webhook URL format");
  930. }
  931. // Test the webhook with a GET request (Discord allows GET on webhooks)
  932. const response = yield fetch(webhookUrl, {
  933. method: "GET",
  934. headers: {
  935. "Content-Type": "application/json",
  936. },
  937. });
  938. // Discord returns 200 for valid webhooks
  939. return response.status === 200;
  940. }
  941. catch (error) {
  942. console.error("Error validating webhook:", error);
  943. return false;
  944. }
  945. });
  946. }
  947. static testWebhook(webhookUrl) {
  948. return __awaiter(this, void 0, void 0, function* () {
  949. try {
  950. if (!webhookUrl) {
  951. return {
  952. isValid: false,
  953. message: "Please enter a webhook URL",
  954. };
  955. }
  956. if (!this.isValidWebhookUrl(webhookUrl)) {
  957. return {
  958. isValid: false,
  959. message: "Invalid Discord webhook URL format",
  960. };
  961. }
  962. const isAlive = yield this.isWebhookAlive(webhookUrl);
  963. return {
  964. isValid: isAlive,
  965. message: isAlive
  966. ? "Webhook is valid and working!"
  967. : "Webhook is not responding or has been deleted",
  968. };
  969. }
  970. catch (error) {
  971. return {
  972. isValid: false,
  973. message: "Error testing webhook connection",
  974. };
  975. }
  976. });
  977. }
  978. }
  979. WebhookValidator.DISCORD_WEBHOOK_REGEX = /^https:\/\/discord\.com\/api\/webhooks\/\d+\/[\w-]+$/;
  980. class DiscordTracking {
  981. constructor(kxsClient, webhookUrl) {
  982. this.kxsClient = kxsClient;
  983. this.webhookUrl = webhookUrl;
  984. }
  985. setWebhookUrl(webhookUrl) {
  986. this.webhookUrl = webhookUrl;
  987. }
  988. validateCurrentWebhook() {
  989. return __awaiter(this, void 0, void 0, function* () {
  990. return WebhookValidator.isWebhookAlive(this.webhookUrl);
  991. });
  992. }
  993. sendWebhookMessage(message) {
  994. return __awaiter(this, void 0, void 0, function* () {
  995. if (!WebhookValidator.isValidWebhookUrl(this.webhookUrl)) {
  996. return;
  997. }
  998. this.kxsClient.nm.showNotification("Sending Discord message...", "info", 2300);
  999. try {
  1000. const response = yield fetch(this.webhookUrl, {
  1001. method: "POST",
  1002. headers: {
  1003. "Content-Type": "application/json",
  1004. },
  1005. body: JSON.stringify(message),
  1006. });
  1007. if (!response.ok) {
  1008. throw new Error(`Discord Webhook Error: ${response.status}`);
  1009. }
  1010. }
  1011. catch (error) {
  1012. console.error("Error sending Discord message:", error);
  1013. }
  1014. });
  1015. }
  1016. getEmbedColor(isWin) {
  1017. return isWin ? 0x2ecc71 : 0xe74c3c; // Green for victory, red for defeat
  1018. }
  1019. trackGameEnd(result) {
  1020. return __awaiter(this, void 0, void 0, function* () {
  1021. const title = result.isWin
  1022. ? "🏆 VICTORY ROYALE!"
  1023. : `${result.position} - Game Over`;
  1024. const embed = {
  1025. title,
  1026. description: `${result.username}'s Match`,
  1027. color: this.getEmbedColor(result.isWin),
  1028. fields: [
  1029. {
  1030. name: "💀 Eliminations",
  1031. value: result.kills.toString(),
  1032. inline: true,
  1033. },
  1034. ],
  1035. };
  1036. if (result.duration) {
  1037. embed.fields.push({
  1038. name: "⏱️ Duration",
  1039. value: result.duration,
  1040. inline: true,
  1041. });
  1042. }
  1043. if (result.damageDealt) {
  1044. embed.fields.push({
  1045. name: "💥 Damage Dealt",
  1046. value: Math.round(result.damageDealt).toString(),
  1047. inline: true,
  1048. });
  1049. }
  1050. if (result.damageTaken) {
  1051. embed.fields.push({
  1052. name: "💢 Damage Taken",
  1053. value: Math.round(result.damageTaken).toString(),
  1054. inline: true,
  1055. });
  1056. }
  1057. if (result.username) {
  1058. embed.fields.push({
  1059. name: "📝 Username",
  1060. value: result.username,
  1061. inline: true,
  1062. });
  1063. }
  1064. if (result.stuff) {
  1065. for (const [key, value] of Object.entries(result.stuff)) {
  1066. if (value) {
  1067. embed.fields.push({
  1068. name: `${stuff_emojis[key]} ${key.replace("_", " ").toUpperCase()}`,
  1069. value,
  1070. inline: true,
  1071. });
  1072. }
  1073. }
  1074. }
  1075. const message = {
  1076. username: result.username,
  1077. content: result.isWin ? "🎉 New Victory!" : "Match Ended",
  1078. embeds: [embed],
  1079. };
  1080. yield this.sendWebhookMessage(message);
  1081. });
  1082. }
  1083. }
  1084.  
  1085.  
  1086. ;// ./src/ClientMainMenu.ts
  1087. var ClientMainMenu_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
  1088. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  1089. return new (P || (P = Promise))(function (resolve, reject) {
  1090. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  1091. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  1092. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  1093. step((generator = generator.apply(thisArg, _arguments || [])).next());
  1094. });
  1095. };
  1096.  
  1097.  
  1098. class KxsMainClientMenu {
  1099. constructor(kxsClient) {
  1100. this.kxsClient = kxsClient;
  1101. // this.setupKeyListeners();
  1102. // this.initMenu();
  1103. }
  1104. initMenu() {
  1105. this.menu = document.createElement("div");
  1106. this.menu.id = "kxsMenu";
  1107. Object.assign(this.menu.style, {
  1108. backgroundColor: "rgba(0, 0, 0, 0.8)",
  1109. padding: "15px",
  1110. marginLeft: "15px",
  1111. borderRadius: "10px",
  1112. boxShadow: "0 4px 10px rgba(0, 0, 0, 0.6)",
  1113. zIndex: "10001",
  1114. width: "250px",
  1115. fontFamily: "Arial, sans-serif",
  1116. color: "#fff",
  1117. maxHeight: "400px",
  1118. overflowY: "auto",
  1119. });
  1120. const title = document.createElement("h2");
  1121. title.textContent = "Kxs Client";
  1122. title.style.margin = "0 0 10px";
  1123. title.style.textAlign = "center";
  1124. title.style.fontSize = "18px";
  1125. title.style.color = "#FFAE00";
  1126. this.menu.appendChild(title);
  1127. window.onload = () => {
  1128. const savedBackground = localStorage.getItem("backgroundImage");
  1129. if (savedBackground) {
  1130. const backgroundElement = document.getElementById("background");
  1131. if (backgroundElement) {
  1132. backgroundElement.style.backgroundImage = `url(${savedBackground})`;
  1133. }
  1134. }
  1135. };
  1136. const startRowTop = document.getElementById("start-row-top");
  1137. if (startRowTop) {
  1138. startRowTop.appendChild(this.menu);
  1139. }
  1140. this.menuManager = new MenuManager(this.menu);
  1141. this.menuManager.addToggleButton({
  1142. id: "fps",
  1143. text: "Show FPS",
  1144. initialState: this.kxsClient.isFpsVisible,
  1145. onClick: () => {
  1146. this.kxsClient.isFpsVisible = !this.kxsClient.isFpsVisible;
  1147. this.kxsClient.updateFpsVisibility();
  1148. this.kxsClient.updateLocalStorage();
  1149. },
  1150. });
  1151. this.menuManager.addToggleButton({
  1152. id: "ping",
  1153. text: `Show Ping`,
  1154. initialState: this.kxsClient.isPingVisible,
  1155. onClick: () => {
  1156. this.kxsClient.isPingVisible = !this.kxsClient.isPingVisible;
  1157. this.kxsClient.updatePingVisibility();
  1158. this.kxsClient.updateLocalStorage();
  1159. },
  1160. });
  1161. this.menuManager.addToggleButton({
  1162. id: "kills",
  1163. text: `Show Kills`,
  1164. initialState: this.kxsClient.isKillsVisible,
  1165. onClick: () => {
  1166. this.kxsClient.isKillsVisible = !this.kxsClient.isKillsVisible;
  1167. this.kxsClient.updateKillsVisibility();
  1168. this.kxsClient.updateLocalStorage();
  1169. },
  1170. });
  1171. this.menuManager.addToggleButton({
  1172. id: "uncapFps",
  1173. text: `Uncap FPS`,
  1174. initialState: this.kxsClient.isFpsUncapped,
  1175. onClick: () => {
  1176. this.kxsClient.toggleFpsUncap();
  1177. this.kxsClient.updateLocalStorage();
  1178. },
  1179. });
  1180. this.menuManager.addButton({
  1181. id: "hideShow",
  1182. text: "👀 Hide/Show Menu [P]",
  1183. color: "#6F42C1",
  1184. onClick: () => this.toggleMenuVisibility(),
  1185. });
  1186. this.menuManager.addButton({
  1187. id: "background",
  1188. text: `🎨 Change Background`,
  1189. color: "#007BFF",
  1190. onClick: () => {
  1191. const backgroundElement = document.getElementById("background");
  1192. if (!backgroundElement) {
  1193. alert("Element with id 'background' not found.");
  1194. return;
  1195. }
  1196. const choice = prompt("Enter '1' to provide a URL or '2' to upload a local image:");
  1197. if (choice === "1") {
  1198. const newBackgroundUrl = prompt("Enter the URL of the new background image:");
  1199. if (newBackgroundUrl) {
  1200. backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
  1201. this.kxsClient.saveBackgroundToLocalStorage(newBackgroundUrl);
  1202. alert("Background updated successfully!");
  1203. }
  1204. }
  1205. else if (choice === "2") {
  1206. const fileInput = document.createElement("input");
  1207. fileInput.type = "file";
  1208. fileInput.accept = "image/*";
  1209. fileInput.onchange = (event) => {
  1210. var _a, _b;
  1211. const file = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];
  1212. if (file) {
  1213. const reader = new FileReader();
  1214. reader.onload = () => {
  1215. backgroundElement.style.backgroundImage = `url(${reader.result})`;
  1216. this.kxsClient.saveBackgroundToLocalStorage(file);
  1217. alert("Background updated successfully!");
  1218. };
  1219. reader.readAsDataURL(file);
  1220. }
  1221. };
  1222. fileInput.click();
  1223. }
  1224. },
  1225. });
  1226. this.menuManager.addButton({
  1227. id: "webhook",
  1228. text: `🕸️ Change Discord Webhook`,
  1229. color: "#007BFF",
  1230. onClick: () => ClientMainMenu_awaiter(this, void 0, void 0, function* () {
  1231. const choice = prompt("enter the new discord webhook url:");
  1232. if (choice) {
  1233. const result = yield WebhookValidator.testWebhook(choice);
  1234. if (result.isValid) {
  1235. this.kxsClient.discordWebhookUrl = choice;
  1236. this.kxsClient.discordTracker.setWebhookUrl(choice);
  1237. this.kxsClient.updateLocalStorage();
  1238. alert(result.message);
  1239. }
  1240. else {
  1241. alert(result.message);
  1242. }
  1243. }
  1244. }),
  1245. });
  1246. }
  1247. setupKeyListeners() {
  1248. document.addEventListener("keydown", (event) => {
  1249. if (event.key.toLowerCase() === "p") {
  1250. this.toggleMenuVisibility();
  1251. }
  1252. });
  1253. }
  1254. toggleMenuVisibility() {
  1255. var _a;
  1256. const isVisible = ((_a = this.menu) === null || _a === void 0 ? void 0 : _a.style.display) !== "none";
  1257. this.menu.style.display = isVisible ? "none" : "block";
  1258. }
  1259. }
  1260.  
  1261.  
  1262. ;// ./src/Ping.ts
  1263. class PingTest {
  1264. constructor(selectedServer) {
  1265. this.ptcDataBuf = new ArrayBuffer(1);
  1266. this.test = {
  1267. region: selectedServer.region,
  1268. url: selectedServer.url.startsWith("ws://") || selectedServer.url.startsWith("wss://")
  1269. ? selectedServer.url
  1270. : `https://${selectedServer.url}`, // Store the base URL without /ping for HTTP
  1271. ping: 0, // Initialize to 0 instead of 9999
  1272. ws: null,
  1273. sendTime: 0,
  1274. retryCount: 0,
  1275. isConnecting: false,
  1276. isWebSocket: selectedServer.url.startsWith("ws://") || selectedServer.url.startsWith("wss://"),
  1277. };
  1278. }
  1279. //check to see if urls match
  1280. getMatchingGameUrl() {
  1281. const gameUrls = [
  1282. "*://survev.io/*",
  1283. "*://66.179.254.36/*",
  1284. "*://zurviv.io/*",
  1285. "*://expandedwater.online/*",
  1286. "*://localhost:3000/*",
  1287. "*://surviv.wf/*",
  1288. "*://resurviv.biz/*",
  1289. "*://82.67.125.203/*",
  1290. "*://leia-uwu.github.io/survev/*",
  1291. "*://50v50.online/*",
  1292. "*://eu-comp.net/*",
  1293. "*://survev.leia-is.gay/*"
  1294. ];
  1295. const currentDomain = window.location.hostname;
  1296. for (let i = 0; i < gameUrls.length; i++) {
  1297. const url = new URL(gameUrls[i].replace('*://', 'http://'));
  1298. if (currentDomain === url.hostname) {
  1299. return gameUrls[i];
  1300. }
  1301. }
  1302. console.warn("No matching game URL found for the current domain");
  1303. return null;
  1304. }
  1305. startPingTest() {
  1306. if (this.test.isConnecting)
  1307. return;
  1308. this.test.isConnecting = true;
  1309. // We don't need to replace the URL with a matching game URL
  1310. // because we want to test the ping to the specific server selected
  1311. // The URL was already properly set in the constructor
  1312. if (this.test.isWebSocket) {
  1313. try {
  1314. const ws = new WebSocket(this.test.url);
  1315. ws.binaryType = "arraybuffer";
  1316. ws.onopen = () => {
  1317. this.test.ws = ws;
  1318. this.test.isConnecting = false;
  1319. this.test.retryCount = 0;
  1320. this.sendPing();
  1321. };
  1322. ws.onmessage = (event) => {
  1323. if (this.test.sendTime === 0)
  1324. return;
  1325. const elapsed = Date.now() - this.test.sendTime;
  1326. this.test.ping = Math.min(Math.round(elapsed), 999);
  1327. setTimeout(() => this.sendPing(), 250);
  1328. };
  1329. ws.onerror = (error) => {
  1330. console.error("WebSocket error:", error);
  1331. this.handleConnectionError();
  1332. };
  1333. ws.onclose = () => {
  1334. this.test.ws = null;
  1335. this.test.isConnecting = false;
  1336. if (this.test.retryCount < 3) {
  1337. setTimeout(() => this.startPingTest(), 1000);
  1338. }
  1339. };
  1340. }
  1341. catch (error) {
  1342. console.error("Failed to create WebSocket:", error);
  1343. this.handleConnectionError();
  1344. }
  1345. }
  1346. else {
  1347. this.sendHttpPing();
  1348. }
  1349. }
  1350. sendHttpPing() {
  1351. // Use image loading technique to avoid CORS issues
  1352. this.test.sendTime = Date.now();
  1353. // Create a new image element
  1354. const img = new Image();
  1355. // Set up load and error handlers
  1356. img.onload = () => {
  1357. const elapsed = Date.now() - this.test.sendTime;
  1358. this.test.ping = Math.min(Math.round(elapsed), 999);
  1359. setTimeout(() => this.sendHttpPing(), 250);
  1360. };
  1361. img.onerror = () => {
  1362. // Even if the image fails to load, we can still measure the time it took to fail
  1363. // This gives us an approximate ping time
  1364. const elapsed = Date.now() - this.test.sendTime;
  1365. this.test.ping = Math.min(Math.round(elapsed), 999);
  1366. setTimeout(() => this.sendHttpPing(), 250);
  1367. };
  1368. // Add a cache-busting parameter to prevent caching
  1369. const cacheBuster = Date.now();
  1370. const baseUrl = this.test.url.replace('/ping', '');
  1371. img.src = `${baseUrl}/favicon.ico?cb=${cacheBuster}`;
  1372. }
  1373. handleConnectionError() {
  1374. this.test.ping = 0;
  1375. this.test.isConnecting = false;
  1376. this.test.retryCount++;
  1377. if (this.test.ws) {
  1378. this.test.ws.close();
  1379. this.test.ws = null;
  1380. }
  1381. if (this.test.retryCount < 3) {
  1382. setTimeout(() => this.startPingTest(), 1000);
  1383. }
  1384. }
  1385. sendPing() {
  1386. if (this.test.isWebSocket) {
  1387. if (!this.test.ws || this.test.ws.readyState !== WebSocket.OPEN) {
  1388. this.handleConnectionError();
  1389. return;
  1390. }
  1391. try {
  1392. this.test.sendTime = Date.now();
  1393. this.test.ws.send(this.ptcDataBuf);
  1394. }
  1395. catch (error) {
  1396. console.error("Failed to send ping:", error);
  1397. this.handleConnectionError();
  1398. }
  1399. }
  1400. }
  1401. getPingResult() {
  1402. return {
  1403. region: this.test.region,
  1404. ping: this.test.ping || 0,
  1405. };
  1406. }
  1407. }
  1408. class PingManager {
  1409. constructor() {
  1410. this.currentServer = null;
  1411. this.pingTest = null;
  1412. }
  1413. startPingTest() {
  1414. const currentUrl = window.location.href;
  1415. const isSpecialUrl = /\/#\w+/.test(currentUrl);
  1416. const teamSelectElement = document.getElementById("team-server-select");
  1417. const mainSelectElement = document.getElementById("server-select-main");
  1418. const region = isSpecialUrl && teamSelectElement
  1419. ? teamSelectElement.value
  1420. : mainSelectElement
  1421. ? mainSelectElement.value
  1422. : null;
  1423. if (!region || region === this.currentServer)
  1424. return;
  1425. this.currentServer = region;
  1426. this.resetPing();
  1427. const servers = [
  1428. { region: "NA", url: "usr.mathsiscoolfun.com:8001" },
  1429. { region: "EU", url: "eur.mathsiscoolfun.com:8001" },
  1430. { region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
  1431. { region: "SA", url: "sa.mathsiscoolfun.com:8001" },
  1432. ];
  1433. const selectedServer = servers.find((server) => region.toUpperCase() === server.region.toUpperCase());
  1434. if (selectedServer) {
  1435. this.pingTest = new PingTest(selectedServer);
  1436. this.pingTest.startPingTest();
  1437. }
  1438. }
  1439. resetPing() {
  1440. var _a;
  1441. if ((_a = this.pingTest) === null || _a === void 0 ? void 0 : _a.test.ws) {
  1442. this.pingTest.test.ws.close();
  1443. this.pingTest.test.ws = null;
  1444. }
  1445. this.pingTest = null;
  1446. }
  1447. getPingResult() {
  1448. var _a;
  1449. return ((_a = this.pingTest) === null || _a === void 0 ? void 0 : _a.getPingResult()) || { region: "", ping: 0 };
  1450. }
  1451. }
  1452.  
  1453.  
  1454. ;// ./src/ClientHUD.ts
  1455.  
  1456. class KxsClientHUD {
  1457. constructor(kxsClient) {
  1458. this.healthAnimations = [];
  1459. this.lastHealthValue = 100;
  1460. this.kxsClient = kxsClient;
  1461. this.frameCount = 0;
  1462. this.fps = 0;
  1463. this.kills = 0;
  1464. this.isMenuVisible = true;
  1465. this.pingManager = new PingManager();
  1466. if (this.kxsClient.isPingVisible) {
  1467. this.initCounter("ping", "Ping", "45ms");
  1468. }
  1469. if (this.kxsClient.isFpsVisible) {
  1470. this.initCounter("fps", "FPS", "60");
  1471. }
  1472. if (this.kxsClient.isKillsVisible) {
  1473. this.initCounter("kills", "Kills", "0");
  1474. }
  1475. this.setupWeaponBorderHandler();
  1476. this.startUpdateLoop();
  1477. this.escapeMenu();
  1478. this.initFriendDetector();
  1479. if (this.kxsClient.isKillFeedBlint) {
  1480. if (document.readyState === 'loading') {
  1481. document.addEventListener('DOMContentLoaded', this.initKillFeed);
  1482. }
  1483. else {
  1484. this.initKillFeed();
  1485. }
  1486. }
  1487. }
  1488. initFriendDetector() {
  1489. // Initialize friends list
  1490. let all_friends = this.kxsClient.all_friends.split(',') || [];
  1491. if (all_friends.length >= 1) {
  1492. // Create a cache for detected friends
  1493. // Structure will be: { "friendName": timestamp }
  1494. const friendsCache = {};
  1495. // Cache duration in milliseconds (4 minutes = 240000 ms)
  1496. const cacheDuration = 4 * 60 * 1000;
  1497. // Select the element containing kill feeds
  1498. const killfeedContents = document.querySelector('#ui-killfeed-contents');
  1499. if (killfeedContents) {
  1500. // Keep track of last seen content for each div
  1501. const lastSeenContent = {
  1502. "ui-killfeed-0": "",
  1503. "ui-killfeed-1": "",
  1504. "ui-killfeed-2": "",
  1505. "ui-killfeed-3": "",
  1506. "ui-killfeed-4": "",
  1507. "ui-killfeed-5": ""
  1508. };
  1509. // Function to check if a friend is in the text with cache management
  1510. const checkForFriends = (text, divId) => {
  1511. // If the text is identical to the last seen, ignore
  1512. // @ts-ignore
  1513. if (text === lastSeenContent[divId])
  1514. return;
  1515. // Update the last seen content
  1516. // @ts-ignore
  1517. lastSeenContent[divId] = text;
  1518. // Ignore empty messages
  1519. if (!text.trim())
  1520. return;
  1521. // Current timestamp
  1522. const currentTime = Date.now();
  1523. // Check if a friend is mentioned
  1524. for (let friend of all_friends) {
  1525. if (friend !== "" && text.includes(friend)) {
  1526. // Check if the friend is in the cache and if the cache is still valid
  1527. // @ts-ignore
  1528. const lastSeen = friendsCache[friend];
  1529. if (!lastSeen || (currentTime - lastSeen > cacheDuration)) {
  1530. // Update the cache
  1531. // @ts-ignore
  1532. friendsCache[friend] = currentTime;
  1533. // Display notification
  1534. this.kxsClient.nm.showNotification(`[FriendDetector] ${friend} is in this game`, "info", 2300);
  1535. }
  1536. break;
  1537. }
  1538. }
  1539. };
  1540. // Function to check all kill feeds
  1541. const checkAllKillfeeds = () => {
  1542. all_friends = this.kxsClient.all_friends.split(',') || [];
  1543. for (let i = 0; i <= 5; i++) {
  1544. const divId = `ui-killfeed-${i}`;
  1545. const killDiv = document.getElementById(divId);
  1546. if (killDiv) {
  1547. const textElement = killDiv.querySelector('.killfeed-text');
  1548. if (textElement && textElement.textContent) {
  1549. checkForFriends(textElement.textContent, divId);
  1550. }
  1551. }
  1552. }
  1553. };
  1554. // Observe style or text changes in the entire container
  1555. const observer = new MutationObserver(() => {
  1556. checkAllKillfeeds();
  1557. });
  1558. // Start observing with a configuration that detects all changes
  1559. observer.observe(killfeedContents, {
  1560. childList: true, // Observe changes to child elements
  1561. subtree: true, // Observe the entire tree
  1562. characterData: true, // Observe text changes
  1563. attributes: true // Observe attribute changes (like style/opacity)
  1564. });
  1565. // Check current content immediately
  1566. checkAllKillfeeds();
  1567. console.log("Friend detector initialized with 4-minute cache");
  1568. }
  1569. else {
  1570. console.warn("Killfeed-contents element not found");
  1571. }
  1572. }
  1573. }
  1574. initKillFeed() {
  1575. this.applyCustomStyles();
  1576. this.setupObserver();
  1577. }
  1578. escapeMenu() {
  1579. const customStyles = `
  1580. .ui-game-menu-desktop {
  1581. background: linear-gradient(135deg, rgba(25, 25, 35, 0.95) 0%, rgba(15, 15, 25, 0.98) 100%) !important;
  1582. border: 1px solid rgba(255, 255, 255, 0.1) !important;
  1583. border-radius: 12px !important;
  1584. box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
  1585. padding: 20px !important;
  1586. backdrop-filter: blur(10px) !important;
  1587. max-width: 350px !important;
  1588. /* max-height: 80vh !important; */ /* Optional: Limit the maximum height */
  1589. margin: auto !important;
  1590. box-sizing: border-box !important;
  1591. overflow-y: auto !important; /* Allow vertical scrolling if necessary */
  1592. }
  1593. /* Style pour les boutons de mode de jeu qui ont une image de fond */
  1594. .btn-mode-cobalt,
  1595. [style*="background: url("] {
  1596. background-repeat: no-repeat !important;
  1597. background-position: right center !important;
  1598. background-size: auto 80% !important;
  1599. position: relative !important;
  1600. padding-right: 40px !important;
  1601. }
  1602. /* Ne pas appliquer ce style aux boutons standards comme Play Solo */
  1603. #btn-start-mode-0 {
  1604. background-repeat: initial !important;
  1605. background-position: initial !important;
  1606. background-size: initial !important;
  1607. padding-right: initial !important;
  1608. }
  1609.  
  1610. .ui-game-menu-desktop::-webkit-scrollbar {
  1611. width: 8px !important;
  1612. }
  1613. .ui-game-menu-desktop::-webkit-scrollbar-track {
  1614. background: rgba(25, 25, 35, 0.5) !important;
  1615. border-radius: 10px !important;
  1616. }
  1617. .ui-game-menu-desktop::-webkit-scrollbar-thumb {
  1618. background-color: #4287f5 !important;
  1619. border-radius: 10px !important;
  1620. border: 2px solid rgba(25, 25, 35, 0.5) !important;
  1621. }
  1622. .ui-game-menu-desktop::-webkit-scrollbar-thumb:hover {
  1623. background-color: #5a9eff !important;
  1624. }
  1625.  
  1626. .ui-game-menu-desktop {
  1627. scrollbar-width: thin !important;
  1628. scrollbar-color: #4287f5 rgba(25, 25, 35, 0.5) !important;
  1629. }
  1630.  
  1631. .kxs-header {
  1632. display: flex;
  1633. align-items: center;
  1634. justify-content: flex-start;
  1635. margin-bottom: 20px;
  1636. padding: 10px;
  1637. border-bottom: 2px solid rgba(255, 255, 255, 0.1);
  1638. }
  1639.  
  1640. .kxs-logo {
  1641. width: 30px;
  1642. height: 30px;
  1643. margin-right: 10px;
  1644. border-radius: 6px;
  1645. }
  1646.  
  1647. .kxs-title {
  1648. font-size: 20px;
  1649. font-weight: 700;
  1650. color: #ffffff;
  1651. text-transform: uppercase;
  1652. text-shadow: 0 0 10px rgba(66, 135, 245, 0.5);
  1653. font-family: 'Arial', sans-serif;
  1654. letter-spacing: 2px;
  1655. }
  1656.  
  1657. .kxs-title span {
  1658. color: #4287f5;
  1659. }
  1660. .btn-game-menu {
  1661. background: linear-gradient(135deg, rgba(66, 135, 245, 0.1) 0%, rgba(66, 135, 245, 0.2) 100%) !important;
  1662. border: 1px solid rgba(66, 135, 245, 0.3) !important;
  1663. border-radius: 8px !important;
  1664. color: #ffffff !important;
  1665. transition: all 0.3s ease !important;
  1666. margin: 5px 0 !important;
  1667. padding: 12px !important;
  1668. font-weight: 600 !important;
  1669. width: 100% !important;
  1670. text-align: center !important;
  1671. display: block !important;
  1672. box-sizing: border-box !important;
  1673. }
  1674.  
  1675. .btn-game-menu:hover {
  1676. background: linear-gradient(135deg, rgba(66, 135, 245, 0.2) 0%, rgba(66, 135, 245, 0.3) 100%) !important;
  1677. transform: translateY(-2px) !important;
  1678. box-shadow: 0 4px 12px rgba(66, 135, 245, 0.2) !important;
  1679. }
  1680.  
  1681. .slider-container {
  1682. background: rgba(66, 135, 245, 0.1) !important;
  1683. border-radius: 8px !important;
  1684. padding: 10px 15px !important;
  1685. margin: 10px 0 !important;
  1686. width: 100% !important;
  1687. box-sizing: border-box !important;
  1688. }
  1689.  
  1690. .slider-text {
  1691. color: #ffffff !important;
  1692. font-size: 14px !important;
  1693. margin-bottom: 8px !important;
  1694. text-align: center !important;
  1695. }
  1696.  
  1697. .slider {
  1698. -webkit-appearance: none !important;
  1699. width: 100% !important;
  1700. height: 6px !important;
  1701. border-radius: 3px !important;
  1702. background: rgba(66, 135, 245, 0.3) !important;
  1703. outline: none !important;
  1704. margin: 10px 0 !important;
  1705. }
  1706.  
  1707. .slider::-webkit-slider-thumb {
  1708. -webkit-appearance: none !important;
  1709. width: 16px !important;
  1710. height: 16px !important;
  1711. border-radius: 50% !important;
  1712. background: #4287f5 !important;
  1713. cursor: pointer !important;
  1714. transition: all 0.3s ease !important;
  1715. }
  1716.  
  1717. .slider::-webkit-slider-thumb:hover {
  1718. transform: scale(1.2) !important;
  1719. box-shadow: 0 0 10px rgba(66, 135, 245, 0.5) !important;
  1720. }
  1721.  
  1722. .btns-game-double-row {
  1723. display: flex !important;
  1724. justify-content: center !important;
  1725. gap: 10px !important;
  1726. margin-bottom: 10px !important;
  1727. width: 100% !important;
  1728. }
  1729.  
  1730. .btn-game-container {
  1731. flex: 1 !important;
  1732. }
  1733. `;
  1734. const addCustomStyles = () => {
  1735. const styleElement = document.createElement('style');
  1736. styleElement.textContent = customStyles;
  1737. document.head.appendChild(styleElement);
  1738. };
  1739. const addKxsHeader = () => {
  1740. const menuContainer = document.querySelector('#ui-game-menu');
  1741. if (!menuContainer)
  1742. return;
  1743. const header = document.createElement('div');
  1744. header.className = 'kxs-header';
  1745. const title = document.createElement('span');
  1746. title.className = 'kxs-title';
  1747. title.innerHTML = '<span>Kxs</span> CLIENT';
  1748. header.appendChild(title);
  1749. menuContainer.insertBefore(header, menuContainer.firstChild);
  1750. };
  1751. if (document.querySelector('#ui-game-menu')) {
  1752. addCustomStyles();
  1753. addKxsHeader();
  1754. }
  1755. }
  1756. handleMessage(element) {
  1757. if (element instanceof HTMLElement && element.classList.contains('killfeed-div')) {
  1758. const killfeedText = element.querySelector('.killfeed-text');
  1759. if (killfeedText instanceof HTMLElement) {
  1760. if (killfeedText.textContent && killfeedText.textContent.trim() !== '') {
  1761. if (!killfeedText.hasAttribute('data-glint')) {
  1762. killfeedText.setAttribute('data-glint', 'true');
  1763. element.style.opacity = '1';
  1764. setTimeout(() => {
  1765. element.style.opacity = '0';
  1766. }, 5000);
  1767. }
  1768. }
  1769. else {
  1770. element.style.opacity = '0';
  1771. }
  1772. }
  1773. }
  1774. }
  1775. setupObserver() {
  1776. const killfeedContents = document.getElementById('ui-killfeed-contents');
  1777. if (killfeedContents) {
  1778. const observer = new MutationObserver((mutations) => {
  1779. mutations.forEach((mutation) => {
  1780. if (mutation.target instanceof HTMLElement &&
  1781. mutation.target.classList.contains('killfeed-text')) {
  1782. const parentDiv = mutation.target.closest('.killfeed-div');
  1783. if (parentDiv) {
  1784. this.handleMessage(parentDiv);
  1785. }
  1786. }
  1787. mutation.addedNodes.forEach((node) => {
  1788. if (node instanceof HTMLElement) {
  1789. this.handleMessage(node);
  1790. }
  1791. });
  1792. });
  1793. });
  1794. observer.observe(killfeedContents, {
  1795. childList: true,
  1796. subtree: true,
  1797. characterData: true,
  1798. attributes: true,
  1799. attributeFilter: ['style', 'class']
  1800. });
  1801. killfeedContents.querySelectorAll('.killfeed-div').forEach(this.handleMessage);
  1802. }
  1803. }
  1804. applyCustomStyles() {
  1805. const customStyles = document.createElement('style');
  1806. if (this.kxsClient.isKillFeedBlint) {
  1807. customStyles.innerHTML = `
  1808. @import url('https://fonts.googleapis.com/css2?family=Oxanium:wght@600&display=swap');
  1809. .killfeed-div {
  1810. position: absolute !important;
  1811. padding: 5px 10px !important;
  1812. background: rgba(0, 0, 0, 0.7) !important;
  1813. border-radius: 5px !important;
  1814. transition: opacity 0.5s ease-out !important;
  1815. }
  1816. .killfeed-text {
  1817. font-family: 'Oxanium', sans-serif !important;
  1818. font-weight: bold !important;
  1819. font-size: 16px !important;
  1820. text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) !important;
  1821. background: linear-gradient(90deg,
  1822. rgb(255, 0, 0),
  1823. rgb(255, 127, 0),
  1824. rgb(255, 255, 0),
  1825. rgb(0, 255, 0),
  1826. rgb(0, 0, 255),
  1827. rgb(75, 0, 130),
  1828. rgb(148, 0, 211),
  1829. rgb(255, 0, 0));
  1830. background-size: 200%;
  1831. -webkit-background-clip: text;
  1832. -webkit-text-fill-color: transparent;
  1833. animation: glint 3s linear infinite;
  1834. }
  1835. @keyframes glint {
  1836. 0% {
  1837. background-position: 200% 0;
  1838. }
  1839. 100% {
  1840. background-position: -200% 0;
  1841. }
  1842. }
  1843. .killfeed-div .killfeed-text:empty {
  1844. display: none !important;
  1845. }
  1846. `;
  1847. }
  1848. else {
  1849. customStyles.innerHTML = `
  1850. .killfeed-div {
  1851. position: absolute;
  1852. padding: 5px 10px;
  1853. background: rgba(0, 0, 0, 0.7);
  1854. border-radius: 5px;
  1855. transition: opacity 0.5s ease-out;
  1856. }
  1857. .killfeed-text {
  1858. font-family: inherit;
  1859. font-weight: normal;
  1860. font-size: inherit;
  1861. color: inherit;
  1862. text-shadow: none;
  1863. background: none;
  1864. }
  1865. .killfeed-div .killfeed-text:empty {
  1866. display: none;
  1867. }
  1868. `;
  1869. }
  1870. document.head.appendChild(customStyles);
  1871. }
  1872. handleResize() {
  1873. const viewportWidth = window.innerWidth;
  1874. const viewportHeight = window.innerHeight;
  1875. for (const name of ['fps', 'kills', 'ping']) {
  1876. const counterContainer = document.getElementById(`${name}CounterContainer`);
  1877. if (!counterContainer)
  1878. continue;
  1879. const counter = this.kxsClient.counters[name];
  1880. if (!counter)
  1881. continue;
  1882. const rect = counterContainer.getBoundingClientRect();
  1883. const savedPosition = this.getSavedPosition(name);
  1884. let newPosition = this.calculateSafePosition(savedPosition, rect.width, rect.height, viewportWidth, viewportHeight);
  1885. this.applyPosition(counterContainer, newPosition);
  1886. this.savePosition(name, newPosition);
  1887. }
  1888. }
  1889. calculateSafePosition(currentPosition, elementWidth, elementHeight, viewportWidth, viewportHeight) {
  1890. let { left, top } = currentPosition;
  1891. if (left + elementWidth > viewportWidth) {
  1892. left = viewportWidth - elementWidth;
  1893. }
  1894. if (left < 0) {
  1895. left = 0;
  1896. }
  1897. if (top + elementHeight > viewportHeight) {
  1898. top = viewportHeight - elementHeight;
  1899. }
  1900. if (top < 0) {
  1901. top = 0;
  1902. }
  1903. return { left, top };
  1904. }
  1905. getSavedPosition(name) {
  1906. const savedPosition = localStorage.getItem(`${name}CounterPosition`);
  1907. if (savedPosition) {
  1908. try {
  1909. return JSON.parse(savedPosition);
  1910. }
  1911. catch (_a) {
  1912. return this.kxsClient.defaultPositions[name];
  1913. }
  1914. }
  1915. return this.kxsClient.defaultPositions[name];
  1916. }
  1917. applyPosition(element, position) {
  1918. element.style.left = `${position.left}px`;
  1919. element.style.top = `${position.top}px`;
  1920. }
  1921. savePosition(name, position) {
  1922. localStorage.setItem(`${name}CounterPosition`, JSON.stringify(position));
  1923. }
  1924. startUpdateLoop() {
  1925. var _a;
  1926. const now = performance.now();
  1927. const delta = now - this.kxsClient.lastFrameTime;
  1928. this.frameCount++;
  1929. if (delta >= 1000) {
  1930. this.fps = Math.round((this.frameCount * 1000) / delta);
  1931. this.frameCount = 0;
  1932. this.kxsClient.lastFrameTime = now;
  1933. this.kills = this.kxsClient.getKills();
  1934. if (this.kxsClient.isFpsVisible && this.kxsClient.counters.fps) {
  1935. this.kxsClient.counters.fps.textContent = `FPS: ${this.fps}`;
  1936. }
  1937. if (this.kxsClient.isKillsVisible && this.kxsClient.counters.kills) {
  1938. this.kxsClient.counters.kills.textContent = `Kills: ${this.kills}`;
  1939. }
  1940. if (this.kxsClient.isPingVisible &&
  1941. this.kxsClient.counters.ping &&
  1942. this.pingManager) {
  1943. const result = this.pingManager.getPingResult();
  1944. this.kxsClient.counters.ping.textContent = `PING: ${result.ping} ms`;
  1945. }
  1946. }
  1947. this.pingManager.startPingTest();
  1948. if (this.kxsClient.animationFrameCallback) {
  1949. this.kxsClient.animationFrameCallback(() => this.startUpdateLoop());
  1950. }
  1951. this.updateUiElements();
  1952. this.updateBoostBars();
  1953. this.updateHealthBars();
  1954. (_a = this.kxsClient.kill_leader) === null || _a === void 0 ? void 0 : _a.update(this.kills);
  1955. }
  1956. initCounter(name, label, initialText) {
  1957. const counter = document.createElement("div");
  1958. counter.id = `${name}Counter`;
  1959. const counterContainer = document.createElement("div");
  1960. counterContainer.id = `${name}CounterContainer`;
  1961. Object.assign(counterContainer.style, {
  1962. position: "absolute",
  1963. left: `${this.kxsClient.defaultPositions[name].left}px`,
  1964. top: `${this.kxsClient.defaultPositions[name].top}px`,
  1965. zIndex: "10000",
  1966. });
  1967. Object.assign(counter.style, {
  1968. color: "white",
  1969. backgroundColor: "rgba(0, 0, 0, 0.2)",
  1970. borderRadius: "5px",
  1971. fontFamily: "Arial, sans-serif",
  1972. padding: "5px 10px",
  1973. pointerEvents: "none",
  1974. cursor: "default",
  1975. width: `${this.kxsClient.defaultSizes[name].width}px`,
  1976. height: `${this.kxsClient.defaultSizes[name].height}px`,
  1977. display: "flex",
  1978. alignItems: "center",
  1979. justifyContent: "center",
  1980. textAlign: "center",
  1981. resize: "both",
  1982. overflow: "hidden",
  1983. });
  1984. counter.textContent = `${label}: ${initialText}`;
  1985. counterContainer.appendChild(counter);
  1986. const uiTopLeft = document.getElementById("ui-top-left");
  1987. if (uiTopLeft) {
  1988. uiTopLeft.appendChild(counterContainer);
  1989. }
  1990. const adjustFontSize = () => {
  1991. const { width, height } = counter.getBoundingClientRect();
  1992. const size = Math.min(width, height) * 0.4;
  1993. counter.style.fontSize = `${size}px`;
  1994. };
  1995. new ResizeObserver(adjustFontSize).observe(counter);
  1996. counter.addEventListener("mousedown", (event) => {
  1997. if (event.button === 1) {
  1998. this.resetCounter(name, label, initialText);
  1999. event.preventDefault();
  2000. }
  2001. });
  2002. this.kxsClient.makeDraggable(counterContainer, `${name}CounterPosition`);
  2003. this.kxsClient.counters[name] = counter;
  2004. }
  2005. resetCounter(name, label, initialText) {
  2006. const counter = this.kxsClient.counters[name];
  2007. const container = document.getElementById(`${name}CounterContainer`);
  2008. if (!counter || !container)
  2009. return;
  2010. // Reset only this counter's position and size
  2011. Object.assign(container.style, {
  2012. left: `${this.kxsClient.defaultPositions[name].left}px`,
  2013. top: `${this.kxsClient.defaultPositions[name].top}px`,
  2014. });
  2015. Object.assign(counter.style, {
  2016. width: `${this.kxsClient.defaultSizes[name].width}px`,
  2017. height: `${this.kxsClient.defaultSizes[name].height}px`,
  2018. fontSize: "18px",
  2019. });
  2020. counter.textContent = `${label}: ${initialText}`;
  2021. // Clear the saved position for this counter only
  2022. localStorage.removeItem(`${name}CounterPosition`);
  2023. }
  2024. updateBoostBars() {
  2025. const boostCounter = document.querySelector("#ui-boost-counter");
  2026. if (boostCounter) {
  2027. const boostBars = boostCounter.querySelectorAll(".ui-boost-base .ui-bar-inner");
  2028. let totalBoost = 0;
  2029. const weights = [25, 25, 40, 10];
  2030. boostBars.forEach((bar, index) => {
  2031. const width = parseFloat(bar.style.width);
  2032. if (!isNaN(width)) {
  2033. totalBoost += width * (weights[index] / 100);
  2034. }
  2035. });
  2036. const averageBoost = Math.round(totalBoost);
  2037. let boostDisplay = boostCounter.querySelector(".boost-display");
  2038. if (!boostDisplay) {
  2039. boostDisplay = document.createElement("div");
  2040. boostDisplay.classList.add("boost-display");
  2041. Object.assign(boostDisplay.style, {
  2042. position: "absolute",
  2043. bottom: "75px",
  2044. right: "335px",
  2045. color: "#FF901A",
  2046. backgroundColor: "rgba(0, 0, 0, 0.4)",
  2047. padding: "5px 10px",
  2048. borderRadius: "5px",
  2049. fontFamily: "Arial, sans-serif",
  2050. fontSize: "14px",
  2051. zIndex: "10",
  2052. textAlign: "center",
  2053. });
  2054. boostCounter.appendChild(boostDisplay);
  2055. }
  2056. boostDisplay.textContent = `AD: ${averageBoost}%`;
  2057. }
  2058. }
  2059. setupWeaponBorderHandler() {
  2060. const weaponContainers = Array.from(document.getElementsByClassName("ui-weapon-switch"));
  2061. weaponContainers.forEach((container) => {
  2062. if (container.id === "ui-weapon-id-4") {
  2063. container.style.border = "3px solid #2f4032";
  2064. }
  2065. else {
  2066. container.style.border = "3px solid #FFFFFF";
  2067. }
  2068. });
  2069. const weaponNames = Array.from(document.getElementsByClassName("ui-weapon-name"));
  2070. const WEAPON_COLORS = {
  2071. ORANGE: '#FFAE00',
  2072. BLUE: '#007FFF',
  2073. GREEN: '#0f690d',
  2074. RED: '#FF0000',
  2075. BLACK: '#000000',
  2076. OLIVE: '#808000',
  2077. ORANGE_RED: '#FF4500',
  2078. PURPLE: '#800080',
  2079. TEAL: '#008080',
  2080. BROWN: '#A52A2A',
  2081. PINK: '#FFC0CB',
  2082. DEFAULT: '#FFFFFF'
  2083. };
  2084. const WEAPON_COLOR_MAPPING = {
  2085. ORANGE: ['CZ-3A1', 'G18C', 'M9', 'M93R', 'MAC-10', 'MP5', 'P30L', 'DUAL P30L', 'UMP9', 'VECTOR', 'VSS', 'FLAMETHROWER'],
  2086. BLUE: ['AK-47', 'OT-38', 'OTS-38', 'M39 EMR', 'DP-28', 'MOSIN-NAGANT', 'SCAR-H', 'SV-98', 'M1 GARAND', 'PKP PECHENEG', 'AN-94', 'BAR M1918', 'BLR 81', 'SVD-63', 'M134', 'WATER GUN', 'GROZA', 'GROZA-S'],
  2087. GREEN: ['FAMAS', 'M416', 'M249', 'QBB-97', 'MK 12 SPR', 'M4A1-S', 'SCOUT ELITE', 'L86A2'],
  2088. RED: ['M870', 'MP220', 'SAIGA-12', 'SPAS-12', 'USAS-12', 'SUPER 90', 'LASR GUN', 'M1100'],
  2089. BLACK: ['DEAGLE 50', 'RAINBOW BLASTER'],
  2090. OLIVE: ['AWM-S', 'MK 20 SSR'],
  2091. ORANGE_RED: ['FLARE GUN'],
  2092. PURPLE: ['MODEL 94', 'PEACEMAKER', 'VECTOR (.45 ACP)', 'M1911', 'M1A1', 'MK45G'],
  2093. TEAL: ['M79'],
  2094. BROWN: ['POTATO CANNON', 'SPUD GUN'],
  2095. PINK: ['HEART CANNON'],
  2096. DEFAULT: []
  2097. };
  2098. weaponNames.forEach((weaponNameElement) => {
  2099. const weaponContainer = weaponNameElement.closest(".ui-weapon-switch");
  2100. const observer = new MutationObserver(() => {
  2101. var _a, _b, _c;
  2102. const weaponName = ((_b = (_a = weaponNameElement.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === null || _b === void 0 ? void 0 : _b.toUpperCase()) || '';
  2103. const colorKey = (((_c = Object.entries(WEAPON_COLOR_MAPPING)
  2104. .find(([_, weapons]) => weapons.includes(weaponName))) === null || _c === void 0 ? void 0 : _c[0]) || 'DEFAULT');
  2105. if (weaponContainer && weaponContainer.id !== "ui-weapon-id-4") {
  2106. weaponContainer.style.border = `3px solid ${WEAPON_COLORS[colorKey]}`;
  2107. }
  2108. });
  2109. observer.observe(weaponNameElement, { childList: true, characterData: true, subtree: true });
  2110. });
  2111. }
  2112. updateUiElements() {
  2113. const currentUrl = window.location.href;
  2114. const isSpecialUrl = /\/#\w+/.test(currentUrl);
  2115. const playerOptions = document.getElementById("player-options");
  2116. const teamMenuContents = document.getElementById("team-menu-contents");
  2117. const startMenuContainer = document.querySelector("#start-menu .play-button-container");
  2118. // Update counters draggable state based on LSHIFT menu visibility
  2119. this.updateCountersDraggableState();
  2120. if (!playerOptions)
  2121. return;
  2122. if (isSpecialUrl &&
  2123. teamMenuContents &&
  2124. playerOptions.parentNode !== teamMenuContents) {
  2125. teamMenuContents.appendChild(playerOptions);
  2126. }
  2127. else if (!isSpecialUrl &&
  2128. startMenuContainer &&
  2129. playerOptions.parentNode !== startMenuContainer) {
  2130. const firstChild = startMenuContainer.firstChild;
  2131. startMenuContainer.insertBefore(playerOptions, firstChild);
  2132. }
  2133. const teamMenu = document.getElementById("team-menu");
  2134. if (teamMenu) {
  2135. teamMenu.style.height = "355px";
  2136. }
  2137. const menuBlocks = document.querySelectorAll(".menu-block");
  2138. menuBlocks.forEach((block) => {
  2139. block.style.maxHeight = "355px";
  2140. });
  2141. //scalable?
  2142. }
  2143. updateMenuButtonText() {
  2144. const hideButton = document.getElementById("hideMenuButton");
  2145. hideButton.textContent = this.isMenuVisible
  2146. ? "Hide Menu [P]"
  2147. : "Show Menu [P]";
  2148. }
  2149. updateHealthBars() {
  2150. const healthBars = document.querySelectorAll("#ui-health-container");
  2151. healthBars.forEach((container) => {
  2152. var _a, _b;
  2153. const bar = container.querySelector("#ui-health-actual");
  2154. if (bar) {
  2155. const currentHealth = Math.round(parseFloat(bar.style.width));
  2156. let percentageText = container.querySelector(".health-text");
  2157. // Create or update percentage text
  2158. if (!percentageText) {
  2159. percentageText = document.createElement("span");
  2160. percentageText.classList.add("health-text");
  2161. Object.assign(percentageText.style, {
  2162. width: "100%",
  2163. textAlign: "center",
  2164. marginTop: "5px",
  2165. color: "#333",
  2166. fontSize: "20px",
  2167. fontWeight: "bold",
  2168. position: "absolute",
  2169. zIndex: "10",
  2170. });
  2171. container.appendChild(percentageText);
  2172. }
  2173. // Check for health change
  2174. if (currentHealth !== this.lastHealthValue) {
  2175. const healthChange = currentHealth - this.lastHealthValue;
  2176. if (healthChange !== 0) {
  2177. this.showHealthChangeAnimation(container, healthChange);
  2178. }
  2179. this.lastHealthValue = currentHealth;
  2180. }
  2181. if (this.kxsClient.isHealthWarningEnabled) {
  2182. (_a = this.kxsClient.healWarning) === null || _a === void 0 ? void 0 : _a.update(currentHealth);
  2183. }
  2184. else {
  2185. (_b = this.kxsClient.healWarning) === null || _b === void 0 ? void 0 : _b.hide();
  2186. }
  2187. percentageText.textContent = `${currentHealth}%`;
  2188. // Update animations
  2189. this.updateHealthAnimations();
  2190. }
  2191. });
  2192. }
  2193. showHealthChangeAnimation(container, change) {
  2194. const animation = document.createElement("div");
  2195. const isPositive = change > 0;
  2196. Object.assign(animation.style, {
  2197. position: "absolute",
  2198. color: isPositive ? "#2ecc71" : "#e74c3c",
  2199. fontSize: "24px",
  2200. fontWeight: "bold",
  2201. fontFamily: "Arial, sans-serif",
  2202. textShadow: "2px 2px 4px rgba(0,0,0,0.3)",
  2203. pointerEvents: "none",
  2204. zIndex: "100",
  2205. opacity: "1",
  2206. top: "50%",
  2207. right: "-80px", // Position à droite de la barre de vie
  2208. transform: "translateY(-50%)", // Centre verticalement
  2209. whiteSpace: "nowrap", // Empêche le retour à la ligne
  2210. });
  2211. // Check if change is a valid number before displaying it
  2212. if (!isNaN(change)) {
  2213. animation.textContent = `${isPositive ? "+" : ""}${change} HP`;
  2214. }
  2215. else {
  2216. // Skip showing animation if change is NaN
  2217. return;
  2218. }
  2219. container.appendChild(animation);
  2220. this.healthAnimations.push({
  2221. element: animation,
  2222. startTime: performance.now(),
  2223. duration: 1500, // Animation duration in milliseconds
  2224. value: change,
  2225. });
  2226. }
  2227. updateCountersDraggableState() {
  2228. var _a;
  2229. const isMenuOpen = ((_a = this.kxsClient.secondaryMenu) === null || _a === void 0 ? void 0 : _a.getMenuVisibility()) || false;
  2230. const counters = ['fps', 'kills', 'ping'];
  2231. counters.forEach(name => {
  2232. const counter = document.getElementById(`${name}Counter`);
  2233. if (counter) {
  2234. // Mise à jour des propriétés de draggabilité
  2235. counter.style.pointerEvents = isMenuOpen ? 'auto' : 'none';
  2236. counter.style.cursor = isMenuOpen ? 'move' : 'default';
  2237. // Mise à jour de la possibilité de redimensionnement
  2238. counter.style.resize = isMenuOpen ? 'both' : 'none';
  2239. }
  2240. });
  2241. }
  2242. updateHealthAnimations() {
  2243. const currentTime = performance.now();
  2244. this.healthAnimations = this.healthAnimations.filter(animation => {
  2245. const elapsed = currentTime - animation.startTime;
  2246. const progress = Math.min(elapsed / animation.duration, 1);
  2247. if (progress < 1) {
  2248. // Update animation position and opacity
  2249. // Maintenant l'animation se déplace horizontalement vers la droite
  2250. const translateX = progress * 20; // Déplacement horizontal
  2251. Object.assign(animation.element.style, {
  2252. transform: `translateY(-50%) translateX(${translateX}px)`,
  2253. opacity: String(1 - progress),
  2254. });
  2255. return true;
  2256. }
  2257. else {
  2258. // Remove completed animation
  2259. animation.element.remove();
  2260. return false;
  2261. }
  2262. });
  2263. }
  2264. }
  2265.  
  2266.  
  2267. ;// ./src/intercept.ts
  2268. function intercept(link, targetUrl) {
  2269. const open = XMLHttpRequest.prototype.open;
  2270. XMLHttpRequest.prototype.open = function (method, url) {
  2271. if (url.includes(link)) {
  2272. arguments[1] = targetUrl;
  2273. }
  2274. open.apply(this, arguments);
  2275. };
  2276. const originalFetch = window.fetch;
  2277. window.fetch = function (url, options) {
  2278. if (url.includes(link)) {
  2279. url = targetUrl;
  2280. }
  2281. return originalFetch.apply(this, arguments);
  2282. };
  2283. }
  2284.  
  2285.  
  2286. ;// ./src/HealthWarning.ts
  2287. class HealthWarning {
  2288. constructor(kxsClient) {
  2289. this.warningElement = null;
  2290. this.kxsClient = kxsClient;
  2291. this.createWarningElement();
  2292. this.setFixedPosition();
  2293. }
  2294. createWarningElement() {
  2295. const warning = document.createElement("div");
  2296. const uiTopLeft = document.getElementById("ui-top-left");
  2297. warning.style.cssText = `
  2298. position: fixed;
  2299. background: rgba(0, 0, 0, 0.8);
  2300. border: 2px solid #ff0000;
  2301. border-radius: 5px;
  2302. padding: 10px 15px;
  2303. color: #ff0000;
  2304. font-family: Arial, sans-serif;
  2305. font-size: 14px;
  2306. z-index: 9999;
  2307. display: none;
  2308. backdrop-filter: blur(5px);
  2309. pointer-events: none;
  2310. `;
  2311. const content = document.createElement("div");
  2312. content.style.cssText = `
  2313. display: flex;
  2314. align-items: center;
  2315. gap: 8px;
  2316. `;
  2317. const icon = document.createElement("div");
  2318. icon.innerHTML = `
  2319. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  2320. <circle cx="12" cy="12" r="10"></circle>
  2321. <line x1="12" y1="8" x2="12" y2="12"></line>
  2322. <line x1="12" y1="16" x2="12.01" y2="16"></line>
  2323. </svg>
  2324. `;
  2325. const text = document.createElement("span");
  2326. text.textContent = "LOW HP!";
  2327. if (uiTopLeft) {
  2328. content.appendChild(icon);
  2329. content.appendChild(text);
  2330. warning.appendChild(content);
  2331. uiTopLeft.appendChild(warning);
  2332. }
  2333. this.warningElement = warning;
  2334. this.addPulseAnimation();
  2335. }
  2336. setFixedPosition() {
  2337. if (!this.warningElement)
  2338. return;
  2339. // Example
  2340. this.warningElement.style.top = "742px";
  2341. this.warningElement.style.left = "285px";
  2342. //OR use transform use somethin like, this.warningElement.style.transform = `translate(20px, 20px)`;
  2343. }
  2344. addPulseAnimation() {
  2345. const keyframes = `
  2346. @keyframes pulse {
  2347. 0% { opacity: 1; }
  2348. 50% { opacity: 0.5; }
  2349. 100% { opacity: 1; }
  2350. }
  2351. `;
  2352. const style = document.createElement("style");
  2353. style.textContent = keyframes;
  2354. document.head.appendChild(style);
  2355. if (this.warningElement) {
  2356. this.warningElement.style.animation = "pulse 1.5s infinite";
  2357. }
  2358. }
  2359. show(health) {
  2360. if (!this.warningElement)
  2361. return;
  2362. this.warningElement.style.display = "block";
  2363. const span = this.warningElement.querySelector("span");
  2364. if (span) {
  2365. span.textContent = `LOW HP: ${health}%`;
  2366. }
  2367. }
  2368. hide() {
  2369. if (!this.warningElement)
  2370. return;
  2371. this.warningElement.style.display = "none";
  2372. }
  2373. update(health) {
  2374. if (health <= 30 && health > 0) {
  2375. this.show(health);
  2376. }
  2377. else {
  2378. this.hide();
  2379. }
  2380. }
  2381. }
  2382.  
  2383.  
  2384. ;// ./src/KillLeaderTracking.ts
  2385. class KillLeaderTracker {
  2386. constructor(kxsClient) {
  2387. this.offsetX = 20;
  2388. this.offsetY = 20;
  2389. this.lastKnownKills = 0;
  2390. this.wasKillLeader = false;
  2391. this.MINIMUM_KILLS_FOR_LEADER = 3;
  2392. this.kxsClient = kxsClient;
  2393. this.warningElement = null;
  2394. this.encouragementElement = null;
  2395. this.killLeaderKillCount = 0;
  2396. this.wasKillLeader = false;
  2397. this.createEncouragementElement();
  2398. this.initMouseTracking();
  2399. }
  2400. createEncouragementElement() {
  2401. const encouragement = document.createElement("div");
  2402. encouragement.style.cssText = `
  2403. position: fixed;
  2404. background: rgba(0, 255, 0, 0.1);
  2405. border: 2px solid #00ff00;
  2406. border-radius: 5px;
  2407. padding: 10px 15px;
  2408. color: #00ff00;
  2409. font-family: Arial, sans-serif;
  2410. font-size: 14px;
  2411. z-index: 9999;
  2412. display: none;
  2413. backdrop-filter: blur(5px);
  2414. transition: all 0.3s ease;
  2415. pointer-events: none;
  2416. box-shadow: 0 0 10px rgba(0, 255, 0, 0.3);
  2417. `;
  2418. const content = document.createElement("div");
  2419. content.style.cssText = `
  2420. display: flex;
  2421. align-items: center;
  2422. gap: 8px;
  2423. `;
  2424. const icon = document.createElement("div");
  2425. icon.innerHTML = `
  2426. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  2427. <path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"/>
  2428. </svg>
  2429. `;
  2430. const text = document.createElement("span");
  2431. text.textContent = "Nice Kill!";
  2432. content.appendChild(icon);
  2433. content.appendChild(text);
  2434. encouragement.appendChild(content);
  2435. document.body.appendChild(encouragement);
  2436. this.encouragementElement = encouragement;
  2437. this.addEncouragementAnimation();
  2438. }
  2439. initMouseTracking() {
  2440. document.addEventListener("mousemove", (e) => {
  2441. this.updateElementPosition(this.warningElement, e);
  2442. this.updateElementPosition(this.encouragementElement, e);
  2443. });
  2444. }
  2445. updateElementPosition(element, e) {
  2446. if (!element || element.style.display === "none")
  2447. return;
  2448. const x = e.clientX + this.offsetX;
  2449. const y = e.clientY + this.offsetY;
  2450. const rect = element.getBoundingClientRect();
  2451. const maxX = window.innerWidth - rect.width;
  2452. const maxY = window.innerHeight - rect.height;
  2453. const finalX = Math.min(Math.max(0, x), maxX);
  2454. const finalY = Math.min(Math.max(0, y), maxY);
  2455. element.style.transform = `translate(${finalX}px, ${finalY}px)`;
  2456. }
  2457. addEncouragementAnimation() {
  2458. const keyframes = `
  2459. @keyframes encouragementPulse {
  2460. 0% { transform: scale(1); opacity: 1; }
  2461. 50% { transform: scale(1.1); opacity: 0.8; }
  2462. 100% { transform: scale(1); opacity: 1; }
  2463. }
  2464. @keyframes fadeInOut {
  2465. 0% { opacity: 0; transform: translateY(20px); }
  2466. 10% { opacity: 1; transform: translateY(0); }
  2467. 90% { opacity: 1; transform: translateY(0); }
  2468. 100% { opacity: 0; transform: translateY(-20px); }
  2469. }
  2470. `;
  2471. const style = document.createElement("style");
  2472. style.textContent = keyframes;
  2473. document.head.appendChild(style);
  2474. if (this.encouragementElement) {
  2475. this.encouragementElement.style.animation = "fadeInOut 3s forwards";
  2476. }
  2477. }
  2478. showEncouragement(killsToLeader, isDethrone = false, noKillLeader = false) {
  2479. if (!this.encouragementElement)
  2480. return;
  2481. let message;
  2482. if (isDethrone) {
  2483. message = "Oh no! You've been dethroned!";
  2484. this.encouragementElement.style.borderColor = "#ff0000";
  2485. this.encouragementElement.style.color = "#ff0000";
  2486. this.encouragementElement.style.background = "rgba(255, 0, 0, 0.1)";
  2487. }
  2488. else if (noKillLeader) {
  2489. const killsNeeded = this.MINIMUM_KILLS_FOR_LEADER - this.lastKnownKills;
  2490. message = `Nice Kill! Get ${killsNeeded} more kills to become the first Kill Leader!`;
  2491. }
  2492. else {
  2493. message =
  2494. killsToLeader <= 0
  2495. ? "You're the Kill Leader! 👑"
  2496. : `Nice Kill! ${killsToLeader} more to become Kill Leader!`;
  2497. }
  2498. const span = this.encouragementElement.querySelector("span");
  2499. if (span)
  2500. span.textContent = message;
  2501. this.encouragementElement.style.display = "block";
  2502. this.encouragementElement.style.animation = "fadeInOut 3s forwards";
  2503. setTimeout(() => {
  2504. if (this.encouragementElement) {
  2505. this.encouragementElement.style.display = "none";
  2506. // Reset colors
  2507. this.encouragementElement.style.borderColor = "#00ff00";
  2508. this.encouragementElement.style.color = "#00ff00";
  2509. this.encouragementElement.style.background = "rgba(0, 255, 0, 0.1)";
  2510. }
  2511. }, 7000);
  2512. }
  2513. isKillLeader() {
  2514. const killLeaderNameElement = document.querySelector("#ui-kill-leader-name");
  2515. return this.kxsClient.getPlayerName() === (killLeaderNameElement === null || killLeaderNameElement === void 0 ? void 0 : killLeaderNameElement.textContent);
  2516. }
  2517. update(myKills) {
  2518. if (!this.kxsClient.isKillLeaderTrackerEnabled)
  2519. return;
  2520. const killLeaderElement = document.querySelector("#ui-kill-leader-count");
  2521. this.killLeaderKillCount = parseInt((killLeaderElement === null || killLeaderElement === void 0 ? void 0 : killLeaderElement.textContent) || "0", 10);
  2522. if (myKills > this.lastKnownKills) {
  2523. if (this.killLeaderKillCount === 0) {
  2524. // Pas encore de kill leader, encourager le joueur à atteindre 3 kills
  2525. this.showEncouragement(0, false, true);
  2526. }
  2527. else if (this.killLeaderKillCount < this.MINIMUM_KILLS_FOR_LEADER) {
  2528. // Ne rien faire si le kill leader n'a pas atteint le minimum requis
  2529. return;
  2530. }
  2531. else if (this.isKillLeader()) {
  2532. this.showEncouragement(0);
  2533. this.wasKillLeader = true;
  2534. }
  2535. else {
  2536. const killsNeeded = this.killLeaderKillCount + 1 - myKills;
  2537. this.showEncouragement(killsNeeded);
  2538. }
  2539. }
  2540. else if (this.wasKillLeader && !this.isKillLeader()) {
  2541. // Détroné
  2542. this.showEncouragement(0, true);
  2543. this.wasKillLeader = false;
  2544. }
  2545. this.lastKnownKills = myKills;
  2546. }
  2547. }
  2548.  
  2549.  
  2550. ;// ./src/GridSystem.ts
  2551. class GridSystem {
  2552. constructor() {
  2553. this.gridSize = 20; // Size of each grid cell
  2554. this.snapThreshold = 15; // Distance in pixels to trigger snap
  2555. this.gridVisible = false;
  2556. this.magneticEdges = true;
  2557. this.gridContainer = this.createGridOverlay();
  2558. this.setupKeyBindings();
  2559. }
  2560. createGridOverlay() {
  2561. const container = document.createElement("div");
  2562. container.id = "grid-overlay";
  2563. Object.assign(container.style, {
  2564. position: "fixed",
  2565. top: "0",
  2566. left: "0",
  2567. width: "100%",
  2568. height: "100%",
  2569. pointerEvents: "none",
  2570. zIndex: "9999",
  2571. display: "none",
  2572. opacity: "0.2",
  2573. });
  2574. // Create vertical lines
  2575. for (let x = this.gridSize; x < window.innerWidth; x += this.gridSize) {
  2576. const vLine = document.createElement("div");
  2577. Object.assign(vLine.style, {
  2578. position: "absolute",
  2579. left: `${x}px`,
  2580. top: "0",
  2581. width: "1px",
  2582. height: "100%",
  2583. backgroundColor: "#4CAF50",
  2584. });
  2585. container.appendChild(vLine);
  2586. }
  2587. // Create horizontal lines
  2588. for (let y = this.gridSize; y < window.innerHeight; y += this.gridSize) {
  2589. const hLine = document.createElement("div");
  2590. Object.assign(hLine.style, {
  2591. position: "absolute",
  2592. left: "0",
  2593. top: `${y}px`,
  2594. width: "100%",
  2595. height: "1px",
  2596. backgroundColor: "#4CAF50",
  2597. });
  2598. container.appendChild(hLine);
  2599. }
  2600. document.body.appendChild(container);
  2601. return container;
  2602. }
  2603. setupKeyBindings() {
  2604. document.addEventListener("keydown", (e) => {
  2605. if (e.key === "g" && e.altKey) {
  2606. this.toggleGrid();
  2607. }
  2608. });
  2609. }
  2610. toggleGrid() {
  2611. this.gridVisible = !this.gridVisible;
  2612. this.gridContainer.style.display = this.gridVisible ? "block" : "none";
  2613. }
  2614. snapToGrid(element, x, y) {
  2615. const rect = element.getBoundingClientRect();
  2616. const elementWidth = rect.width;
  2617. const elementHeight = rect.height;
  2618. // Snap to grid
  2619. let snappedX = Math.round(x / this.gridSize) * this.gridSize;
  2620. let snappedY = Math.round(y / this.gridSize) * this.gridSize;
  2621. // Edge snapping
  2622. if (this.magneticEdges) {
  2623. const screenEdges = {
  2624. left: 0,
  2625. right: window.innerWidth - elementWidth,
  2626. center: (window.innerWidth - elementWidth) / 2,
  2627. top: 0,
  2628. bottom: window.innerHeight - elementHeight,
  2629. middle: (window.innerHeight - elementHeight) / 2,
  2630. };
  2631. // Snap to horizontal edges
  2632. if (Math.abs(x - screenEdges.left) < this.snapThreshold) {
  2633. snappedX = screenEdges.left;
  2634. }
  2635. else if (Math.abs(x - screenEdges.right) < this.snapThreshold) {
  2636. snappedX = screenEdges.right;
  2637. }
  2638. else if (Math.abs(x - screenEdges.center) < this.snapThreshold) {
  2639. snappedX = screenEdges.center;
  2640. }
  2641. // Snap to vertical edges
  2642. if (Math.abs(y - screenEdges.top) < this.snapThreshold) {
  2643. snappedY = screenEdges.top;
  2644. }
  2645. else if (Math.abs(y - screenEdges.bottom) < this.snapThreshold) {
  2646. snappedY = screenEdges.bottom;
  2647. }
  2648. else if (Math.abs(y - screenEdges.middle) < this.snapThreshold) {
  2649. snappedY = screenEdges.middle;
  2650. }
  2651. }
  2652. return { x: snappedX, y: snappedY };
  2653. }
  2654. highlightNearestGridLine(x, y) {
  2655. if (!this.gridVisible)
  2656. return;
  2657. // Remove existing highlights
  2658. const highlights = document.querySelectorAll(".grid-highlight");
  2659. highlights.forEach((h) => h.remove());
  2660. // Create highlight for nearest vertical line
  2661. const nearestX = Math.round(x / this.gridSize) * this.gridSize;
  2662. if (Math.abs(x - nearestX) < this.snapThreshold) {
  2663. const vHighlight = document.createElement("div");
  2664. Object.assign(vHighlight.style, {
  2665. position: "absolute",
  2666. left: `${nearestX}px`,
  2667. top: "0",
  2668. width: "2px",
  2669. height: "100%",
  2670. backgroundColor: "#FFD700",
  2671. zIndex: "10000",
  2672. pointerEvents: "none",
  2673. });
  2674. vHighlight.classList.add("grid-highlight");
  2675. this.gridContainer.appendChild(vHighlight);
  2676. }
  2677. // Create highlight for nearest horizontal line
  2678. const nearestY = Math.round(y / this.gridSize) * this.gridSize;
  2679. if (Math.abs(y - nearestY) < this.snapThreshold) {
  2680. const hHighlight = document.createElement("div");
  2681. Object.assign(hHighlight.style, {
  2682. position: "absolute",
  2683. left: "0",
  2684. top: `${nearestY}px`,
  2685. width: "100%",
  2686. height: "2px",
  2687. backgroundColor: "#FFD700",
  2688. zIndex: "10000",
  2689. pointerEvents: "none",
  2690. });
  2691. hHighlight.classList.add("grid-highlight");
  2692. this.gridContainer.appendChild(hHighlight);
  2693. }
  2694. }
  2695. }
  2696.  
  2697.  
  2698. ;// ./src/StatsParser.ts
  2699. class StatsParser {
  2700. static cleanNumber(str) {
  2701. return parseInt(str.replace(/[^\d.-]/g, "")) || 0;
  2702. }
  2703. /**
  2704. * Extract the full duration string including the unit
  2705. */
  2706. static extractDuration(str) {
  2707. const match = str.match(/(\d+\s*[smh])/i);
  2708. return match ? match[1].trim() : "0s";
  2709. }
  2710. static parse(statsText, rankContent) {
  2711. let stats = {
  2712. username: "Player",
  2713. kills: 0,
  2714. damageDealt: 0,
  2715. damageTaken: 0,
  2716. duration: "",
  2717. position: "#unknown",
  2718. };
  2719. // Handle developer format
  2720. const devPattern = /Developer.*?Kills(\d+).*?Damage Dealt(\d+).*?Damage Taken(\d+).*?Survived(\d+\s*[smh])/i;
  2721. const devMatch = statsText.match(devPattern);
  2722. if (devMatch) {
  2723. return {
  2724. username: "Player",
  2725. kills: this.cleanNumber(devMatch[1]),
  2726. damageDealt: this.cleanNumber(devMatch[2]),
  2727. damageTaken: this.cleanNumber(devMatch[3]),
  2728. duration: devMatch[4].trim(), // Keep the full duration string with unit
  2729. position: rankContent.replace("##", "#"),
  2730. };
  2731. }
  2732. // Handle template format
  2733. const templatePattern = /%username%.*?Kills%kills_number%.*?Dealt%number_dealt%.*?Taken%damage_taken%.*?Survived%duration%/;
  2734. const templateMatch = statsText.match(templatePattern);
  2735. if (templateMatch) {
  2736. const parts = statsText.split(/Kills|Dealt|Taken|Survived/);
  2737. if (parts.length >= 5) {
  2738. return {
  2739. username: parts[0].trim(),
  2740. kills: this.cleanNumber(parts[1]),
  2741. damageDealt: this.cleanNumber(parts[2]),
  2742. damageTaken: this.cleanNumber(parts[3]),
  2743. duration: this.extractDuration(parts[4]), // Extract full duration with unit
  2744. position: rankContent.replace("##", "#"),
  2745. };
  2746. }
  2747. }
  2748. // Generic parsing as fallback
  2749. const usernameMatch = statsText.match(/^([^0-9]+)/);
  2750. if (usernameMatch) {
  2751. stats.username = usernameMatch[1].trim();
  2752. }
  2753. const killsMatch = statsText.match(/Kills[^0-9]*(\d+)/i);
  2754. if (killsMatch) {
  2755. stats.kills = this.cleanNumber(killsMatch[1]);
  2756. }
  2757. const dealtMatch = statsText.match(/Dealt[^0-9]*(\d+)/i);
  2758. if (dealtMatch) {
  2759. stats.damageDealt = this.cleanNumber(dealtMatch[1]);
  2760. }
  2761. const takenMatch = statsText.match(/Taken[^0-9]*(\d+)/i);
  2762. if (takenMatch) {
  2763. stats.damageTaken = this.cleanNumber(takenMatch[1]);
  2764. }
  2765. // Extract survival time with unit
  2766. const survivalMatch = statsText.match(/Survived[^0-9]*(\d+\s*[smh])/i);
  2767. if (survivalMatch) {
  2768. stats.duration = survivalMatch[1].trim();
  2769. }
  2770. stats.position = rankContent.replace("##", "#");
  2771. return stats;
  2772. }
  2773. }
  2774.  
  2775.  
  2776. // EXTERNAL MODULE: ./node_modules/semver/functions/gt.js
  2777. var gt = __webpack_require__(580);
  2778. var gt_default = /*#__PURE__*/__webpack_require__.n(gt);
  2779. ;// ./src/UpdateChecker.ts
  2780. var UpdateChecker_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
  2781. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  2782. return new (P || (P = Promise))(function (resolve, reject) {
  2783. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  2784. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  2785. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  2786. step((generator = generator.apply(thisArg, _arguments || [])).next());
  2787. });
  2788. };
  2789.  
  2790. const packageInfo = __webpack_require__(330);
  2791. const config = __webpack_require__(891);
  2792. class UpdateChecker {
  2793. constructor(kxsClient) {
  2794. this.remoteScriptUrl = config.base_url + "/download/latest-dev.js";
  2795. this.kxsClient = kxsClient;
  2796. if (this.kxsClient.isAutoUpdateEnabled) {
  2797. this.checkForUpdate();
  2798. }
  2799. }
  2800. downloadScript() {
  2801. return UpdateChecker_awaiter(this, void 0, void 0, function* () {
  2802. return new Promise((resolve, reject) => {
  2803. GM.xmlHttpRequest({
  2804. method: "GET",
  2805. url: this.remoteScriptUrl,
  2806. headers: {
  2807. "Cache-Control": "no-cache, no-store, must-revalidate",
  2808. "Pragma": "no-cache",
  2809. "Expires": "0"
  2810. },
  2811. nocache: true,
  2812. responseType: "blob",
  2813. onload: (response) => {
  2814. if (response.status === 200) {
  2815. const blob = new Blob([response.response], { type: 'application/javascript' });
  2816. const downloadUrl = window.URL.createObjectURL(blob);
  2817. const downloadLink = document.createElement('a');
  2818. downloadLink.href = downloadUrl;
  2819. downloadLink.download = 'KxsClient.user.js';
  2820. document.body.appendChild(downloadLink);
  2821. downloadLink.click();
  2822. document.body.removeChild(downloadLink);
  2823. window.URL.revokeObjectURL(downloadUrl);
  2824. resolve();
  2825. }
  2826. else {
  2827. reject(new Error("Error downloading script: " + response.statusText));
  2828. }
  2829. },
  2830. onerror: (error) => {
  2831. reject(new Error("Error during script download: " + error));
  2832. }
  2833. });
  2834. });
  2835. });
  2836. }
  2837. getNewScriptVersion() {
  2838. return UpdateChecker_awaiter(this, void 0, void 0, function* () {
  2839. return new Promise((resolve, reject) => {
  2840. GM.xmlHttpRequest({
  2841. method: "GET",
  2842. url: this.remoteScriptUrl,
  2843. headers: {
  2844. "Cache-Control": "no-cache, no-store, must-revalidate",
  2845. "Pragma": "no-cache",
  2846. "Expires": "0"
  2847. },
  2848. nocache: true,
  2849. onload: (response) => {
  2850. if (response.status === 200) {
  2851. const scriptContent = response.responseText;
  2852. const versionMatch = scriptContent.match(/\/\/\s*@version\s+([\d.]+)/);
  2853. if (versionMatch && versionMatch[1]) {
  2854. resolve(versionMatch[1]);
  2855. }
  2856. else {
  2857. reject(new Error("Script version was not found in the file."));
  2858. }
  2859. }
  2860. else {
  2861. reject(new Error("Error retrieving remote script: " + response.statusText));
  2862. }
  2863. },
  2864. onerror: (error) => {
  2865. reject(new Error("Error during remote script request: " + error));
  2866. }
  2867. });
  2868. });
  2869. });
  2870. }
  2871. checkForUpdate() {
  2872. return UpdateChecker_awaiter(this, void 0, void 0, function* () {
  2873. const localScriptVersion = yield this.getCurrentScriptVersion();
  2874. const hostedScriptVersion = yield this.getNewScriptVersion();
  2875. this.hostedScriptVersion = hostedScriptVersion;
  2876. // Vérifie si la version hébergée est supérieure à la version locale
  2877. if (gt_default()(hostedScriptVersion, localScriptVersion)) {
  2878. this.displayUpdateNotification();
  2879. }
  2880. else {
  2881. this.kxsClient.nm.showNotification("Client is up to date", "success", 2300);
  2882. }
  2883. });
  2884. }
  2885. displayUpdateNotification() {
  2886. const modal = document.createElement("div");
  2887. modal.style.position = "fixed";
  2888. modal.style.top = "50%";
  2889. modal.style.left = "50%";
  2890. modal.style.transform = "translate(-50%, -50%)";
  2891. modal.style.backgroundColor = "rgb(250, 250, 250)";
  2892. modal.style.borderRadius = "10px";
  2893. modal.style.padding = "20px";
  2894. modal.style.width = "400px";
  2895. modal.style.boxShadow = "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)";
  2896. modal.style.border = "1px solid rgb(229, 229, 229)";
  2897. const header = document.createElement("div");
  2898. header.style.display = "flex";
  2899. header.style.alignItems = "center";
  2900. header.style.marginBottom = "15px";
  2901. const title = document.createElement("h3");
  2902. title.textContent = "Download Update";
  2903. title.style.margin = "0";
  2904. title.style.fontSize = "16px";
  2905. title.style.fontWeight = "600";
  2906. header.appendChild(title);
  2907. const closeButton = document.createElement("button");
  2908. closeButton.innerHTML = "×";
  2909. closeButton.style.marginLeft = "auto";
  2910. closeButton.style.border = "none";
  2911. closeButton.style.background = "none";
  2912. closeButton.style.fontSize = "20px";
  2913. closeButton.style.cursor = "pointer";
  2914. closeButton.style.padding = "0 5px";
  2915. closeButton.onclick = () => modal.remove();
  2916. header.appendChild(closeButton);
  2917. const content = document.createElement("div");
  2918. content.innerHTML = `A new version of KxsClient is available!<br>
  2919. Locale: ${this.getCurrentScriptVersion()} | On web: ${this.hostedScriptVersion}<br>
  2920. Click the button below to update now.`;
  2921. content.style.marginBottom = "20px";
  2922. content.style.color = "rgb(75, 85, 99)";
  2923. const updateButton = document.createElement("button");
  2924. updateButton.textContent = "Update Now";
  2925. updateButton.style.backgroundColor = "rgb(59, 130, 246)";
  2926. updateButton.style.color = "white";
  2927. updateButton.style.padding = "8px 16px";
  2928. updateButton.style.borderRadius = "6px";
  2929. updateButton.style.border = "none";
  2930. updateButton.style.cursor = "pointer";
  2931. updateButton.style.width = "100%";
  2932. updateButton.onclick = () => UpdateChecker_awaiter(this, void 0, void 0, function* () {
  2933. try {
  2934. yield this.downloadScript();
  2935. this.kxsClient.nm.showNotification("Download started", "success", 2300);
  2936. modal.remove();
  2937. }
  2938. catch (error) {
  2939. this.kxsClient.nm.showNotification("Download failed: " + error.message, "info", 5000);
  2940. }
  2941. });
  2942. modal.appendChild(header);
  2943. modal.appendChild(content);
  2944. modal.appendChild(updateButton);
  2945. document.body.appendChild(modal);
  2946. }
  2947. getCurrentScriptVersion() {
  2948. return packageInfo.version;
  2949. }
  2950. }
  2951.  
  2952.  
  2953. ;// ./src/DiscordRichPresence.ts
  2954. const DiscordRichPresence_packageInfo = __webpack_require__(330);
  2955. class DiscordWebSocket {
  2956. constructor(kxsClient, token) {
  2957. this.ws = null;
  2958. this.heartbeatInterval = 0;
  2959. this.sequence = null;
  2960. this.isAuthenticated = false;
  2961. this.kxsClient = kxsClient;
  2962. }
  2963. connect() {
  2964. if (this.kxsClient.discordToken === ""
  2965. || this.kxsClient.discordToken === null
  2966. || this.kxsClient.discordToken === undefined) {
  2967. return;
  2968. }
  2969. this.ws = new WebSocket('wss://gateway.discord.gg/?v=9&encoding=json');
  2970. this.ws.onopen = () => {
  2971. console.log('WebSocket connection established');
  2972. };
  2973. this.ws.onmessage = (event) => {
  2974. const data = JSON.parse(event.data);
  2975. this.handleMessage(data);
  2976. };
  2977. this.ws.onerror = (error) => {
  2978. this.kxsClient.nm.showNotification('WebSocket error: ' + error.type, 'error', 5000);
  2979. };
  2980. this.ws.onclose = () => {
  2981. this.kxsClient.nm.showNotification('Disconnected from Discord gateway', 'info', 5000);
  2982. clearInterval(this.heartbeatInterval);
  2983. this.isAuthenticated = false;
  2984. };
  2985. }
  2986. identify() {
  2987. const payload = {
  2988. op: 2,
  2989. d: {
  2990. token: this.kxsClient.discordToken,
  2991. properties: {
  2992. $os: 'linux',
  2993. $browser: 'chrome',
  2994. $device: 'chrome'
  2995. },
  2996. presence: {
  2997. activities: [{
  2998. name: "KxsClient",
  2999. type: 0,
  3000. application_id: "1321193265533550602",
  3001. assets: {
  3002. large_image: "mp:app-assets/1321193265533550602/1322173537326338058.png?size=512",
  3003. large_text: "KxsClient v" + DiscordRichPresence_packageInfo.version,
  3004. }
  3005. }],
  3006. status: 'online',
  3007. afk: false
  3008. }
  3009. }
  3010. };
  3011. this.send(payload);
  3012. }
  3013. handleMessage(data) {
  3014. switch (data.op) {
  3015. case 10: // Hello
  3016. const { heartbeat_interval } = data.d;
  3017. this.startHeartbeat(heartbeat_interval);
  3018. this.identify();
  3019. this.kxsClient.nm.showNotification('Started Discord RPC', 'success', 3000);
  3020. break;
  3021. case 11: // Heartbeat ACK
  3022. console.log('Heartbeat acknowledged');
  3023. break;
  3024. case 0: // Dispatch
  3025. this.sequence = data.s;
  3026. if (data.t === 'READY') {
  3027. this.isAuthenticated = true;
  3028. this.kxsClient.nm.showNotification('Connected to Discord gateway', 'success', 2500);
  3029. }
  3030. break;
  3031. }
  3032. }
  3033. startHeartbeat(interval) {
  3034. this.heartbeatInterval = setInterval(() => {
  3035. this.send({
  3036. op: 1,
  3037. d: this.sequence
  3038. });
  3039. }, interval);
  3040. }
  3041. send(data) {
  3042. var _a;
  3043. if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
  3044. this.ws.send(JSON.stringify(data));
  3045. }
  3046. }
  3047. disconnect() {
  3048. if (this.ws) {
  3049. clearInterval(this.heartbeatInterval);
  3050. this.ws.close();
  3051. }
  3052. }
  3053. }
  3054.  
  3055.  
  3056. ;// ./src/NotificationManager.ts
  3057. class NotificationManager {
  3058. constructor() {
  3059. this.notifications = [];
  3060. this.NOTIFICATION_HEIGHT = 65; // Height + margin
  3061. this.NOTIFICATION_MARGIN = 10;
  3062. this.addGlobalStyles();
  3063. }
  3064. static getInstance() {
  3065. if (!NotificationManager.instance) {
  3066. NotificationManager.instance = new NotificationManager();
  3067. }
  3068. return NotificationManager.instance;
  3069. }
  3070. addGlobalStyles() {
  3071. const styleSheet = document.createElement("style");
  3072. styleSheet.textContent = `
  3073. @keyframes slideIn {
  3074. 0% { transform: translateX(-120%); opacity: 0; }
  3075. 50% { transform: translateX(10px); opacity: 0.8; }
  3076. 100% { transform: translateX(0); opacity: 1; }
  3077. }
  3078. @keyframes slideOut {
  3079. 0% { transform: translateX(0); opacity: 1; }
  3080. 50% { transform: translateX(10px); opacity: 0.8; }
  3081. 100% { transform: translateX(-120%); opacity: 0; }
  3082. }
  3083. @keyframes slideLeft {
  3084. from { transform-origin: right; transform: scaleX(1); }
  3085. to { transform-origin: right; transform: scaleX(0); }
  3086. }
  3087. @keyframes bounce {
  3088. 0%, 100% { transform: scale(1); }
  3089. 50% { transform: scale(1.1); }
  3090. }
  3091. `;
  3092. document.head.appendChild(styleSheet);
  3093. }
  3094. updateNotificationPositions() {
  3095. this.notifications.forEach((notification, index) => {
  3096. const topPosition = 20 + (index * this.NOTIFICATION_HEIGHT);
  3097. notification.style.top = `${topPosition}px`;
  3098. });
  3099. }
  3100. removeNotification(notification) {
  3101. const index = this.notifications.indexOf(notification);
  3102. if (index > -1) {
  3103. this.notifications.splice(index, 1);
  3104. this.updateNotificationPositions();
  3105. }
  3106. }
  3107. getIconConfig(type) {
  3108. const configs = {
  3109. success: {
  3110. color: '#4CAF50',
  3111. svg: `<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
  3112. <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
  3113. </svg>`
  3114. },
  3115. error: {
  3116. color: '#F44336',
  3117. svg: `<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
  3118. <path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/>
  3119. </svg>`
  3120. },
  3121. info: {
  3122. color: '#FFD700',
  3123. svg: `<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
  3124. <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
  3125. </svg>`
  3126. }
  3127. };
  3128. return configs[type];
  3129. }
  3130. showNotification(message, type, duration = 5000) {
  3131. const notification = document.createElement("div");
  3132. // Base styles
  3133. Object.assign(notification.style, {
  3134. position: "fixed",
  3135. top: "20px",
  3136. left: "20px",
  3137. padding: "12px 20px",
  3138. backgroundColor: "#333333",
  3139. color: "white",
  3140. zIndex: "9999",
  3141. minWidth: "200px",
  3142. borderRadius: "4px",
  3143. display: "flex",
  3144. alignItems: "center",
  3145. gap: "10px",
  3146. transform: "translateX(-120%)",
  3147. opacity: "0",
  3148. boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
  3149. });
  3150. // Create icon
  3151. const icon = document.createElement("div");
  3152. Object.assign(icon.style, {
  3153. width: "20px",
  3154. height: "20px",
  3155. display: "flex",
  3156. alignItems: "center",
  3157. justifyContent: "center",
  3158. animation: "bounce 0.5s ease-in-out"
  3159. });
  3160. const iconConfig = this.getIconConfig(type);
  3161. icon.style.color = iconConfig.color;
  3162. icon.innerHTML = iconConfig.svg;
  3163. // Create message
  3164. const messageDiv = document.createElement("div");
  3165. messageDiv.textContent = message;
  3166. messageDiv.style.flex = "1";
  3167. // Create progress bar
  3168. const progressBar = document.createElement("div");
  3169. Object.assign(progressBar.style, {
  3170. height: "4px",
  3171. backgroundColor: "#e6f3ff",
  3172. width: "100%",
  3173. position: "absolute",
  3174. bottom: "0",
  3175. left: "0",
  3176. animation: `slideLeft ${duration}ms linear forwards`
  3177. });
  3178. // Assemble notification
  3179. notification.appendChild(icon);
  3180. notification.appendChild(messageDiv);
  3181. notification.appendChild(progressBar);
  3182. document.body.appendChild(notification);
  3183. // Add to stack and update positions
  3184. this.notifications.push(notification);
  3185. this.updateNotificationPositions();
  3186. // Entrance animation
  3187. requestAnimationFrame(() => {
  3188. notification.style.transition = "all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55)";
  3189. notification.style.animation = "slideIn 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards";
  3190. });
  3191. // Exit animation and cleanup
  3192. setTimeout(() => {
  3193. notification.style.animation = "slideOut 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards";
  3194. setTimeout(() => {
  3195. this.removeNotification(notification);
  3196. notification.remove();
  3197. }, 500);
  3198. }, duration);
  3199. }
  3200. }
  3201.  
  3202.  
  3203. ;// ./src/ClientSecondaryMenu.ts
  3204.  
  3205. class KxsLegacyClientSecondaryMenu {
  3206. constructor(kxsClient) {
  3207. this.kxsClient = kxsClient;
  3208. this.isClientMenuVisible = false;
  3209. this.isDragging = false;
  3210. this.dragOffset = { x: 0, y: 0 };
  3211. this.sections = [];
  3212. this.menu = document.createElement("div");
  3213. this.boundShiftListener = this.handleShiftPress.bind(this);
  3214. this.boundMouseDownListener = this.handleMouseDown.bind(this);
  3215. this.boundMouseMoveListener = this.handleMouseMove.bind(this);
  3216. this.boundMouseUpListener = this.handleMouseUp.bind(this);
  3217. this.initMenu();
  3218. this.addShiftListener();
  3219. this.addDragListeners();
  3220. }
  3221. handleShiftPress(event) {
  3222. if (event.key === "Shift" && event.location == 2) {
  3223. this.clearMenu();
  3224. this.toggleMenuVisibility();
  3225. this.loadOption();
  3226. }
  3227. }
  3228. handleMouseDown(e) {
  3229. if (e.target instanceof HTMLElement && !e.target.matches("input, select, button")) {
  3230. this.isDragging = true;
  3231. const rect = this.menu.getBoundingClientRect();
  3232. this.dragOffset = {
  3233. x: e.clientX - rect.left,
  3234. y: e.clientY - rect.top,
  3235. };
  3236. this.menu.style.cursor = "grabbing";
  3237. }
  3238. }
  3239. handleMouseMove(e) {
  3240. if (!this.isDragging)
  3241. return;
  3242. e.preventDefault();
  3243. const newX = e.clientX - this.dragOffset.x;
  3244. const newY = e.clientY - this.dragOffset.y;
  3245. const maxX = window.innerWidth - this.menu.offsetWidth;
  3246. const maxY = window.innerHeight - this.menu.offsetHeight;
  3247. this.menu.style.left = `${Math.max(0, Math.min(newX, maxX))}px`;
  3248. this.menu.style.top = `${Math.max(0, Math.min(newY, maxY))}px`;
  3249. }
  3250. handleMouseUp() {
  3251. this.isDragging = false;
  3252. this.menu.style.cursor = "move";
  3253. }
  3254. initMenu() {
  3255. this.menu.id = "kxsMenuIG";
  3256. this.applyMenuStyles();
  3257. this.createHeader();
  3258. document.body.appendChild(this.menu);
  3259. }
  3260. loadOption() {
  3261. let HUD = this.addSection("HUD");
  3262. this.addOption(HUD, {
  3263. label: "Use Legacy Menu",
  3264. value: this.kxsClient.isLegaySecondaryMenu,
  3265. type: "toggle",
  3266. onChange: (value) => {
  3267. this.kxsClient.isLegaySecondaryMenu = !this.kxsClient.isLegaySecondaryMenu;
  3268. this.kxsClient.updateLocalStorage();
  3269. this.kxsClient.secondaryMenu = new KxsClientSecondaryMenu(this.kxsClient);
  3270. this.destroy();
  3271. },
  3272. });
  3273. this.addOption(HUD, {
  3274. label: "Clean Main Menu",
  3275. value: this.kxsClient.isMainMenuCleaned,
  3276. type: "toggle",
  3277. onChange: (value) => {
  3278. this.kxsClient.isMainMenuCleaned = !this.kxsClient.isMainMenuCleaned;
  3279. this.kxsClient.MainMenuCleaning();
  3280. this.kxsClient.updateLocalStorage();
  3281. },
  3282. });
  3283. this.addOption(HUD, {
  3284. label: "Show Ping",
  3285. value: this.kxsClient.isPingVisible,
  3286. type: "toggle",
  3287. onChange: (value) => {
  3288. this.kxsClient.isPingVisible = !this.kxsClient.isPingVisible;
  3289. this.kxsClient.updatePingVisibility();
  3290. this.kxsClient.updateLocalStorage();
  3291. },
  3292. });
  3293. this.addOption(HUD, {
  3294. label: "Show FPS",
  3295. value: this.kxsClient.isFpsVisible,
  3296. type: "toggle",
  3297. onChange: (value) => {
  3298. this.kxsClient.isFpsVisible = !this.kxsClient.isFpsVisible;
  3299. this.kxsClient.updateFpsVisibility();
  3300. this.kxsClient.updateLocalStorage();
  3301. },
  3302. });
  3303. this.addOption(HUD, {
  3304. label: "Show Kills",
  3305. value: this.kxsClient.isKillsVisible,
  3306. type: "toggle",
  3307. onChange: (value) => {
  3308. this.kxsClient.isKillsVisible = !this.kxsClient.isKillsVisible;
  3309. this.kxsClient.updateKillsVisibility();
  3310. this.kxsClient.updateLocalStorage();
  3311. },
  3312. });
  3313. this.addOption(HUD, {
  3314. label: "Kill Feed Blint Text",
  3315. value: this.kxsClient.isKillFeedBlint,
  3316. type: "toggle",
  3317. onChange: (value) => {
  3318. this.kxsClient.isKillFeedBlint = !this.kxsClient.isKillFeedBlint;
  3319. this.kxsClient.updateLocalStorage();
  3320. },
  3321. });
  3322. let musicSection = this.addSection("Music");
  3323. this.addOption(musicSection, {
  3324. label: "Death sound",
  3325. value: this.kxsClient.isDeathSoundEnabled,
  3326. type: "toggle",
  3327. onChange: (value) => {
  3328. this.kxsClient.isDeathSoundEnabled = !this.kxsClient.isDeathSoundEnabled;
  3329. this.kxsClient.updateLocalStorage();
  3330. },
  3331. });
  3332. this.addOption(musicSection, {
  3333. label: "Win sound",
  3334. value: this.kxsClient.isWinSoundEnabled,
  3335. type: "toggle",
  3336. onChange: (value) => {
  3337. this.kxsClient.isWinSoundEnabled = !this.kxsClient.isWinSoundEnabled;
  3338. this.kxsClient.updateLocalStorage();
  3339. },
  3340. });
  3341. let pluginsSection = this.addSection("Plugins");
  3342. this.addOption(pluginsSection, {
  3343. label: "Webhook URL",
  3344. value: this.kxsClient.discordWebhookUrl || "",
  3345. type: "input",
  3346. onChange: (value) => {
  3347. value = value.toString().trim();
  3348. this.kxsClient.discordWebhookUrl = value;
  3349. this.kxsClient.discordTracker.setWebhookUrl(value);
  3350. this.kxsClient.updateLocalStorage();
  3351. },
  3352. });
  3353. this.addOption(pluginsSection, {
  3354. label: "Heal Warning",
  3355. value: this.kxsClient.isHealthWarningEnabled,
  3356. type: "toggle",
  3357. onChange: (value) => {
  3358. this.kxsClient.isHealthWarningEnabled = !this.kxsClient.isHealthWarningEnabled;
  3359. this.kxsClient.updateLocalStorage();
  3360. },
  3361. });
  3362. this.addOption(pluginsSection, {
  3363. label: "Update Checker",
  3364. value: this.kxsClient.isAutoUpdateEnabled,
  3365. type: "toggle",
  3366. onChange: (value) => {
  3367. this.kxsClient.isAutoUpdateEnabled = !this.kxsClient.isAutoUpdateEnabled;
  3368. this.kxsClient.updateLocalStorage();
  3369. },
  3370. });
  3371. this.addOption(HUD, {
  3372. label: `Spotify Player`,
  3373. value: this.kxsClient.isSpotifyPlayerEnabled,
  3374. type: "toggle",
  3375. onChange: () => {
  3376. this.kxsClient.isSpotifyPlayerEnabled = !this.kxsClient.isSpotifyPlayerEnabled;
  3377. this.kxsClient.updateLocalStorage();
  3378. this.kxsClient.toggleSpotifyMenu();
  3379. },
  3380. });
  3381. this.addOption(pluginsSection, {
  3382. label: `Uncap FPS`,
  3383. value: this.kxsClient.isFpsUncapped,
  3384. type: "toggle",
  3385. onChange: () => {
  3386. this.kxsClient.toggleFpsUncap();
  3387. this.kxsClient.updateLocalStorage();
  3388. },
  3389. });
  3390. this.addOption(pluginsSection, {
  3391. label: `Winning Animation`,
  3392. value: this.kxsClient.isWinningAnimationEnabled,
  3393. type: "toggle",
  3394. onChange: () => {
  3395. this.kxsClient.isWinningAnimationEnabled = !this.kxsClient.isWinningAnimationEnabled;
  3396. this.kxsClient.updateLocalStorage();
  3397. },
  3398. });
  3399. this.addOption(pluginsSection, {
  3400. label: `Rich Presence (Account token required)`,
  3401. value: this.kxsClient.discordToken || "",
  3402. type: "input",
  3403. onChange: (value) => {
  3404. value = value.toString().trim();
  3405. this.kxsClient.discordToken = this.kxsClient.parseToken(value);
  3406. this.kxsClient.discordRPC.disconnect();
  3407. this.kxsClient.discordRPC.connect();
  3408. this.kxsClient.updateLocalStorage();
  3409. },
  3410. });
  3411. this.addOption(pluginsSection, {
  3412. label: `Kill Leader Tracking`,
  3413. value: this.kxsClient.isKillLeaderTrackerEnabled,
  3414. type: "toggle",
  3415. onChange: (value) => {
  3416. this.kxsClient.isKillLeaderTrackerEnabled = !this.kxsClient.isKillLeaderTrackerEnabled;
  3417. this.kxsClient.updateLocalStorage();
  3418. },
  3419. });
  3420. this.addOption(pluginsSection, {
  3421. label: `Friends Detector (separe with ',')`,
  3422. value: this.kxsClient.all_friends,
  3423. type: "input",
  3424. onChange: (value) => {
  3425. this.kxsClient.all_friends = value;
  3426. this.kxsClient.updateLocalStorage();
  3427. },
  3428. });
  3429. this.addOption(HUD, {
  3430. label: `Change Background`,
  3431. value: true,
  3432. type: "click",
  3433. onChange: () => {
  3434. const backgroundElement = document.getElementById("background");
  3435. if (!backgroundElement) {
  3436. alert("Element with id 'background' not found.");
  3437. return;
  3438. }
  3439. const choice = prompt("Enter '0' to default Kxs background, '1' to provide a URL or '2' to upload a local image:");
  3440. if (choice === "0") {
  3441. localStorage.removeItem("lastBackgroundUrl");
  3442. localStorage.removeItem("lastBackgroundFile");
  3443. localStorage.removeItem("lastBackgroundType");
  3444. localStorage.removeItem("lastBackgroundValue");
  3445. }
  3446. else if (choice === "1") {
  3447. const newBackgroundUrl = prompt("Enter the URL of the new background image:");
  3448. if (newBackgroundUrl) {
  3449. backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
  3450. this.kxsClient.saveBackgroundToLocalStorage(newBackgroundUrl);
  3451. alert("Background updated successfully!");
  3452. }
  3453. }
  3454. else if (choice === "2") {
  3455. const fileInput = document.createElement("input");
  3456. fileInput.type = "file";
  3457. fileInput.accept = "image/*";
  3458. fileInput.onchange = (event) => {
  3459. var _a, _b;
  3460. const file = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];
  3461. if (file) {
  3462. const reader = new FileReader();
  3463. reader.onload = () => {
  3464. backgroundElement.style.backgroundImage = `url(${reader.result})`;
  3465. this.kxsClient.saveBackgroundToLocalStorage(file);
  3466. alert("Background updated successfully!");
  3467. };
  3468. reader.readAsDataURL(file);
  3469. }
  3470. };
  3471. fileInput.click();
  3472. }
  3473. },
  3474. });
  3475. }
  3476. clearMenu() {
  3477. this.sections.forEach((section) => {
  3478. if (section.element) {
  3479. section.element.remove();
  3480. }
  3481. });
  3482. this.sections = [];
  3483. }
  3484. applyMenuStyles() {
  3485. Object.assign(this.menu.style, {
  3486. backgroundColor: "rgba(30, 30, 30, 0.95)",
  3487. padding: "15px",
  3488. borderRadius: "10px",
  3489. boxShadow: "0 4px 15px rgba(0, 0, 0, 0.7)",
  3490. zIndex: "10001",
  3491. width: "300px",
  3492. fontFamily: "Arial, sans-serif",
  3493. color: "#fff",
  3494. maxHeight: "500px",
  3495. overflowY: "auto",
  3496. position: "fixed",
  3497. top: "15%",
  3498. left: "10%",
  3499. cursor: "move",
  3500. display: "none",
  3501. });
  3502. }
  3503. createHeader() {
  3504. const title = document.createElement("h2");
  3505. title.textContent = "KxsClient alpha";
  3506. Object.assign(title.style, {
  3507. margin: "0 0 10px",
  3508. textAlign: "center",
  3509. fontSize: "18px",
  3510. color: "#FFAE00",
  3511. });
  3512. const subtitle = document.createElement("p");
  3513. subtitle.textContent = "reset with tab";
  3514. Object.assign(subtitle.style, {
  3515. margin: "0 0 10px",
  3516. textAlign: "center",
  3517. fontSize: "12px",
  3518. color: "#ccc",
  3519. });
  3520. this.menu.appendChild(title);
  3521. this.menu.appendChild(subtitle);
  3522. }
  3523. addSection(title) {
  3524. const section = {
  3525. title,
  3526. options: [],
  3527. };
  3528. const sectionElement = document.createElement("div");
  3529. sectionElement.className = "menu-section";
  3530. const sectionTitle = document.createElement("h3");
  3531. sectionTitle.textContent = title;
  3532. Object.assign(sectionTitle.style, {
  3533. margin: "15px 0 10px",
  3534. fontSize: "16px",
  3535. color: "#4CAF50",
  3536. });
  3537. sectionElement.appendChild(sectionTitle);
  3538. this.menu.appendChild(sectionElement);
  3539. // Stocker la référence à l'élément DOM
  3540. section.element = sectionElement;
  3541. this.sections.push(section);
  3542. return section;
  3543. }
  3544. addOption(section, option) {
  3545. section.options.push(option);
  3546. const optionDiv = document.createElement("div");
  3547. Object.assign(optionDiv.style, {
  3548. display: "flex",
  3549. justifyContent: "space-between",
  3550. alignItems: "center",
  3551. marginBottom: "8px",
  3552. padding: "4px",
  3553. borderRadius: "4px",
  3554. backgroundColor: "rgba(255, 255, 255, 0.1)",
  3555. });
  3556. const label = document.createElement("span");
  3557. label.textContent = option.label;
  3558. label.style.color = "#fff";
  3559. let valueElement = null;
  3560. switch (option.type) {
  3561. case "toggle":
  3562. valueElement = this.createToggleElement(option);
  3563. break;
  3564. case "input":
  3565. valueElement = this.createInputElement(option);
  3566. break;
  3567. case "click":
  3568. valueElement = this.createClickElement(option);
  3569. break;
  3570. }
  3571. optionDiv.appendChild(label);
  3572. optionDiv.appendChild(valueElement);
  3573. // Utiliser la référence stockée à l'élément de section
  3574. if (section.element) {
  3575. section.element.appendChild(optionDiv);
  3576. }
  3577. }
  3578. createToggleElement(option) {
  3579. const toggle = document.createElement("div");
  3580. toggle.style.cursor = "pointer";
  3581. toggle.style.color = option.value ? "#4CAF50" : "#ff4444";
  3582. toggle.textContent = String(option.value);
  3583. toggle.addEventListener("click", () => {
  3584. var _a;
  3585. const newValue = !option.value;
  3586. option.value = newValue;
  3587. toggle.textContent = String(newValue);
  3588. toggle.style.color = newValue ? "#4CAF50" : "#ff4444";
  3589. (_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, newValue);
  3590. });
  3591. return toggle;
  3592. }
  3593. createClickElement(option) {
  3594. const button = document.createElement("button");
  3595. button.textContent = option.label;
  3596. button.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
  3597. button.style.border = "none";
  3598. button.style.borderRadius = "3px";
  3599. button.style.color = "#FFAE00";
  3600. button.style.padding = "2px 5px";
  3601. button.style.cursor = "pointer";
  3602. button.style.fontSize = "12px";
  3603. button.addEventListener("click", () => {
  3604. var _a;
  3605. (_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, true);
  3606. });
  3607. return button;
  3608. }
  3609. createInputElement(option) {
  3610. const input = document.createElement("input");
  3611. input.type = "text";
  3612. input.value = String(option.value);
  3613. Object.assign(input.style, {
  3614. backgroundColor: "rgba(255, 255, 255, 0.1)",
  3615. border: "none",
  3616. borderRadius: "3px",
  3617. color: "#FFAE00",
  3618. padding: "2px 5px",
  3619. width: "60px",
  3620. textAlign: "right",
  3621. });
  3622. input.addEventListener("change", () => {
  3623. var _a;
  3624. option.value = input.value;
  3625. (_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, input.value);
  3626. });
  3627. return input;
  3628. }
  3629. addShiftListener() {
  3630. window.addEventListener("keydown", this.boundShiftListener);
  3631. }
  3632. addDragListeners() {
  3633. this.menu.addEventListener("mousedown", this.boundMouseDownListener);
  3634. window.addEventListener("mousemove", this.boundMouseMoveListener);
  3635. window.addEventListener("mouseup", this.boundMouseUpListener);
  3636. }
  3637. toggleMenuVisibility() {
  3638. this.isClientMenuVisible = !this.isClientMenuVisible;
  3639. this.kxsClient.nm.showNotification(this.isClientMenuVisible ? "Opening menu..." : "Closing menu...", "info", 1400);
  3640. this.menu.style.display = this.isClientMenuVisible ? "block" : "none";
  3641. }
  3642. destroy() {
  3643. // Remove event listeners
  3644. window.removeEventListener("keydown", this.boundShiftListener);
  3645. this.menu.removeEventListener("mousedown", this.boundMouseDownListener);
  3646. window.removeEventListener("mousemove", this.boundMouseMoveListener);
  3647. window.removeEventListener("mouseup", this.boundMouseUpListener);
  3648. // Remove all section elements and clear sections array
  3649. this.sections.forEach(section => {
  3650. if (section.element) {
  3651. // Remove all option elements within the section
  3652. const optionElements = section.element.querySelectorAll("div");
  3653. optionElements.forEach(element => {
  3654. // Remove event listeners from toggle and input elements
  3655. const interactive = element.querySelector("div, input");
  3656. if (interactive) {
  3657. interactive.replaceWith(interactive.cloneNode(true));
  3658. }
  3659. element.remove();
  3660. });
  3661. section.element.remove();
  3662. }
  3663. });
  3664. this.sections = [];
  3665. // Remove the menu from DOM
  3666. this.menu.remove();
  3667. // Reset instance variables
  3668. this.isClientMenuVisible = false;
  3669. this.isDragging = false;
  3670. this.dragOffset = { x: 0, y: 0 };
  3671. this.menu = null;
  3672. // Clear references
  3673. this.kxsClient = null;
  3674. this.boundShiftListener = null;
  3675. this.boundMouseDownListener = null;
  3676. this.boundMouseMoveListener = null;
  3677. this.boundMouseUpListener = null;
  3678. }
  3679. getMenuVisibility() {
  3680. return this.isClientMenuVisible;
  3681. }
  3682. }
  3683.  
  3684.  
  3685. ;// ./src/ClientSecondaryMenuRework.ts
  3686.  
  3687.  
  3688. class KxsClientSecondaryMenu {
  3689. constructor(kxsClient) {
  3690. this.searchTerm = '';
  3691. this.shiftListener = (event) => {
  3692. if (event.key === "Shift" && event.location == 2) {
  3693. this.clearMenu();
  3694. this.toggleMenuVisibility();
  3695. this.loadOption();
  3696. // Ensure options are displayed after loading
  3697. this.filterOptions();
  3698. }
  3699. };
  3700. this.mouseMoveListener = (e) => {
  3701. if (this.isDragging) {
  3702. const x = e.clientX - this.dragOffset.x;
  3703. const y = e.clientY - this.dragOffset.y;
  3704. this.menu.style.transform = 'none';
  3705. this.menu.style.left = `${x}px`;
  3706. this.menu.style.top = `${y}px`;
  3707. }
  3708. };
  3709. this.mouseUpListener = () => {
  3710. this.isDragging = false;
  3711. this.menu.style.cursor = "grab";
  3712. };
  3713. this.kxsClient = kxsClient;
  3714. this.isClientMenuVisible = false;
  3715. this.isDragging = false;
  3716. this.dragOffset = { x: 0, y: 0 };
  3717. this.sections = [];
  3718. this.allOptions = [];
  3719. this.activeCategory = "ALL";
  3720. this.menu = document.createElement("div");
  3721. this.initMenu();
  3722. this.addShiftListener();
  3723. this.addDragListeners();
  3724. }
  3725. initMenu() {
  3726. this.menu.id = "kxsMenuIG";
  3727. this.applyMenuStyles();
  3728. this.createHeader();
  3729. this.createGridContainer();
  3730. document.body.appendChild(this.menu);
  3731. }
  3732. applyMenuStyles() {
  3733. Object.assign(this.menu.style, {
  3734. backgroundColor: "rgba(17, 24, 39, 0.95)",
  3735. padding: "20px",
  3736. borderRadius: "12px",
  3737. boxShadow: "0 4px 20px rgba(0, 0, 0, 0.8)",
  3738. zIndex: "10001",
  3739. width: "800px",
  3740. fontFamily: "'Segoe UI', Arial, sans-serif",
  3741. color: "#fff",
  3742. maxHeight: "80vh",
  3743. overflowY: "auto",
  3744. overflowX: "hidden", // Prevent horizontal scrolling
  3745. position: "fixed",
  3746. top: "10%",
  3747. left: "50%",
  3748. transform: "translateX(-50%)",
  3749. display: "none",
  3750. boxSizing: "border-box", // Include padding in width calculation
  3751. });
  3752. }
  3753. createHeader() {
  3754. const header = document.createElement("div");
  3755. header.style.marginBottom = "20px";
  3756. header.innerHTML = `
  3757. <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; width: 100%; box-sizing: border-box;">
  3758. <div style="display: flex; align-items: center; gap: 10px;">
  3759. <img src="${kxs_logo}"
  3760. alt="Logo" style="width: 24px; height: 24px;">
  3761. <span style="font-size: 20px; font-weight: bold;">KXS CLIENT</span>
  3762. </div>
  3763. <div style="display: flex; gap: 10px;">
  3764. <button style="
  3765. padding: 6px;
  3766. background: none;
  3767. border: none;
  3768. color: white;
  3769. cursor: pointer;
  3770. font-size: 18px;
  3771. ">×</button>
  3772. </div>
  3773. </div>
  3774. <div style="display: flex; flex-direction: column; gap: 10px; margin-bottom: 15px; width: 100%; box-sizing: border-box;">
  3775. <div style="display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 5px;">
  3776. ${["ALL", "HUD", "SERVER", "MECHANIC"].map(cat => `
  3777. <button class="category-btn" data-category="${cat}" style="
  3778. padding: 6px 16px;
  3779. background: ${this.activeCategory === cat ? '#3B82F6' : 'rgba(55, 65, 81, 0.8)'};
  3780. border: none;
  3781. border-radius: 6px;
  3782. color: white;
  3783. cursor: pointer;
  3784. font-size: 14px;
  3785. transition: background 0.2s;
  3786. ">${cat}</button>
  3787. `).join('')}
  3788. </div>
  3789. <div style="display: flex; width: 100%; box-sizing: border-box;">
  3790. <div style="position: relative; width: 100%; box-sizing: border-box;">
  3791. <input type="text" id="kxsSearchInput" placeholder="Search options..." style="
  3792. width: 100%;
  3793. padding: 8px 12px 8px 32px;
  3794. background: rgba(55, 65, 81, 0.8);
  3795. border: none;
  3796. border-radius: 6px;
  3797. color: white;
  3798. font-size: 14px;
  3799. outline: none;
  3800. box-sizing: border-box;
  3801. ">
  3802. <div style="
  3803. position: absolute;
  3804. left: 10px;
  3805. top: 50%;
  3806. transform: translateY(-50%);
  3807. width: 14px;
  3808. height: 14px;
  3809. ">
  3810. <svg fill="#ffffff" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  3811. <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
  3812. </svg>
  3813. </div>
  3814. </div>
  3815. </div>
  3816. </div>
  3817. `;
  3818. header.querySelectorAll('.category-btn').forEach(btn => {
  3819. btn.addEventListener('click', (e) => {
  3820. const category = e.target.dataset.category;
  3821. if (category) {
  3822. this.setActiveCategory(category);
  3823. }
  3824. });
  3825. });
  3826. const closeButton = header.querySelector('button');
  3827. closeButton === null || closeButton === void 0 ? void 0 : closeButton.addEventListener('click', () => {
  3828. this.toggleMenuVisibility();
  3829. });
  3830. const searchInput = header.querySelector('#kxsSearchInput');
  3831. if (searchInput) {
  3832. // Gestionnaire pour mettre à jour la recherche
  3833. searchInput.addEventListener('input', (e) => {
  3834. this.searchTerm = e.target.value.toLowerCase();
  3835. this.filterOptions();
  3836. });
  3837. // Prevent keys from being interpreted by the game
  3838. // We only block the propagation of keyboard events, except for special keys
  3839. ['keydown', 'keyup', 'keypress'].forEach(eventType => {
  3840. searchInput.addEventListener(eventType, (e) => {
  3841. const keyEvent = e;
  3842. // Don't block special keys (Escape, Shift)
  3843. if (keyEvent.key === 'Escape' || (keyEvent.key === 'Shift' && keyEvent.location === 2)) {
  3844. return; // Let the event propagate normally
  3845. }
  3846. // Block propagation for all other keys
  3847. e.stopPropagation();
  3848. });
  3849. });
  3850. // Assurer que le champ garde le focus
  3851. searchInput.addEventListener('blur', () => {
  3852. // Retarder légèrement pour permettre d'autres interactions
  3853. setTimeout(() => {
  3854. if (this.isClientMenuVisible) {
  3855. searchInput.focus();
  3856. }
  3857. }, 100);
  3858. });
  3859. }
  3860. this.menu.appendChild(header);
  3861. }
  3862. clearMenu() {
  3863. const gridContainer = document.getElementById('kxsMenuGrid');
  3864. if (gridContainer) {
  3865. gridContainer.innerHTML = '';
  3866. }
  3867. // Reset search term when clearing menu
  3868. this.searchTerm = '';
  3869. const searchInput = document.getElementById('kxsSearchInput');
  3870. if (searchInput) {
  3871. searchInput.value = '';
  3872. }
  3873. }
  3874. loadOption() {
  3875. // Clear existing options to avoid duplicates
  3876. this.allOptions = [];
  3877. let HUD = this.addSection("HUD", 'HUD');
  3878. let MECHANIC = this.addSection("MECHANIC", 'MECHANIC');
  3879. let SERVER = this.addSection("SERVER", 'SERVER');
  3880. this.addOption(HUD, {
  3881. label: "Clean Main Menu",
  3882. value: this.kxsClient.isMainMenuCleaned,
  3883. category: "HUD",
  3884. icon: '<svg fill="#000000" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <defs> <style> .cls-1 { fill: none; } </style> </defs> <title>clean</title> <rect x="20" y="18" width="6" height="2" transform="translate(46 38) rotate(-180)"></rect> <rect x="24" y="26" width="6" height="2" transform="translate(54 54) rotate(-180)"></rect> <rect x="22" y="22" width="6" height="2" transform="translate(50 46) rotate(-180)"></rect> <path d="M17.0029,20a4.8952,4.8952,0,0,0-2.4044-4.1729L22,3,20.2691,2,12.6933,15.126A5.6988,5.6988,0,0,0,7.45,16.6289C3.7064,20.24,3.9963,28.6821,4.01,29.04a1,1,0,0,0,1,.96H20.0012a1,1,0,0,0,.6-1.8C17.0615,25.5439,17.0029,20.0537,17.0029,20ZM11.93,16.9971A3.11,3.11,0,0,1,15.0041,20c0,.0381.0019.208.0168.4688L9.1215,17.8452A3.8,3.8,0,0,1,11.93,16.9971ZM15.4494,28A5.2,5.2,0,0,1,14,25H12a6.4993,6.4993,0,0,0,.9684,3H10.7451A16.6166,16.6166,0,0,1,10,24H8a17.3424,17.3424,0,0,0,.6652,4H6c.031-1.8364.29-5.8921,1.8027-8.5527l7.533,3.35A13.0253,13.0253,0,0,0,17.5968,28Z"></path> <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32"></rect> </g></svg>',
  3885. type: "toggle",
  3886. onChange: (value) => {
  3887. this.kxsClient.isMainMenuCleaned = !this.kxsClient.isMainMenuCleaned;
  3888. this.kxsClient.MainMenuCleaning();
  3889. this.kxsClient.updateLocalStorage();
  3890. },
  3891. });
  3892. this.addOption(HUD, {
  3893. label: "Show Ping",
  3894. value: this.kxsClient.isPingVisible,
  3895. category: "HUD",
  3896. icon: '<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><defs><style>.a{fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;}</style></defs><path class="a" d="M34.6282,24.0793a14.7043,14.7043,0,0,0-22.673,1.7255"></path><path class="a" d="M43.5,20.5846a23.8078,23.8078,0,0,0-39,0"></path><path class="a" d="M43.5,20.5845,22.0169,29.0483a5.5583,5.5583,0,1,0,6.2116,8.7785l.0153.0206Z"></path></g></svg>',
  3897. type: "toggle",
  3898. onChange: (value) => {
  3899. this.kxsClient.isPingVisible = !this.kxsClient.isPingVisible;
  3900. this.kxsClient.updatePingVisibility();
  3901. this.kxsClient.updateLocalStorage();
  3902. },
  3903. });
  3904. this.addOption(HUD, {
  3905. label: "Show FPS",
  3906. value: this.kxsClient.isFpsVisible,
  3907. category: "HUD",
  3908. type: "toggle",
  3909. icon: '<svg fill="#000000" viewBox="0 0 24 24" id="60fps" data-name="Flat Line" xmlns="http://www.w3.org/2000/svg" class="icon flat-line"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><rect id="primary" x="10.5" y="8.5" width="14" height="7" rx="1" transform="translate(5.5 29.5) rotate(-90)" style="fill: none; stroke: #000000; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></rect><path id="primary-2" data-name="primary" d="M3,12H9a1,1,0,0,1,1,1v5a1,1,0,0,1-1,1H4a1,1,0,0,1-1-1V6A1,1,0,0,1,4,5h6" style="fill: none; stroke: #000000; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></path></g></svg>',
  3910. onChange: (value) => {
  3911. this.kxsClient.isFpsVisible = !this.kxsClient.isFpsVisible;
  3912. this.kxsClient.updateFpsVisibility();
  3913. this.kxsClient.updateLocalStorage();
  3914. },
  3915. });
  3916. this.addOption(HUD, {
  3917. label: "Show Kills",
  3918. value: this.kxsClient.isKillsVisible,
  3919. type: "toggle",
  3920. category: "HUD",
  3921. icon: '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M14.7245 11.2754L16 12.4999L10.0129 17.8218C8.05054 19.5661 5.60528 20.6743 3 20.9999L3.79443 19.5435C4.6198 18.0303 5.03249 17.2737 5.50651 16.5582C5.92771 15.9224 6.38492 15.3113 6.87592 14.7278C7.42848 14.071 8.0378 13.4615 9.25644 12.2426L12 9.49822M11.5 8.99787L17.4497 3.04989C18.0698 2.42996 19.0281 2.3017 19.7894 2.73674C20.9027 3.37291 21.1064 4.89355 20.1997 5.80024L19.8415 6.15847C19.6228 6.3771 19.3263 6.49992 19.0171 6.49992H18L16 8.49992V8.67444C16 9.16362 16 9.40821 15.9447 9.63839C15.8957 9.84246 15.8149 10.0375 15.7053 10.2165C15.5816 10.4183 15.4086 10.5913 15.0627 10.9372L14.2501 11.7498L11.5 8.99787Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>',
  3922. onChange: (value) => {
  3923. this.kxsClient.isKillsVisible = !this.kxsClient.isKillsVisible;
  3924. this.kxsClient.updateKillsVisibility();
  3925. this.kxsClient.updateLocalStorage();
  3926. },
  3927. });
  3928. this.addOption(HUD, {
  3929. label: "Use Legacy Menu",
  3930. value: this.kxsClient.isLegaySecondaryMenu,
  3931. type: "toggle",
  3932. category: 'HUD',
  3933. icon: '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M4 12H20M4 8H20M4 16H12" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>',
  3934. onChange: (value) => {
  3935. this.kxsClient.isLegaySecondaryMenu = !this.kxsClient.isLegaySecondaryMenu;
  3936. this.kxsClient.updateLocalStorage();
  3937. this.kxsClient.secondaryMenu = new KxsLegacyClientSecondaryMenu(this.kxsClient);
  3938. this.destroy();
  3939. },
  3940. });
  3941. this.addOption(MECHANIC, {
  3942. label: "Death sound",
  3943. value: this.kxsClient.isDeathSoundEnabled,
  3944. type: "toggle",
  3945. icon: '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M19 21C19 21.5523 18.5523 22 18 22H14H10H6C5.44771 22 5 21.5523 5 21V18.75C5 17.7835 4.2165 17 3.25 17C2.55964 17 2 16.4404 2 15.75V11C2 5.47715 6.47715 1 12 1C17.5228 1 22 5.47715 22 11V15.75C22 16.4404 21.4404 17 20.75 17C19.7835 17 19 17.7835 19 18.75V21ZM17 20V18.75C17 16.9358 18.2883 15.4225 20 15.075V11C20 6.58172 16.4183 3 12 3C7.58172 3 4 6.58172 4 11V15.075C5.71168 15.4225 7 16.9358 7 18.75V20H9V18C9 17.4477 9.44771 17 10 17C10.5523 17 11 17.4477 11 18V20H13V18C13 17.4477 13.4477 17 14 17C14.5523 17 15 17.4477 15 18V20H17ZM11 12.5C11 13.8807 8.63228 15 7.25248 15C5.98469 15 5.99206 14.055 6.00161 12.8306V12.8305C6.00245 12.7224 6.00331 12.6121 6.00331 12.5C6.00331 11.1193 7.12186 10 8.50166 10C9.88145 10 11 11.1193 11 12.5ZM17.9984 12.8306C17.9975 12.7224 17.9967 12.6121 17.9967 12.5C17.9967 11.1193 16.8781 10 15.4983 10C14.1185 10 13 11.1193 13 12.5C13 13.8807 15.3677 15 16.7475 15C18.0153 15 18.0079 14.055 17.9984 12.8306Z" fill="#000000"></path> </g></svg>',
  3946. category: "MECHANIC",
  3947. onChange: (value) => {
  3948. this.kxsClient.isDeathSoundEnabled = !this.kxsClient.isDeathSoundEnabled;
  3949. this.kxsClient.updateLocalStorage();
  3950. },
  3951. });
  3952. this.addOption(HUD, {
  3953. label: "Win sound",
  3954. value: this.kxsClient.isWinSoundEnabled,
  3955. type: "toggle",
  3956. icon: '<svg fill="#000000" version="1.1" id="Trophy_x5F_cup" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M190.878,111.272c31.017-11.186,53.254-40.907,53.254-75.733l-0.19-8.509h-48.955V5H64.222v22.03H15.266l-0.19,8.509 c0,34.825,22.237,64.546,53.254,75.733c7.306,18.421,22.798,31.822,41.878,37.728v20c-0.859,15.668-14.112,29-30,29v18h-16v35H195 v-35h-16v-18c-15.888,0-29.141-13.332-30-29v-20C168.08,143.094,183.572,129.692,190.878,111.272z M195,44h30.563 c-0.06,0.427-0.103,1.017-0.171,1.441c-3.02,18.856-14.543,34.681-30.406,44.007C195.026,88.509,195,44,195,44z M33.816,45.441 c-0.068-0.424-0.111-1.014-0.171-1.441h30.563c0,0-0.026,44.509,0.013,45.448C48.359,80.122,36.837,64.297,33.816,45.441z M129.604,86.777l-20.255,13.52l6.599-23.442L96.831,61.77l24.334-0.967l8.44-22.844l8.44,22.844l24.334,0.967L143.26,76.856 l6.599,23.442L129.604,86.777z"></path> </g></svg>',
  3957. category: "HUD",
  3958. onChange: (value) => {
  3959. this.kxsClient.isWinSoundEnabled = !this.kxsClient.isWinSoundEnabled;
  3960. this.kxsClient.updateLocalStorage();
  3961. },
  3962. });
  3963. this.addOption(SERVER, {
  3964. label: "Webhook URL",
  3965. value: this.kxsClient.discordWebhookUrl || "",
  3966. icon: '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M12.52 3.046a3 3 0 0 0-2.13 5.486 1 1 0 0 1 .306 1.38l-3.922 6.163a2 2 0 1 1-1.688-1.073l3.44-5.405a5 5 0 1 1 8.398-2.728 1 1 0 1 1-1.97-.348 3 3 0 0 0-2.433-3.475zM10 6a2 2 0 1 1 3.774.925l3.44 5.405a5 5 0 1 1-1.427 8.5 1 1 0 0 1 1.285-1.532 3 3 0 1 0 .317-4.83 1 1 0 0 1-1.38-.307l-3.923-6.163A2 2 0 0 1 10 6zm-5.428 6.9a1 1 0 0 1-.598 1.281A3 3 0 1 0 8.001 17a1 1 0 0 1 1-1h8.266a2 2 0 1 1 0 2H9.9a5 5 0 1 1-6.61-5.698 1 1 0 0 1 1.282.597Z" fill="#000000"></path> </g></svg>',
  3967. category: "SERVER",
  3968. type: "input",
  3969. onChange: (value) => {
  3970. value = value.toString().trim();
  3971. this.kxsClient.discordWebhookUrl = value;
  3972. this.kxsClient.discordTracker.setWebhookUrl(value);
  3973. this.kxsClient.updateLocalStorage();
  3974. },
  3975. });
  3976. this.addOption(MECHANIC, {
  3977. label: "Heal Warning",
  3978. value: this.kxsClient.isHealthWarningEnabled,
  3979. type: "toggle",
  3980. category: "MECHANIC",
  3981. icon: '<svg viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>health</title> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="add" fill="#000000" transform="translate(42.666667, 64.000000)"> <path d="M365.491733,234.665926 C339.947827,276.368766 302.121072,321.347032 252.011468,369.600724 L237.061717,383.7547 C234.512147,386.129148 231.933605,388.511322 229.32609,390.901222 L213.333333,405.333333 C205.163121,398.070922 197.253659,390.878044 189.604949,383.7547 L174.655198,369.600724 C124.545595,321.347032 86.7188401,276.368766 61.174934,234.665926 L112.222458,234.666026 C134.857516,266.728129 165.548935,301.609704 204.481843,339.08546 L213.333333,347.498667 L214.816772,346.115558 C257.264819,305.964102 290.400085,268.724113 314.444476,234.665648 L365.491733,234.665926 Z M149.333333,58.9638831 L213.333333,186.944 L245.333333,122.963883 L269.184,170.666667 L426.666667,170.666667 L426.666667,213.333333 L247.850667,213.333333 L213.333333,282.36945 L149.333333,154.368 L119.851392,213.333333 L3.55271368e-14,213.333333 L3.55271368e-14,170.666667 L93.4613333,170.666667 L149.333333,58.9638831 Z M290.133333,0 C353.756537,0 405.333333,51.5775732 405.333333,115.2 C405.333333,126.248908 404.101625,137.626272 401.63821,149.33209 L357.793994,149.332408 C360.62486,138.880112 362.217829,128.905378 362.584434,119.422244 L362.666667,115.2 C362.666667,75.1414099 330.192075,42.6666667 290.133333,42.6666667 C273.651922,42.6666667 258.124715,48.1376509 245.521279,58.0219169 L241.829932,61.1185374 L213.366947,86.6338354 L184.888885,61.1353673 C171.661383,49.2918281 154.669113,42.6666667 136.533333,42.6666667 C96.4742795,42.6666667 64,75.1409461 64,115.2 C64,125.932203 65.6184007,137.316846 68.8727259,149.332605 L25.028457,149.33209 C22.5650412,137.626272 21.3333333,126.248908 21.3333333,115.2 C21.3333333,51.5767968 72.9101302,0 136.533333,0 C166.046194,0 192.966972,11.098031 213.350016,29.348444 C233.716605,11.091061 260.629741,0 290.133333,0 Z" id="Combined-Shape"> </path> </g> </g> </g></svg>',
  3982. onChange: (value) => {
  3983. this.kxsClient.isHealthWarningEnabled = !this.kxsClient.isHealthWarningEnabled;
  3984. this.kxsClient.updateLocalStorage();
  3985. },
  3986. });
  3987. this.addOption(SERVER, {
  3988. label: "Update Checker",
  3989. value: this.kxsClient.isAutoUpdateEnabled,
  3990. type: "toggle",
  3991. icon: '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M18.4721 16.7023C17.3398 18.2608 15.6831 19.3584 13.8064 19.7934C11.9297 20.2284 9.95909 19.9716 8.25656 19.0701C6.55404 18.1687 5.23397 16.6832 4.53889 14.8865C3.84381 13.0898 3.82039 11.1027 4.47295 9.29011C5.12551 7.47756 6.41021 5.96135 8.09103 5.02005C9.77184 4.07875 11.7359 3.77558 13.6223 4.16623C15.5087 4.55689 17.1908 5.61514 18.3596 7.14656C19.5283 8.67797 20.1052 10.5797 19.9842 12.5023M19.9842 12.5023L21.4842 11.0023M19.9842 12.5023L18.4842 11.0023" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M12 8V12L15 15" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>',
  3992. category: "SERVER",
  3993. onChange: (value) => {
  3994. this.kxsClient.isAutoUpdateEnabled = !this.kxsClient.isAutoUpdateEnabled;
  3995. this.kxsClient.updateLocalStorage();
  3996. },
  3997. });
  3998. this.addOption(MECHANIC, {
  3999. label: `Uncap FPS`,
  4000. value: this.kxsClient.isFpsUncapped,
  4001. type: "toggle",
  4002. icon: '<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <title>ic_fluent_fps_960_24_filled</title> <desc>Created with Sketch.</desc> <g id="🔍-Product-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="ic_fluent_fps_960_24_filled" fill="#000000" fill-rule="nonzero"> <path d="M11.75,15 C12.9926407,15 14,16.0073593 14,17.25 C14,18.440864 13.0748384,19.4156449 11.9040488,19.4948092 L11.75,19.5 L11,19.5 L11,21.25 C11,21.6296958 10.7178461,21.943491 10.3517706,21.9931534 L10.25,22 C9.87030423,22 9.55650904,21.7178461 9.50684662,21.3517706 L9.5,21.25 L9.5,15.75 C9.5,15.3703042 9.78215388,15.056509 10.1482294,15.0068466 L10.25,15 L11.75,15 Z M18,15 C19.1045695,15 20,15.8954305 20,17 C20,17.4142136 19.6642136,17.75 19.25,17.75 C18.8703042,17.75 18.556509,17.4678461 18.5068466,17.1017706 L18.5,17 C18.5,16.7545401 18.3231248,16.5503916 18.0898756,16.5080557 L18,16.5 L17.375,16.5 C17.029822,16.5 16.75,16.779822 16.75,17.125 C16.75,17.4387982 16.9812579,17.6985831 17.2826421,17.7432234 L17.375,17.75 L17.875,17.75 C19.0486051,17.75 20,18.7013949 20,19.875 C20,20.9975788 19.1295366,21.91685 18.0267588,21.9946645 L17.875,22 L17.25,22 C16.1454305,22 15.25,21.1045695 15.25,20 C15.25,19.5857864 15.5857864,19.25 16,19.25 C16.3796958,19.25 16.693491,19.5321539 16.7431534,19.8982294 L16.75,20 C16.75,20.2454599 16.9268752,20.4496084 17.1601244,20.4919443 L17.25,20.5 L17.875,20.5 C18.220178,20.5 18.5,20.220178 18.5,19.875 C18.5,19.5612018 18.2687421,19.3014169 17.9673579,19.2567766 L17.875,19.25 L17.375,19.25 C16.2013949,19.25 15.25,18.2986051 15.25,17.125 C15.25,16.0024212 16.1204634,15.08315 17.2232412,15.0053355 L17.375,15 L18,15 Z M7.75,15 C8.16421356,15 8.5,15.3357864 8.5,15.75 C8.5,16.1296958 8.21784612,16.443491 7.85177056,16.4931534 L7.75,16.5 L5.5,16.4990964 L5.5,18.0020964 L7.25,18.002809 C7.66421356,18.002809 8,18.3385954 8,18.752809 C8,19.1325047 7.71784612,19.4462999 7.35177056,19.4959623 L7.25,19.502809 L5.5,19.5020964 L5.5,21.2312276 C5.5,21.6109234 5.21784612,21.9247186 4.85177056,21.974381 L4.75,21.9812276 C4.37030423,21.9812276 4.05650904,21.6990738 4.00684662,21.3329982 L4,21.2312276 L4,15.75 C4,15.3703042 4.28215388,15.056509 4.64822944,15.0068466 L4.75,15 L7.75,15 Z M11.75,16.5 L11,16.5 L11,18 L11.75,18 C12.1642136,18 12.5,17.6642136 12.5,17.25 C12.5,16.8703042 12.2178461,16.556509 11.8517706,16.5068466 L11.75,16.5 Z M5,3 C6.65685425,3 8,4.34314575 8,6 L7.99820112,6.1048763 L8,6.15469026 L8,10 C8,11.5976809 6.75108004,12.9036609 5.17627279,12.9949073 L5,13 L4.7513884,13 C3.23183855,13 2,11.7681615 2,10.2486116 C2,9.69632685 2.44771525,9.2486116 3,9.2486116 C3.51283584,9.2486116 3.93550716,9.63465179 3.99327227,10.1319905 L4,10.2486116 C4,10.6290103 4.28267621,10.9433864 4.64942945,10.9931407 L4.7513884,11 L5,11 C5.51283584,11 5.93550716,10.6139598 5.99327227,10.1166211 L6,10 L5.99991107,8.82932572 C5.68715728,8.93985718 5.35060219,9 5,9 C3.34314575,9 2,7.65685425 2,6 C2,4.34314575 3.34314575,3 5,3 Z M12.2512044,3 C13.7707542,3 15.0025928,4.23183855 15.0025928,5.7513884 C15.0025928,6.30367315 14.5548775,6.7513884 14.0025928,6.7513884 C13.489757,6.7513884 13.0670856,6.36534821 13.0093205,5.86800953 L13.0025928,5.7513884 C13.0025928,5.37098974 12.7199166,5.05661365 12.3531633,5.00685929 L12.2512044,5 L12.0025928,5 C11.489757,5 11.0670856,5.38604019 11.0093205,5.88337887 L11.0025928,6 L11.0026817,7.17067428 C11.3154355,7.06014282 11.6519906,7 12.0025928,7 C13.659447,7 15.0025928,8.34314575 15.0025928,10 C15.0025928,11.6568542 13.659447,13 12.0025928,13 C10.3457385,13 9.0025928,11.6568542 9.0025928,10 L9.00441213,9.89453033 L9.0025928,9.84530974 L9.0025928,6 C9.0025928,4.40231912 10.2515128,3.09633912 11.82632,3.00509269 L12.0025928,3 L12.2512044,3 Z M19,3 C20.5976809,3 21.9036609,4.24891996 21.9949073,5.82372721 L22,6 L22,10 C22,11.6568542 20.6568542,13 19,13 C17.4023191,13 16.0963391,11.75108 16.0050927,10.1762728 L16,10 L16,6 C16,4.34314575 17.3431458,3 19,3 Z M12.0025928,9 C11.450308,9 11.0025928,9.44771525 11.0025928,10 C11.0025928,10.5522847 11.450308,11 12.0025928,11 C12.5548775,11 13.0025928,10.5522847 13.0025928,10 C13.0025928,9.44771525 12.5548775,9 12.0025928,9 Z M19,5 C18.4871642,5 18.0644928,5.38604019 18.0067277,5.88337887 L18,6 L18,10 C18,10.5522847 18.4477153,11 19,11 C19.5128358,11 19.9355072,10.6139598 19.9932723,10.1166211 L20,10 L20,6 C20,5.44771525 19.5522847,5 19,5 Z M5,5 C4.44771525,5 4,5.44771525 4,6 C4,6.55228475 4.44771525,7 5,7 C5.55228475,7 6,6.55228475 6,6 C6,5.44771525 5.55228475,5 5,5 Z" id="🎨Color"> </path> </g> </g> </g></svg>',
  4003. category: 'MECHANIC',
  4004. onChange: () => {
  4005. this.kxsClient.toggleFpsUncap();
  4006. this.kxsClient.updateLocalStorage();
  4007. },
  4008. });
  4009. this.addOption(HUD, {
  4010. label: `Winning Animation`,
  4011. value: this.kxsClient.isWinningAnimationEnabled,
  4012. icon: '<svg fill="#000000" height="200px" width="200px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 448.881 448.881" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M189.82,138.531c-8.92,0-16.611,6.307-18.353,15.055l-11.019,55.306c-3.569,20.398-7.394,40.53-9.946,59.652h-0.513 c-2.543-19.122-5.35-37.474-9.176-57.615l-11.85-62.35c-1.112-5.832-6.206-10.048-12.139-10.048H95.819 c-5.854,0-10.909,4.114-12.099,9.853l-12.497,60.507c-4.332,21.159-8.414,41.805-11.213,60.413h-0.513 c-2.8-17.332-6.369-39.511-10.196-59.901l-10.024-54.643c-1.726-9.403-9.922-16.23-19.479-16.23c-6.05,0-11.774,2.77-15.529,7.52 c-3.755,4.751-5.133,10.965-3.733,16.851l32.747,137.944c1.322,5.568,6.299,9.503,12.022,9.503h22.878 c5.792,0,10.809-4.028,12.061-9.689l14.176-64.241c4.083-17.334,6.883-33.648,9.946-53.019h0.507 c2.037,19.627,4.845,35.685,8.157,53.019l12.574,63.96c1.136,5.794,6.222,9.97,12.125,9.97h22.325 c5.638,0,10.561-3.811,11.968-9.269l35.919-139.158c1.446-5.607,0.225-11.564-3.321-16.136 C201.072,141.207,195.612,138.531,189.82,138.531z"></path> <path d="M253.516,138.531c-10.763,0-19.495,8.734-19.495,19.503v132.821c0,10.763,8.732,19.495,19.495,19.495 c10.771,0,19.503-8.732,19.503-19.495V158.034C273.019,147.265,264.287,138.531,253.516,138.531z"></path> <path d="M431.034,138.531c-9.861,0-17.847,7.995-17.847,17.847v32.373c0,25.748,0.761,48.945,3.313,71.637h-0.763 c-7.652-19.379-17.847-40.786-28.041-58.891l-32.14-56.704c-2.193-3.865-6.299-6.26-10.747-6.26h-25.818 c-6.827,0-12.357,5.529-12.357,12.357v141.615c0,9.86,7.987,17.847,17.847,17.847c9.853,0,17.84-7.987,17.84-17.847v-33.905 c0-28.042-0.514-52.258-1.532-74.941l0.769-0.256c8.406,20.141,19.627,42.318,29.823,60.671l33.174,59.909 c2.177,3.927,6.321,6.369,10.809,6.369h21.159c6.828,0,12.357-5.53,12.357-12.357V156.378 C448.881,146.526,440.894,138.531,431.034,138.531z"></path> </g> </g></svg>',
  4013. category: "HUD",
  4014. type: "toggle",
  4015. onChange: () => {
  4016. this.kxsClient.isWinningAnimationEnabled = !this.kxsClient.isWinningAnimationEnabled;
  4017. this.kxsClient.updateLocalStorage();
  4018. },
  4019. });
  4020. this.addOption(HUD, {
  4021. label: `Spotify Player`,
  4022. value: this.kxsClient.isSpotifyPlayerEnabled,
  4023. icon: '<svg fill="#000000" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>spotify</title> <path d="M24.849 14.35c-3.206-1.616-6.988-2.563-10.991-2.563-2.278 0-4.484 0.306-6.58 0.881l0.174-0.041c-0.123 0.040-0.265 0.063-0.412 0.063-0.76 0-1.377-0.616-1.377-1.377 0-0.613 0.401-1.132 0.954-1.311l0.010-0.003c5.323-1.575 14.096-1.275 19.646 2.026 0.426 0.258 0.706 0.719 0.706 1.245 0 0.259-0.068 0.502-0.186 0.712l0.004-0.007c-0.29 0.345-0.721 0.563-1.204 0.563-0.273 0-0.529-0.070-0.752-0.192l0.008 0.004zM24.699 18.549c-0.201 0.332-0.561 0.55-0.971 0.55-0.225 0-0.434-0.065-0.61-0.178l0.005 0.003c-2.739-1.567-6.021-2.49-9.518-2.49-1.925 0-3.784 0.28-5.539 0.801l0.137-0.035c-0.101 0.032-0.217 0.051-0.337 0.051-0.629 0-1.139-0.51-1.139-1.139 0-0.509 0.333-0.939 0.793-1.086l0.008-0.002c1.804-0.535 3.878-0.843 6.023-0.843 3.989 0 7.73 1.064 10.953 2.925l-0.106-0.056c0.297 0.191 0.491 0.52 0.491 0.894 0 0.227-0.071 0.437-0.192 0.609l0.002-0.003zM22.899 22.673c-0.157 0.272-0.446 0.452-0.777 0.452-0.186 0-0.359-0.057-0.502-0.154l0.003 0.002c-2.393-1.346-5.254-2.139-8.299-2.139-1.746 0-3.432 0.261-5.020 0.745l0.122-0.032c-0.067 0.017-0.145 0.028-0.224 0.028-0.512 0-0.927-0.415-0.927-0.927 0-0.432 0.296-0.795 0.696-0.898l0.006-0.001c1.581-0.47 3.397-0.74 5.276-0.74 3.402 0 6.596 0.886 9.366 2.44l-0.097-0.050c0.302 0.15 0.506 0.456 0.506 0.809 0 0.172-0.048 0.333-0.132 0.469l0.002-0.004zM16 1.004c0 0 0 0-0 0-8.282 0-14.996 6.714-14.996 14.996s6.714 14.996 14.996 14.996c8.282 0 14.996-6.714 14.996-14.996v0c-0.025-8.272-6.724-14.971-14.993-14.996h-0.002z"></path> </g></svg>',
  4024. category: "HUD",
  4025. type: "toggle",
  4026. onChange: () => {
  4027. this.kxsClient.isSpotifyPlayerEnabled = !this.kxsClient.isSpotifyPlayerEnabled;
  4028. this.kxsClient.updateLocalStorage();
  4029. this.kxsClient.toggleSpotifyMenu();
  4030. },
  4031. });
  4032. this.addOption(HUD, {
  4033. label: "Kill Feed Blint Text",
  4034. value: this.kxsClient.isKillFeedBlint,
  4035. icon: `<svg fill="#000000" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title></title> <g data-name="Layer 2" id="Layer_2"> <path d="M18,11a1,1,0,0,1-1,1,5,5,0,0,0-5,5,1,1,0,0,1-2,0,5,5,0,0,0-5-5,1,1,0,0,1,0-2,5,5,0,0,0,5-5,1,1,0,0,1,2,0,5,5,0,0,0,5,5A1,1,0,0,1,18,11Z"></path> <path d="M19,24a1,1,0,0,1-1,1,2,2,0,0,0-2,2,1,1,0,0,1-2,0,2,2,0,0,0-2-2,1,1,0,0,1,0-2,2,2,0,0,0,2-2,1,1,0,0,1,2,0,2,2,0,0,0,2,2A1,1,0,0,1,19,24Z"></path> <path d="M28,17a1,1,0,0,1-1,1,4,4,0,0,0-4,4,1,1,0,0,1-2,0,4,4,0,0,0-4-4,1,1,0,0,1,0-2,4,4,0,0,0,4-4,1,1,0,0,1,2,0,4,4,0,0,0,4,4A1,1,0,0,1,28,17Z"></path> </g> </g></svg>`,
  4036. category: "HUD",
  4037. type: "toggle",
  4038. onChange: () => {
  4039. this.kxsClient.isKillFeedBlint = !this.kxsClient.isKillFeedBlint;
  4040. this.kxsClient.updateLocalStorage();
  4041. },
  4042. });
  4043. this.addOption(SERVER, {
  4044. label: `Rich Presence (Account token required)`,
  4045. value: this.kxsClient.discordToken || "",
  4046. icon: '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M18.59 5.88997C17.36 5.31997 16.05 4.89997 14.67 4.65997C14.5 4.95997 14.3 5.36997 14.17 5.69997C12.71 5.47997 11.26 5.47997 9.83001 5.69997C9.69001 5.36997 9.49001 4.95997 9.32001 4.65997C7.94001 4.89997 6.63001 5.31997 5.40001 5.88997C2.92001 9.62997 2.25001 13.28 2.58001 16.87C4.23001 18.1 5.82001 18.84 7.39001 19.33C7.78001 18.8 8.12001 18.23 8.42001 17.64C7.85001 17.43 7.31001 17.16 6.80001 16.85C6.94001 16.75 7.07001 16.64 7.20001 16.54C10.33 18 13.72 18 16.81 16.54C16.94 16.65 17.07 16.75 17.21 16.85C16.7 17.16 16.15 17.42 15.59 17.64C15.89 18.23 16.23 18.8 16.62 19.33C18.19 18.84 19.79 18.1 21.43 16.87C21.82 12.7 20.76 9.08997 18.61 5.88997H18.59ZM8.84001 14.67C7.90001 14.67 7.13001 13.8 7.13001 12.73C7.13001 11.66 7.88001 10.79 8.84001 10.79C9.80001 10.79 10.56 11.66 10.55 12.73C10.55 13.79 9.80001 14.67 8.84001 14.67ZM15.15 14.67C14.21 14.67 13.44 13.8 13.44 12.73C13.44 11.66 14.19 10.79 15.15 10.79C16.11 10.79 16.87 11.66 16.86 12.73C16.86 13.79 16.11 14.67 15.15 14.67Z" fill="#000000"></path> </g></svg>',
  4047. category: "SERVER",
  4048. type: "input",
  4049. onChange: (value) => {
  4050. value = value.toString().trim();
  4051. this.kxsClient.discordToken = this.kxsClient.parseToken(value);
  4052. this.kxsClient.discordRPC.disconnect();
  4053. this.kxsClient.discordRPC.connect();
  4054. this.kxsClient.updateLocalStorage();
  4055. },
  4056. });
  4057. this.addOption(MECHANIC, {
  4058. label: `Kill Leader Tracking`,
  4059. icon: '<svg fill="#000000" viewBox="-4 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>crown</title> <path d="M12 10.938c-1.375 0-2.5-1.125-2.5-2.5 0-1.406 1.125-2.5 2.5-2.5s2.5 1.094 2.5 2.5c0 1.375-1.125 2.5-2.5 2.5zM2.031 9.906c1.094 0 1.969 0.906 1.969 2 0 1.125-0.875 2-1.969 2-1.125 0-2.031-0.875-2.031-2 0-1.094 0.906-2 2.031-2zM22.031 9.906c1.094 0 1.969 0.906 1.969 2 0 1.125-0.875 2-1.969 2-1.125 0-2.031-0.875-2.031-2 0-1.094 0.906-2 2.031-2zM4.219 23.719l-1.656-9.063c0.5-0.094 0.969-0.375 1.344-0.688 1.031 0.938 2.344 1.844 3.594 1.844 1.5 0 2.719-2.313 3.563-4.25 0.281 0.094 0.625 0.188 0.938 0.188s0.656-0.094 0.938-0.188c0.844 1.938 2.063 4.25 3.563 4.25 1.25 0 2.563-0.906 3.594-1.844 0.375 0.313 0.844 0.594 1.344 0.688l-1.656 9.063h-15.563zM3.875 24.5h16.25v1.531h-16.25v-1.531z"></path> </g></svg>',
  4060. category: "MECHANIC",
  4061. value: this.kxsClient.isKillLeaderTrackerEnabled,
  4062. type: "toggle",
  4063. onChange: (value) => {
  4064. this.kxsClient.isKillLeaderTrackerEnabled = !this.kxsClient.isKillLeaderTrackerEnabled;
  4065. this.kxsClient.updateLocalStorage();
  4066. },
  4067. });
  4068. this.addOption(MECHANIC, {
  4069. label: `Friends Detector (separe with ',')`,
  4070. icon: '<svg fill="#000000" viewBox="0 -6 44 44" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M42.001,32.000 L14.010,32.000 C12.908,32.000 12.010,31.104 12.010,30.001 L12.010,28.002 C12.010,27.636 12.211,27.300 12.532,27.124 L22.318,21.787 C19.040,18.242 19.004,13.227 19.004,12.995 L19.010,7.002 C19.010,6.946 19.015,6.891 19.024,6.837 C19.713,2.751 24.224,0.007 28.005,0.007 C28.006,0.007 28.008,0.007 28.009,0.007 C31.788,0.007 36.298,2.749 36.989,6.834 C36.998,6.889 37.003,6.945 37.003,7.000 L37.006,12.994 C37.006,13.225 36.970,18.240 33.693,21.785 L43.479,27.122 C43.800,27.298 44.000,27.634 44.000,28.000 L44.000,30.001 C44.000,31.104 43.103,32.000 42.001,32.000 ZM31.526,22.880 C31.233,22.720 31.039,22.425 31.008,22.093 C30.978,21.761 31.116,21.436 31.374,21.226 C34.971,18.310 35.007,13.048 35.007,12.995 L35.003,7.089 C34.441,4.089 30.883,2.005 28.005,2.005 C25.126,2.006 21.570,4.091 21.010,7.091 L21.004,12.997 C21.004,13.048 21.059,18.327 24.636,21.228 C24.895,21.438 25.033,21.763 25.002,22.095 C24.972,22.427 24.778,22.722 24.485,22.882 L14.010,28.596 L14.010,30.001 L41.999,30.001 L42.000,28.595 L31.526,22.880 ZM18.647,2.520 C17.764,2.177 16.848,1.997 15.995,1.997 C13.116,1.998 9.559,4.083 8.999,7.083 L8.993,12.989 C8.993,13.041 9.047,18.319 12.625,21.220 C12.884,21.430 13.022,21.755 12.992,22.087 C12.961,22.419 12.767,22.714 12.474,22.874 L1.999,28.588 L1.999,29.993 L8.998,29.993 C9.550,29.993 9.997,30.441 9.997,30.993 C9.997,31.545 9.550,31.993 8.998,31.993 L1.999,31.993 C0.897,31.993 -0.000,31.096 -0.000,29.993 L-0.000,27.994 C-0.000,27.629 0.200,27.292 0.521,27.117 L10.307,21.779 C7.030,18.234 6.993,13.219 6.993,12.988 L6.999,6.994 C6.999,6.939 7.004,6.883 7.013,6.829 C7.702,2.744 12.213,-0.000 15.995,-0.000 C15.999,-0.000 16.005,-0.000 16.010,-0.000 C17.101,-0.000 18.262,0.227 19.369,0.656 C19.885,0.856 20.140,1.435 19.941,1.949 C19.740,2.464 19.158,2.720 18.647,2.520 Z"></path> </g></svg>',
  4071. category: "MECHANIC",
  4072. value: this.kxsClient.all_friends,
  4073. type: "input",
  4074. onChange: (value) => {
  4075. this.kxsClient.all_friends = value;
  4076. this.kxsClient.updateLocalStorage();
  4077. },
  4078. });
  4079. this.addOption(HUD, {
  4080. label: `Change Background`,
  4081. icon: '<svg height="200px" width="200px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 179.006 179.006" xml:space="preserve" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <polygon style="fill:#010002;" points="20.884,116.354 11.934,116.354 11.934,32.818 137.238,32.818 137.238,41.768 149.172,41.768 149.172,20.884 0,20.884 0,128.288 20.884,128.288 "></polygon> <path style="fill:#010002;" d="M29.834,50.718v107.404h149.172V50.718H29.834z M123.58,136.856c-0.024,0-0.048,0-0.072,0 c-0.012,0-1.187,0-2.81,0c-3.795,0-10.078,0-10.114,0c-19.625,0-39.25,0-58.875,0v-3.473c0.907-0.859,2.005-1.551,3.168-2.166 c1.981-1.062,3.938-2.148,5.967-3.115c1.957-0.937,3.998-1.742,6.003-2.59c1.886-0.8,3.801-1.545,5.674-2.363 c0.328-0.137,0.638-0.489,0.776-0.811c0.424-1.05,0.782-2.124,1.116-3.216c0.245-0.823,0.412-1.635,1.468-1.862 c0.263-0.048,0.597-0.513,0.627-0.817c0.209-1.581,0.37-3.168,0.489-4.744c0.024-0.346-0.149-0.776-0.382-1.038 c-1.384-1.557-2.142-3.353-2.47-5.406c-0.161-1.038-0.74-1.993-1.038-3.013c-0.394-1.366-0.728-2.745-1.038-4.129 c-0.119-0.501-0.048-1.038-0.125-1.551c-0.125-0.746-0.107-1.319,0.806-1.611c0.233-0.084,0.442-0.668,0.453-1.032 c0.048-2.214,0.012-4.433,0.024-6.641c0.012-1.36,0-2.727,0.107-4.087c0.185-2.596,1.718-4.421,3.622-5.997 c2.787-2.303,6.128-3.377,9.565-4.189c1.808-0.424,3.64-0.68,5.478-0.979c0.489-0.078,0.996-0.006,1.498-0.006 c0.095,0.125,0.161,0.251,0.251,0.37c-0.376,0.28-0.811,0.513-1.134,0.847c-0.746,0.746-0.674,1.265,0.125,1.945 c1.647,1.396,3.318,2.804,4.911,4.254c1.42,1.271,1.969,2.942,1.981,4.815c0,3.222,0,6.45,0,9.672c0,0.65-0.048,1.313,0.776,1.605 c0.167,0.066,0.352,0.424,0.34,0.632c-0.131,1.641-0.322,3.294-0.489,4.941c-0.006,0.066-0.018,0.131-0.054,0.185 c-1.486,2.166-1.677,4.827-2.733,7.148c-0.048,0.09-0.078,0.191-0.125,0.257c-1.969,2.315-1.36,5.102-1.396,7.769 c0,0.269,0.197,0.686,0.406,0.782c0.806,0.358,1.002,1.044,1.223,1.772c0.352,1.14,0.692,2.303,1.181,3.389 c0.179,0.394,0.716,0.746,1.17,0.907c0.943,0.364,1.886,0.74,2.834,1.11c2.363-1.002,5.734-2.434,6.385-2.727 c0.919-0.418,1.611-1.349,2.44-1.993c0.37-0.28,0.817-0.537,1.259-0.615c1.504-0.239,2.16-0.77,2.518-2.255 c0.465-1.945,0.806-3.89,0.388-5.913c-0.167-0.877-0.489-1.45-1.366-1.784c-1.778-0.698-3.532-1.474-5.293-2.22 c-1.319-0.555-1.396-1.02-0.919-2.387c1.516-4.296,2.631-8.658,3.007-13.258c0.28-3.443,0.048-6.981,1.307-10.305 c0.871-2.339,2.339-4.505,4.696-5.203c1.796-0.531,3.359-1.742,5.269-1.999c0.358-0.018,0.674-0.072,1.026-0.054 c0.042,0.006,0.078,0.012,0.113,0.012c4.529,0.286,9.923,3.019,11.2,8.043c0.066,0.257,0.101,0.525,0.143,0.788h0.125 c0.698,2.852,0.621,5.818,0.859,8.712c0.37,4.594,1.504,8.962,3.019,13.264c0.477,1.366,0.394,1.832-0.919,2.381 c-1.76,0.746-3.514,1.522-5.299,2.22c-0.871,0.34-1.181,0.895-1.36,1.784c-0.406,2.029-0.084,3.968,0.388,5.913 c0.346,1.48,1.014,2.011,2.512,2.25c0.442,0.078,0.883,0.334,1.259,0.615c0.829,0.644,1.516,1.569,2.44,1.993 c3.234,1.468,6.51,2.888,9.839,4.117c5.114,1.88,8.509,5.478,9.326,11.045C145.944,136.856,134.768,136.856,123.58,136.856z"></path> </g> </g> </g></svg>',
  4082. category: "HUD",
  4083. value: true,
  4084. type: "click",
  4085. onChange: () => {
  4086. const backgroundElement = document.getElementById("background");
  4087. if (!backgroundElement) {
  4088. alert("Element with id 'background' not found.");
  4089. return;
  4090. }
  4091. const choice = prompt("Enter '0' to default Kxs background, '1' to provide a URL or '2' to upload a local image:");
  4092. if (choice === "0") {
  4093. localStorage.removeItem("lastBackgroundUrl");
  4094. localStorage.removeItem("lastBackgroundFile");
  4095. localStorage.removeItem("lastBackgroundType");
  4096. localStorage.removeItem("lastBackgroundValue");
  4097. backgroundElement.style.backgroundImage = `url(${background_image})`;
  4098. }
  4099. else if (choice === "1") {
  4100. const newBackgroundUrl = prompt("Enter the URL of the new background image:");
  4101. if (newBackgroundUrl) {
  4102. backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
  4103. this.kxsClient.saveBackgroundToLocalStorage(newBackgroundUrl);
  4104. alert("Background updated successfully!");
  4105. }
  4106. }
  4107. else if (choice === "2") {
  4108. const fileInput = document.createElement("input");
  4109. fileInput.type = "file";
  4110. fileInput.accept = "image/*";
  4111. fileInput.onchange = (event) => {
  4112. var _a, _b;
  4113. const file = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];
  4114. if (file) {
  4115. const reader = new FileReader();
  4116. reader.onload = () => {
  4117. backgroundElement.style.backgroundImage = `url(${reader.result})`;
  4118. this.kxsClient.saveBackgroundToLocalStorage(file);
  4119. alert("Background updated successfully!");
  4120. };
  4121. reader.readAsDataURL(file);
  4122. }
  4123. };
  4124. fileInput.click();
  4125. }
  4126. },
  4127. });
  4128. }
  4129. createOptionCard(option, container) {
  4130. const optionCard = document.createElement("div");
  4131. Object.assign(optionCard.style, {
  4132. background: "rgba(31, 41, 55, 0.8)",
  4133. borderRadius: "10px",
  4134. padding: "16px",
  4135. display: "flex",
  4136. flexDirection: "column",
  4137. alignItems: "center",
  4138. gap: "12px",
  4139. minHeight: "150px",
  4140. });
  4141. const iconContainer = document.createElement("div");
  4142. Object.assign(iconContainer.style, {
  4143. width: "48px",
  4144. height: "48px",
  4145. borderRadius: "50%",
  4146. display: "flex",
  4147. alignItems: "center",
  4148. justifyContent: "center",
  4149. marginBottom: "8px"
  4150. });
  4151. iconContainer.innerHTML = option.icon || '';
  4152. const title = document.createElement("div");
  4153. title.textContent = option.label;
  4154. title.style.fontSize = "16px";
  4155. title.style.textAlign = "center";
  4156. let control = null;
  4157. switch (option.type) {
  4158. case "input":
  4159. control = this.createInputElement(option);
  4160. break;
  4161. case "toggle":
  4162. control = this.createToggleButton(option);
  4163. break;
  4164. case "click":
  4165. control = this.createClickButton(option);
  4166. }
  4167. optionCard.appendChild(iconContainer);
  4168. optionCard.appendChild(title);
  4169. optionCard.appendChild(control);
  4170. container.appendChild(optionCard);
  4171. }
  4172. setActiveCategory(category) {
  4173. this.activeCategory = category;
  4174. this.filterOptions();
  4175. // Update button styles
  4176. this.menu.querySelectorAll('.category-btn').forEach(btn => {
  4177. const btnCategory = btn.dataset.category;
  4178. btn.style.background =
  4179. btnCategory === category ? '#3B82F6' : 'rgba(55, 65, 81, 0.8)';
  4180. });
  4181. }
  4182. filterOptions() {
  4183. const gridContainer = document.getElementById('kxsMenuGrid');
  4184. if (gridContainer) {
  4185. // Clear existing content
  4186. gridContainer.innerHTML = '';
  4187. // Get unique options based on category and search term
  4188. const displayedOptions = new Set();
  4189. this.sections.forEach(section => {
  4190. if (this.activeCategory === 'ALL' || section.category === this.activeCategory) {
  4191. section.options.forEach(option => {
  4192. // Create a unique key for each option
  4193. const optionKey = `${option.label}-${option.category}`;
  4194. // Check if option matches search term
  4195. const matchesSearch = this.searchTerm === '' ||
  4196. option.label.toLowerCase().includes(this.searchTerm) ||
  4197. option.category.toLowerCase().includes(this.searchTerm);
  4198. if (!displayedOptions.has(optionKey) && matchesSearch) {
  4199. displayedOptions.add(optionKey);
  4200. this.createOptionCard(option, gridContainer);
  4201. }
  4202. });
  4203. }
  4204. });
  4205. // Show a message if no options match the search
  4206. if (displayedOptions.size === 0 && this.searchTerm !== '') {
  4207. const noResultsMsg = document.createElement('div');
  4208. noResultsMsg.textContent = `No results found for "${this.searchTerm}"`;
  4209. noResultsMsg.style.gridColumn = '1 / -1';
  4210. noResultsMsg.style.textAlign = 'center';
  4211. noResultsMsg.style.padding = '20px';
  4212. noResultsMsg.style.color = '#9CA3AF';
  4213. gridContainer.appendChild(noResultsMsg);
  4214. }
  4215. }
  4216. }
  4217. createGridContainer() {
  4218. const gridContainer = document.createElement("div");
  4219. Object.assign(gridContainer.style, {
  4220. display: "grid",
  4221. gridTemplateColumns: "repeat(3, 1fr)",
  4222. gap: "16px",
  4223. padding: "16px",
  4224. gridAutoRows: "minmax(150px, auto)",
  4225. overflowY: "auto",
  4226. overflowX: "hidden", // Prevent horizontal scrolling
  4227. maxHeight: "calc(3 * 150px + 2 * 16px)",
  4228. width: "100%",
  4229. boxSizing: "border-box" // Include padding in width calculation
  4230. });
  4231. gridContainer.id = "kxsMenuGrid";
  4232. this.menu.appendChild(gridContainer);
  4233. }
  4234. addOption(section, option) {
  4235. section.options.push(option);
  4236. // Store all options for searching
  4237. this.allOptions.push(option);
  4238. }
  4239. addSection(title, category = "ALL") {
  4240. const section = {
  4241. title,
  4242. options: [],
  4243. category
  4244. };
  4245. const sectionElement = document.createElement("div");
  4246. sectionElement.className = "menu-section";
  4247. sectionElement.style.display = this.activeCategory === "ALL" || this.activeCategory === category ? "block" : "none";
  4248. section.element = sectionElement;
  4249. this.sections.push(section);
  4250. this.menu.appendChild(sectionElement);
  4251. return section;
  4252. }
  4253. createToggleButton(option) {
  4254. const btn = document.createElement("button");
  4255. Object.assign(btn.style, {
  4256. width: "100%",
  4257. padding: "8px",
  4258. background: option.value ? "#059669" : "#DC2626",
  4259. border: "none",
  4260. borderRadius: "6px",
  4261. color: "white",
  4262. cursor: "pointer",
  4263. transition: "background 0.2s",
  4264. fontSize: "14px",
  4265. fontWeight: "bold"
  4266. });
  4267. btn.textContent = option.value ? "ENABLED" : "DISABLED";
  4268. btn.addEventListener("click", () => {
  4269. var _a;
  4270. const newValue = !option.value;
  4271. option.value = newValue;
  4272. btn.textContent = newValue ? "ENABLED" : "DISABLED";
  4273. btn.style.background = newValue ? "#059669" : "#DC2626";
  4274. (_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, newValue);
  4275. });
  4276. return btn;
  4277. }
  4278. createClickButton(option) {
  4279. const btn = document.createElement("button");
  4280. Object.assign(btn.style, {
  4281. width: "100%",
  4282. padding: "8px",
  4283. background: "#3B82F6",
  4284. border: "none",
  4285. borderRadius: "6px",
  4286. color: "white",
  4287. cursor: "pointer",
  4288. transition: "background 0.2s",
  4289. fontSize: "14px",
  4290. fontWeight: "bold"
  4291. });
  4292. btn.textContent = option.label;
  4293. btn.addEventListener("click", () => {
  4294. var _a;
  4295. (_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, true);
  4296. });
  4297. return btn;
  4298. }
  4299. addShiftListener() {
  4300. window.addEventListener("keydown", (event) => {
  4301. if (event.key === "Shift" && event.location == 2) {
  4302. this.clearMenu();
  4303. this.toggleMenuVisibility();
  4304. this.loadOption();
  4305. // Ensure options are displayed after loading
  4306. this.filterOptions();
  4307. }
  4308. });
  4309. }
  4310. createInputElement(option) {
  4311. const input = document.createElement("input");
  4312. input.type = "text";
  4313. input.value = String(option.value);
  4314. Object.assign(input.style, {
  4315. width: "100%",
  4316. padding: "8px",
  4317. background: "rgba(55, 65, 81, 0.8)",
  4318. border: "none",
  4319. borderRadius: "6px",
  4320. color: "#FFAE00",
  4321. fontSize: "14px"
  4322. });
  4323. input.addEventListener("change", () => {
  4324. var _a;
  4325. option.value = input.value;
  4326. (_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, input.value);
  4327. });
  4328. return input;
  4329. }
  4330. addDragListeners() {
  4331. this.menu.addEventListener('mousedown', (e) => {
  4332. if (e.target instanceof HTMLElement &&
  4333. !e.target.matches("input, select, button, svg, path")) {
  4334. this.isDragging = true;
  4335. const rect = this.menu.getBoundingClientRect();
  4336. this.dragOffset = {
  4337. x: e.clientX - rect.left,
  4338. y: e.clientY - rect.top
  4339. };
  4340. this.menu.style.cursor = "grabbing";
  4341. }
  4342. });
  4343. document.addEventListener('mousemove', (e) => {
  4344. if (this.isDragging) {
  4345. const x = e.clientX - this.dragOffset.x;
  4346. const y = e.clientY - this.dragOffset.y;
  4347. this.menu.style.transform = 'none';
  4348. this.menu.style.left = `${x}px`;
  4349. this.menu.style.top = `${y}px`;
  4350. }
  4351. });
  4352. document.addEventListener('mouseup', () => {
  4353. this.isDragging = false;
  4354. this.menu.style.cursor = "grab";
  4355. });
  4356. }
  4357. toggleMenuVisibility() {
  4358. this.isClientMenuVisible = !this.isClientMenuVisible;
  4359. this.kxsClient.nm.showNotification(this.isClientMenuVisible ? "Opening menu..." : "Closing menu...", "info", 1400);
  4360. this.menu.style.display = this.isClientMenuVisible ? "block" : "none";
  4361. // If opening the menu, make sure to display options
  4362. if (this.isClientMenuVisible) {
  4363. this.filterOptions();
  4364. }
  4365. }
  4366. destroy() {
  4367. // Remove global event listeners
  4368. window.removeEventListener("keydown", this.shiftListener);
  4369. document.removeEventListener('mousemove', this.mouseMoveListener);
  4370. document.removeEventListener('mouseup', this.mouseUpListener);
  4371. // Remove all event listeners from menu elements
  4372. const removeAllListeners = (element) => {
  4373. var _a;
  4374. const clone = element.cloneNode(true);
  4375. (_a = element.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(clone, element);
  4376. };
  4377. // Clean up all buttons and inputs in the menu
  4378. this.menu.querySelectorAll('button, input').forEach(element => {
  4379. removeAllListeners(element);
  4380. });
  4381. // Remove the menu from DOM
  4382. this.menu.remove();
  4383. // Clear all sections
  4384. this.sections.forEach(section => {
  4385. if (section.element) {
  4386. removeAllListeners(section.element);
  4387. section.element.remove();
  4388. delete section.element;
  4389. }
  4390. section.options = [];
  4391. });
  4392. this.sections = [];
  4393. // Reset all class properties
  4394. this.isClientMenuVisible = false;
  4395. this.isDragging = false;
  4396. this.dragOffset = { x: 0, y: 0 };
  4397. this.activeCategory = "ALL";
  4398. // Clear references
  4399. this.menu = null;
  4400. this.kxsClient = null;
  4401. }
  4402. getMenuVisibility() {
  4403. return this.isClientMenuVisible;
  4404. }
  4405. }
  4406.  
  4407.  
  4408. ;// ./src/KxsClient.ts
  4409. var KxsClient_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
  4410. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4411. return new (P || (P = Promise))(function (resolve, reject) {
  4412. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  4413. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  4414. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  4415. step((generator = generator.apply(thisArg, _arguments || [])).next());
  4416. });
  4417. };
  4418.  
  4419.  
  4420.  
  4421.  
  4422.  
  4423.  
  4424.  
  4425.  
  4426.  
  4427.  
  4428. class KxsClient {
  4429. constructor() {
  4430. this.deathObserver = null;
  4431. this.adBlockObserver = null;
  4432. this.config = __webpack_require__(891);
  4433. this.menu = document.createElement("div");
  4434. this.lastFrameTime = performance.now();
  4435. this.isFpsUncapped = false;
  4436. this.isFpsVisible = true;
  4437. this.isPingVisible = true;
  4438. this.isKillsVisible = true;
  4439. this.isDeathSoundEnabled = true;
  4440. this.isWinSoundEnabled = true;
  4441. this.isHealthWarningEnabled = true;
  4442. this.isAutoUpdateEnabled = true;
  4443. this.isWinningAnimationEnabled = true;
  4444. this.isKillLeaderTrackerEnabled = true;
  4445. this.isLegaySecondaryMenu = false;
  4446. this.isKillFeedBlint = false;
  4447. this.isSpotifyPlayerEnabled = false;
  4448. this.discordToken = null;
  4449. this.counters = {};
  4450. this.all_friends = '';
  4451. this.isMainMenuCleaned = false;
  4452. this.defaultPositions = {
  4453. fps: { left: 20, top: 160 },
  4454. ping: { left: 20, top: 220 },
  4455. kills: { left: 20, top: 280 },
  4456. };
  4457. this.defaultSizes = {
  4458. fps: { width: 100, height: 30 },
  4459. ping: { width: 100, height: 30 },
  4460. kills: { width: 100, height: 30 },
  4461. };
  4462. // Before all, load local storage
  4463. this.loadLocalStorage();
  4464. this.changeSurvevLogo();
  4465. this.nm = NotificationManager.getInstance();
  4466. this.discordRPC = new DiscordWebSocket(this, this.parseToken(this.discordToken));
  4467. this.updater = new UpdateChecker(this);
  4468. this.kill_leader = new KillLeaderTracker(this);
  4469. this.healWarning = new HealthWarning(this);
  4470. this.setAnimationFrameCallback();
  4471. this.loadBackgroundFromLocalStorage();
  4472. this.initDeathDetection();
  4473. this.discordRPC.connect();
  4474. if (this.isLegaySecondaryMenu) {
  4475. this.secondaryMenu = new KxsLegacyClientSecondaryMenu(this);
  4476. }
  4477. else {
  4478. this.secondaryMenu = new KxsClientSecondaryMenu(this);
  4479. }
  4480. this.discordTracker = new DiscordTracking(this, this.discordWebhookUrl);
  4481. if (this.isSpotifyPlayerEnabled) {
  4482. this.createSimpleSpotifyPlayer();
  4483. }
  4484. this.MainMenuCleaning();
  4485. }
  4486. parseToken(token) {
  4487. if (token) {
  4488. return token.replace(/^(["'`])(.+)\1$/, '$2');
  4489. }
  4490. return null;
  4491. }
  4492. getPlayerName() {
  4493. let config = localStorage.getItem("surviv_config");
  4494. if (config) {
  4495. let configObject = JSON.parse(config);
  4496. return configObject.playerName;
  4497. }
  4498. }
  4499. changeSurvevLogo() {
  4500. var startRowHeader = document.querySelector("#start-row-header");
  4501. if (startRowHeader) {
  4502. startRowHeader.style.backgroundImage =
  4503. `url("${this.config.base_url}/assets/KysClient.gif")`;
  4504. }
  4505. }
  4506. updateLocalStorage() {
  4507. localStorage.setItem("userSettings", JSON.stringify({
  4508. isFpsVisible: this.isFpsVisible,
  4509. isPingVisible: this.isPingVisible,
  4510. isFpsUncapped: this.isFpsUncapped,
  4511. isKillsVisible: this.isKillsVisible,
  4512. discordWebhookUrl: this.discordWebhookUrl,
  4513. isDeathSoundEnabled: this.isDeathSoundEnabled,
  4514. isWinSoundEnabled: this.isWinSoundEnabled,
  4515. isHealthWarningEnabled: this.isHealthWarningEnabled,
  4516. isAutoUpdateEnabled: this.isAutoUpdateEnabled,
  4517. isWinningAnimationEnabled: this.isWinningAnimationEnabled,
  4518. discordToken: this.discordToken,
  4519. isKillLeaderTrackerEnabled: this.isKillLeaderTrackerEnabled,
  4520. isLegaySecondaryMenu: this.isLegaySecondaryMenu,
  4521. isKillFeedBlint: this.isKillFeedBlint,
  4522. all_friends: this.all_friends,
  4523. isSpotifyPlayerEnabled: this.isSpotifyPlayerEnabled,
  4524. isMainMenuCleaned: this.isMainMenuCleaned
  4525. }));
  4526. }
  4527. ;
  4528. initDeathDetection() {
  4529. const config = {
  4530. childList: true,
  4531. subtree: true,
  4532. attributes: false,
  4533. characterData: false,
  4534. };
  4535. this.deathObserver = new MutationObserver((mutations) => {
  4536. for (const mutation of mutations) {
  4537. if (mutation.addedNodes.length) {
  4538. this.checkForDeathScreen(mutation.addedNodes);
  4539. }
  4540. }
  4541. });
  4542. this.deathObserver.observe(document.body, config);
  4543. }
  4544. checkForDeathScreen(nodes) {
  4545. let loseArray = [
  4546. "died",
  4547. "eliminated",
  4548. "was"
  4549. ];
  4550. let winArray = [
  4551. "Winner",
  4552. "Victory",
  4553. "dinner",
  4554. ];
  4555. nodes.forEach((node) => {
  4556. if (node instanceof HTMLElement) {
  4557. const deathTitle = node.querySelector(".ui-stats-header-title");
  4558. if (loseArray.some((word) => { var _a; return (_a = deathTitle === null || deathTitle === void 0 ? void 0 : deathTitle.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(word); })) {
  4559. this.handlePlayerDeath();
  4560. }
  4561. else if (winArray.some((word) => { var _a; return (_a = deathTitle === null || deathTitle === void 0 ? void 0 : deathTitle.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(word); })) {
  4562. this.handlePlayerWin();
  4563. }
  4564. }
  4565. });
  4566. }
  4567. handlePlayerDeath() {
  4568. return KxsClient_awaiter(this, void 0, void 0, function* () {
  4569. try {
  4570. if (this.isDeathSoundEnabled) {
  4571. const audio = new Audio(this.config.base_url + "/assets/dead.m4a");
  4572. audio.volume = 0.3;
  4573. audio.play().catch((err) => false);
  4574. }
  4575. }
  4576. catch (error) {
  4577. console.error("Reading error:", error);
  4578. }
  4579. const stats = this.getPlayerStats(false);
  4580. yield this.discordTracker.trackGameEnd({
  4581. username: stats.username,
  4582. kills: stats.kills,
  4583. damageDealt: stats.damageDealt,
  4584. damageTaken: stats.damageTaken,
  4585. duration: stats.duration,
  4586. position: stats.position,
  4587. isWin: false,
  4588. });
  4589. });
  4590. }
  4591. handlePlayerWin() {
  4592. return KxsClient_awaiter(this, void 0, void 0, function* () {
  4593. var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
  4594. if (this.isWinningAnimationEnabled) {
  4595. this.felicitation();
  4596. }
  4597. const stats = this.getPlayerStats(true);
  4598. yield this.discordTracker.trackGameEnd({
  4599. username: stats.username,
  4600. kills: stats.kills,
  4601. damageDealt: stats.damageDealt,
  4602. damageTaken: stats.damageTaken,
  4603. duration: stats.duration,
  4604. position: stats.position,
  4605. isWin: true,
  4606. stuff: {
  4607. main_weapon: (_a = document.querySelector('#ui-weapon-id-1 .ui-weapon-name')) === null || _a === void 0 ? void 0 : _a.textContent,
  4608. secondary_weapon: (_b = document.querySelector('#ui-weapon-id-2 .ui-weapon-name')) === null || _b === void 0 ? void 0 : _b.textContent,
  4609. soda: (_c = document.querySelector("#ui-loot-soda .ui-loot-count")) === null || _c === void 0 ? void 0 : _c.textContent,
  4610. melees: (_d = document.querySelector('#ui-weapon-id-3 .ui-weapon-name')) === null || _d === void 0 ? void 0 : _d.textContent,
  4611. grenades: (_e = document.querySelector(`#ui-weapon-id-4 .ui-weapon-name`)) === null || _e === void 0 ? void 0 : _e.textContent,
  4612. medkit: (_f = document.querySelector("#ui-loot-healthkit .ui-loot-count")) === null || _f === void 0 ? void 0 : _f.textContent,
  4613. bandage: (_g = document.querySelector("#ui-loot-bandage .ui-loot-count")) === null || _g === void 0 ? void 0 : _g.textContent,
  4614. pills: (_h = document.querySelector("#ui-loot-painkiller .ui-loot-count")) === null || _h === void 0 ? void 0 : _h.textContent,
  4615. backpack: (_j = document.querySelector("#ui-armor-backpack .ui-armor-level")) === null || _j === void 0 ? void 0 : _j.textContent,
  4616. chest: (_k = document.querySelector("#ui-armor-chest .ui-armor-level")) === null || _k === void 0 ? void 0 : _k.textContent,
  4617. helmet: (_l = document.querySelector("#ui-armor-helmet .ui-armor-level")) === null || _l === void 0 ? void 0 : _l.textContent,
  4618. }
  4619. });
  4620. });
  4621. }
  4622. felicitation() {
  4623. const goldText = document.createElement("div");
  4624. goldText.textContent = "#1";
  4625. goldText.style.position = "fixed";
  4626. goldText.style.top = "50%";
  4627. goldText.style.left = "50%";
  4628. goldText.style.transform = "translate(-50%, -50%)";
  4629. goldText.style.fontSize = "80px";
  4630. goldText.style.color = "gold";
  4631. goldText.style.textShadow = "2px 2px 4px rgba(0,0,0,0.3)";
  4632. goldText.style.zIndex = "10000";
  4633. document.body.appendChild(goldText);
  4634. function createConfetti() {
  4635. const colors = [
  4636. "#ff0000",
  4637. "#00ff00",
  4638. "#0000ff",
  4639. "#ffff00",
  4640. "#ff00ff",
  4641. "#00ffff",
  4642. "gold",
  4643. ];
  4644. const confetti = document.createElement("div");
  4645. confetti.style.position = "fixed";
  4646. confetti.style.width = Math.random() * 10 + 5 + "px";
  4647. confetti.style.height = Math.random() * 10 + 5 + "px";
  4648. confetti.style.backgroundColor =
  4649. colors[Math.floor(Math.random() * colors.length)];
  4650. confetti.style.borderRadius = "50%";
  4651. confetti.style.zIndex = "9999";
  4652. confetti.style.left = Math.random() * 100 + "vw";
  4653. confetti.style.top = "-20px";
  4654. document.body.appendChild(confetti);
  4655. let posY = -20;
  4656. let posX = parseFloat(confetti.style.left);
  4657. let rotation = 0;
  4658. let speedY = Math.random() * 2 + 1;
  4659. let speedX = Math.random() * 2 - 1;
  4660. function fall() {
  4661. posY += speedY;
  4662. posX += speedX;
  4663. rotation += 5;
  4664. confetti.style.top = posY + "px";
  4665. confetti.style.left = posX + "vw";
  4666. confetti.style.transform = `rotate(${rotation}deg)`;
  4667. if (posY < window.innerHeight) {
  4668. requestAnimationFrame(fall);
  4669. }
  4670. else {
  4671. confetti.remove();
  4672. }
  4673. }
  4674. fall();
  4675. }
  4676. const confettiInterval = setInterval(() => {
  4677. for (let i = 0; i < 5; i++) {
  4678. createConfetti();
  4679. }
  4680. }, 100);
  4681. if (this.isWinSoundEnabled) {
  4682. const audio = new Audio(this.config.base_url + "/assets/win.m4a");
  4683. audio.play().catch((err) => console.error("Erreur lecture:", err));
  4684. }
  4685. setTimeout(() => {
  4686. clearInterval(confettiInterval);
  4687. goldText.style.transition = "opacity 1s";
  4688. goldText.style.opacity = "0";
  4689. setTimeout(() => goldText.remove(), 1000);
  4690. }, 5000);
  4691. }
  4692. cleanup() {
  4693. if (this.deathObserver) {
  4694. this.deathObserver.disconnect();
  4695. this.deathObserver = null;
  4696. }
  4697. }
  4698. getUsername() {
  4699. const configKey = "surviv_config";
  4700. const savedConfig = localStorage.getItem(configKey);
  4701. const config = JSON.parse(savedConfig);
  4702. if (config.playerName) {
  4703. return config.playerName;
  4704. }
  4705. else {
  4706. return "Player";
  4707. }
  4708. }
  4709. getPlayerStats(win) {
  4710. const statsInfo = win
  4711. ? document.querySelector(".ui-stats-info-player")
  4712. : document.querySelector(".ui-stats-info-player.ui-stats-info-status");
  4713. const rank = document.querySelector(".ui-stats-header-value");
  4714. if (!(statsInfo === null || statsInfo === void 0 ? void 0 : statsInfo.textContent) || !(rank === null || rank === void 0 ? void 0 : rank.textContent)) {
  4715. return {
  4716. username: this.getUsername(),
  4717. kills: 0,
  4718. damageDealt: 0,
  4719. damageTaken: 0,
  4720. duration: "0s",
  4721. position: "#unknown",
  4722. };
  4723. }
  4724. const parsedStats = StatsParser.parse(statsInfo.textContent, rank === null || rank === void 0 ? void 0 : rank.textContent);
  4725. parsedStats.username = this.getUsername();
  4726. return parsedStats;
  4727. }
  4728. setAnimationFrameCallback() {
  4729. this.animationFrameCallback = this.isFpsUncapped
  4730. ? (callback) => setTimeout(callback, 1)
  4731. : window.requestAnimationFrame.bind(window);
  4732. }
  4733. makeResizable(element, storageKey) {
  4734. let isResizing = false;
  4735. let startX, startY, startWidth, startHeight;
  4736. // Add a resize area in the bottom right
  4737. const resizer = document.createElement("div");
  4738. Object.assign(resizer.style, {
  4739. width: "10px",
  4740. height: "10px",
  4741. backgroundColor: "white",
  4742. position: "absolute",
  4743. right: "0",
  4744. bottom: "0",
  4745. cursor: "nwse-resize",
  4746. zIndex: "10001",
  4747. });
  4748. element.appendChild(resizer);
  4749. resizer.addEventListener("mousedown", (event) => {
  4750. isResizing = true;
  4751. startX = event.clientX;
  4752. startY = event.clientY;
  4753. startWidth = element.offsetWidth;
  4754. startHeight = element.offsetHeight;
  4755. event.stopPropagation(); // Empêche l'activation du déplacement
  4756. });
  4757. window.addEventListener("mousemove", (event) => {
  4758. if (isResizing) {
  4759. const newWidth = startWidth + (event.clientX - startX);
  4760. const newHeight = startHeight + (event.clientY - startY);
  4761. element.style.width = `${newWidth}px`;
  4762. element.style.height = `${newHeight}px`;
  4763. // Sauvegarde de la taille
  4764. localStorage.setItem(storageKey, JSON.stringify({
  4765. width: newWidth,
  4766. height: newHeight,
  4767. }));
  4768. }
  4769. });
  4770. window.addEventListener("mouseup", () => {
  4771. isResizing = false;
  4772. });
  4773. const savedSize = localStorage.getItem(storageKey);
  4774. if (savedSize) {
  4775. const { width, height } = JSON.parse(savedSize);
  4776. element.style.width = `${width}px`;
  4777. element.style.height = `${height}px`;
  4778. }
  4779. else {
  4780. element.style.width = "150px"; // Taille par défaut
  4781. element.style.height = "50px";
  4782. }
  4783. }
  4784. makeDraggable(element, storageKey) {
  4785. const gridSystem = new GridSystem();
  4786. let isDragging = false;
  4787. let dragOffset = { x: 0, y: 0 };
  4788. element.addEventListener("mousedown", (event) => {
  4789. if (event.button === 0) {
  4790. // Left click only
  4791. isDragging = true;
  4792. gridSystem.toggleGrid(); // Afficher la grille quand on commence à déplacer
  4793. dragOffset = {
  4794. x: event.clientX - element.offsetLeft,
  4795. y: event.clientY - element.offsetTop,
  4796. };
  4797. element.style.cursor = "grabbing";
  4798. }
  4799. });
  4800. window.addEventListener("mousemove", (event) => {
  4801. if (isDragging) {
  4802. const rawX = event.clientX - dragOffset.x;
  4803. const rawY = event.clientY - dragOffset.y;
  4804. // Get snapped coordinates from grid system
  4805. const snapped = gridSystem.snapToGrid(element, rawX, rawY);
  4806. // Prevent moving off screen
  4807. const maxX = window.innerWidth - element.offsetWidth;
  4808. const maxY = window.innerHeight - element.offsetHeight;
  4809. element.style.left = `${Math.max(0, Math.min(snapped.x, maxX))}px`;
  4810. element.style.top = `${Math.max(0, Math.min(snapped.y, maxY))}px`;
  4811. // Highlight nearest grid lines while dragging
  4812. gridSystem.highlightNearestGridLine(rawX, rawY);
  4813. // Save position
  4814. localStorage.setItem(storageKey, JSON.stringify({
  4815. x: parseInt(element.style.left),
  4816. y: parseInt(element.style.top),
  4817. }));
  4818. }
  4819. });
  4820. window.addEventListener("mouseup", () => {
  4821. if (isDragging) {
  4822. isDragging = false;
  4823. gridSystem.toggleGrid(); // Masquer la grille quand on arrête de déplacer
  4824. element.style.cursor = "move";
  4825. }
  4826. });
  4827. // Load saved position
  4828. const savedPosition = localStorage.getItem(storageKey);
  4829. if (savedPosition) {
  4830. const { x, y } = JSON.parse(savedPosition);
  4831. const snapped = gridSystem.snapToGrid(element, x, y);
  4832. element.style.left = `${snapped.x}px`;
  4833. element.style.top = `${snapped.y}px`;
  4834. }
  4835. }
  4836. getKills() {
  4837. const killElement = document.querySelector(".ui-player-kills.js-ui-player-kills");
  4838. if (killElement) {
  4839. const kills = parseInt(killElement.textContent || "", 10);
  4840. return isNaN(kills) ? 0 : kills;
  4841. }
  4842. return 0;
  4843. }
  4844. getRegionFromLocalStorage() {
  4845. let config = localStorage.getItem("surviv_config");
  4846. if (config) {
  4847. let configObject = JSON.parse(config);
  4848. return configObject.region;
  4849. }
  4850. return null;
  4851. }
  4852. saveFpsUncappedToLocalStorage() {
  4853. let config = JSON.parse(localStorage.getItem("userSettings")) || {};
  4854. config.isFpsUncapped = this.isFpsUncapped;
  4855. localStorage.setItem("userSettings", JSON.stringify(config));
  4856. }
  4857. saveBackgroundToLocalStorage(image) {
  4858. if (typeof image === "string") {
  4859. localStorage.setItem("lastBackgroundUrl", image);
  4860. }
  4861. if (typeof image === "string") {
  4862. localStorage.setItem("lastBackgroundType", "url");
  4863. localStorage.setItem("lastBackgroundValue", image);
  4864. }
  4865. else {
  4866. localStorage.setItem("lastBackgroundType", "local");
  4867. const reader = new FileReader();
  4868. reader.onload = () => {
  4869. localStorage.setItem("lastBackgroundValue", reader.result);
  4870. };
  4871. reader.readAsDataURL(image);
  4872. }
  4873. }
  4874. loadBackgroundFromLocalStorage() {
  4875. const backgroundType = localStorage.getItem("lastBackgroundType");
  4876. const backgroundValue = localStorage.getItem("lastBackgroundValue");
  4877. const backgroundElement = document.getElementById("background");
  4878. if (backgroundElement && backgroundType && backgroundValue) {
  4879. if (backgroundType === "url") {
  4880. backgroundElement.style.backgroundImage = `url(${backgroundValue})`;
  4881. }
  4882. else if (backgroundType === "local") {
  4883. backgroundElement.style.backgroundImage = `url(${backgroundValue})`;
  4884. }
  4885. }
  4886. }
  4887. loadLocalStorage() {
  4888. var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
  4889. const savedSettings = localStorage.getItem("userSettings")
  4890. ? JSON.parse(localStorage.getItem("userSettings"))
  4891. : null;
  4892. if (savedSettings) {
  4893. this.isFpsVisible = (_a = savedSettings.isFpsVisible) !== null && _a !== void 0 ? _a : this.isFpsVisible;
  4894. this.isPingVisible = (_b = savedSettings.isPingVisible) !== null && _b !== void 0 ? _b : this.isPingVisible;
  4895. this.isFpsUncapped = (_c = savedSettings.isFpsUncapped) !== null && _c !== void 0 ? _c : this.isFpsUncapped;
  4896. this.isKillsVisible = (_d = savedSettings.isKillsVisible) !== null && _d !== void 0 ? _d : this.isKillsVisible;
  4897. this.discordWebhookUrl = (_e = savedSettings.discordWebhookUrl) !== null && _e !== void 0 ? _e : this.discordWebhookUrl;
  4898. this.isHealthWarningEnabled = (_f = savedSettings.isHealthWarningEnabled) !== null && _f !== void 0 ? _f : this.isHealthWarningEnabled;
  4899. this.isAutoUpdateEnabled = (_g = savedSettings.isAutoUpdateEnabled) !== null && _g !== void 0 ? _g : this.isAutoUpdateEnabled;
  4900. this.isWinningAnimationEnabled = (_h = savedSettings.isWinningAnimationEnabled) !== null && _h !== void 0 ? _h : this.isWinningAnimationEnabled;
  4901. this.discordToken = (_j = savedSettings.discordToken) !== null && _j !== void 0 ? _j : this.discordToken;
  4902. this.isKillLeaderTrackerEnabled = (_k = savedSettings.isKillLeaderTrackerEnabled) !== null && _k !== void 0 ? _k : this.isKillLeaderTrackerEnabled;
  4903. this.isLegaySecondaryMenu = (_l = savedSettings.isLegaySecondaryMenu) !== null && _l !== void 0 ? _l : this.isLegaySecondaryMenu;
  4904. this.isKillFeedBlint = (_m = savedSettings.isKillFeedBlint) !== null && _m !== void 0 ? _m : this.isKillFeedBlint;
  4905. this.all_friends = (_o = savedSettings.all_friends) !== null && _o !== void 0 ? _o : this.all_friends;
  4906. this.isSpotifyPlayerEnabled = (_p = savedSettings.isSpotifyPlayerEnabled) !== null && _p !== void 0 ? _p : this.isSpotifyPlayerEnabled;
  4907. this.isMainMenuCleaned = (_q = savedSettings.isMainMenuCleaned) !== null && _q !== void 0 ? _q : this.isMainMenuCleaned;
  4908. }
  4909. this.updateKillsVisibility();
  4910. this.updateFpsVisibility();
  4911. this.updatePingVisibility();
  4912. }
  4913. updateFpsVisibility() {
  4914. if (this.counters.fps) {
  4915. this.counters.fps.style.display = this.isFpsVisible ? "block" : "none";
  4916. this.counters.fps.style.backgroundColor = this.isFpsVisible
  4917. ? "rgba(0, 0, 0, 0.2)"
  4918. : "transparent";
  4919. }
  4920. }
  4921. updatePingVisibility() {
  4922. if (this.counters.ping) {
  4923. this.counters.ping.style.display = this.isPingVisible ? "block" : "none";
  4924. }
  4925. }
  4926. updateKillsVisibility() {
  4927. if (this.counters.kills) {
  4928. this.counters.kills.style.display = this.isKillsVisible
  4929. ? "block"
  4930. : "none";
  4931. this.counters.kills.style.backgroundColor = this.isKillsVisible
  4932. ? "rgba(0, 0, 0, 0.2)"
  4933. : "transparent";
  4934. }
  4935. }
  4936. toggleFpsUncap() {
  4937. this.isFpsUncapped = !this.isFpsUncapped;
  4938. this.setAnimationFrameCallback();
  4939. this.saveFpsUncappedToLocalStorage();
  4940. }
  4941. createSimpleSpotifyPlayer() {
  4942. // Main container
  4943. const container = document.createElement('div');
  4944. container.id = 'spotify-player-container';
  4945. Object.assign(container.style, {
  4946. position: 'fixed',
  4947. bottom: '20px',
  4948. right: '20px',
  4949. width: '320px',
  4950. backgroundColor: '#121212',
  4951. borderRadius: '12px',
  4952. boxShadow: '0 8px 24px rgba(0, 0, 0, 0.5)',
  4953. overflow: 'hidden',
  4954. zIndex: '10000',
  4955. fontFamily: 'Montserrat, Arial, sans-serif',
  4956. transition: 'transform 0.3s ease, opacity 0.3s ease',
  4957. transform: 'translateY(0)',
  4958. opacity: '1'
  4959. });
  4960. // Player header
  4961. const header = document.createElement('div');
  4962. Object.assign(header.style, {
  4963. display: 'flex',
  4964. alignItems: 'center',
  4965. justifyContent: 'space-between',
  4966. padding: '12px 16px',
  4967. backgroundColor: '#070707',
  4968. color: 'white',
  4969. borderBottom: '1px solid #282828',
  4970. position: 'relative' // For absolute positioning of the button
  4971. });
  4972. // Spotify logo
  4973. const logo = document.createElement('div');
  4974. logo.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path fill="#1DB954" d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>`;
  4975. const title = document.createElement('span');
  4976. title.textContent = 'Spotify Player';
  4977. title.style.marginLeft = '8px';
  4978. title.style.fontWeight = 'bold';
  4979. const logoContainer = document.createElement('div');
  4980. logoContainer.style.display = 'flex';
  4981. logoContainer.style.alignItems = 'center';
  4982. logoContainer.appendChild(logo);
  4983. logoContainer.appendChild(title);
  4984. // Control buttons
  4985. const controls = document.createElement('div');
  4986. controls.style.display = 'flex';
  4987. controls.style.alignItems = 'center';
  4988. // Minimize button
  4989. const minimizeBtn = document.createElement('button');
  4990. Object.assign(minimizeBtn.style, {
  4991. background: 'none',
  4992. border: 'none',
  4993. color: '#aaa',
  4994. cursor: 'pointer',
  4995. fontSize: '18px',
  4996. padding: '0',
  4997. marginLeft: '10px',
  4998. width: '24px',
  4999. height: '24px',
  5000. display: 'flex',
  5001. alignItems: 'center',
  5002. justifyContent: 'center'
  5003. });
  5004. minimizeBtn.innerHTML = '−';
  5005. minimizeBtn.title = 'Minimize';
  5006. // Close button
  5007. const closeBtn = document.createElement('button');
  5008. Object.assign(closeBtn.style, {
  5009. background: 'none',
  5010. border: 'none',
  5011. color: '#aaa',
  5012. cursor: 'pointer',
  5013. fontSize: '18px',
  5014. padding: '0',
  5015. marginLeft: '10px',
  5016. width: '24px',
  5017. height: '24px',
  5018. display: 'flex',
  5019. alignItems: 'center',
  5020. justifyContent: 'center'
  5021. });
  5022. closeBtn.innerHTML = '×';
  5023. closeBtn.title = 'Close';
  5024. controls.appendChild(minimizeBtn);
  5025. controls.appendChild(closeBtn);
  5026. header.appendChild(logoContainer);
  5027. header.appendChild(controls);
  5028. // Album cover image
  5029. const albumArt = document.createElement('div');
  5030. Object.assign(albumArt.style, {
  5031. width: '50px',
  5032. height: '50px',
  5033. backgroundColor: '#333',
  5034. backgroundSize: 'cover',
  5035. backgroundPosition: 'center',
  5036. borderRadius: '4px',
  5037. flexShrink: '0'
  5038. });
  5039. albumArt.style.backgroundImage = `url('https://i.scdn.co/image/ab67616d00001e02fe24b9ffeb3c3fdb4f9abbe9')`;
  5040. // Track information
  5041. const trackInfo = document.createElement('div');
  5042. Object.assign(trackInfo.style, {
  5043. flex: '1',
  5044. overflow: 'hidden'
  5045. });
  5046. // Player content
  5047. const content = document.createElement('div');
  5048. content.style.padding = '0';
  5049. // Spotify iframe
  5050. const iframe = document.createElement('iframe');
  5051. iframe.id = 'spotify-player-iframe';
  5052. iframe.src = 'https://open.spotify.com/embed/playlist/37i9dQZEVXcJZyENOWUFo7';
  5053. iframe.width = '100%';
  5054. iframe.height = '80px';
  5055. iframe.frameBorder = '0';
  5056. iframe.allow = 'encrypted-media';
  5057. iframe.style.border = 'none';
  5058. content.appendChild(iframe);
  5059. // Playlist change button integrated in the header
  5060. const changePlaylistContainer = document.createElement('div');
  5061. Object.assign(changePlaylistContainer.style, {
  5062. display: 'flex',
  5063. alignItems: 'center',
  5064. marginRight: '10px'
  5065. });
  5066. // Square button to enter a playlist ID
  5067. const changePlaylistBtn = document.createElement('button');
  5068. Object.assign(changePlaylistBtn.style, {
  5069. width: '24px',
  5070. height: '24px',
  5071. backgroundColor: '#1DB954',
  5072. color: 'white',
  5073. border: 'none',
  5074. borderRadius: '4px',
  5075. fontSize: '14px',
  5076. fontWeight: 'bold',
  5077. cursor: 'pointer',
  5078. display: 'flex',
  5079. alignItems: 'center',
  5080. justifyContent: 'center',
  5081. margin: '0 8px 0 0'
  5082. });
  5083. changePlaylistBtn.innerHTML = `
  5084. <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  5085. <path d="M12 5V19M5 12H19" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  5086. </svg>
  5087. `;
  5088. changePlaylistBtn.addEventListener('click', () => {
  5089. const id = prompt('Enter the Spotify playlist ID:', '37i9dQZEVXcJZyENOWUFo7');
  5090. if (id) {
  5091. iframe.src = `https://open.spotify.com/embed/playlist/${id}`;
  5092. localStorage.setItem('kxsSpotifyPlaylist', id);
  5093. // Simulate an album cover based on the playlist ID
  5094. albumArt.style.backgroundImage = `url('https://i.scdn.co/image/ab67706f00000002${id.substring(0, 16)}')`;
  5095. }
  5096. });
  5097. changePlaylistContainer.appendChild(changePlaylistBtn);
  5098. // Load saved playlist
  5099. const savedPlaylist = localStorage.getItem('kxsSpotifyPlaylist');
  5100. if (savedPlaylist) {
  5101. iframe.src = `https://open.spotify.com/embed/playlist/${savedPlaylist}`;
  5102. // Simulate an album cover based on the playlist ID
  5103. albumArt.style.backgroundImage = `url('https://i.scdn.co/image/ab67706f00000002${savedPlaylist.substring(0, 16)}')`;
  5104. }
  5105. // Integrate the playlist change button into the controls
  5106. controls.insertBefore(changePlaylistContainer, minimizeBtn);
  5107. // Assemble the elements
  5108. container.appendChild(header);
  5109. container.appendChild(content);
  5110. // Add a title to the button for accessibility
  5111. changePlaylistBtn.title = "Change playlist";
  5112. // Add to document
  5113. document.body.appendChild(container);
  5114. // Player states
  5115. let isMinimized = false;
  5116. // Events
  5117. minimizeBtn.addEventListener('click', () => {
  5118. if (isMinimized) {
  5119. content.style.display = 'block';
  5120. changePlaylistContainer.style.display = 'block';
  5121. container.style.transform = 'translateY(0)';
  5122. minimizeBtn.innerHTML = '−';
  5123. }
  5124. else {
  5125. content.style.display = 'none';
  5126. changePlaylistContainer.style.display = 'none';
  5127. container.style.transform = 'translateY(0)';
  5128. minimizeBtn.innerHTML = '+';
  5129. }
  5130. isMinimized = !isMinimized;
  5131. });
  5132. closeBtn.addEventListener('click', () => {
  5133. container.style.transform = 'translateY(150%)';
  5134. container.style.opacity = '0';
  5135. setTimeout(() => {
  5136. container.style.display = 'none';
  5137. showButton.style.display = 'flex';
  5138. showButton.style.alignItems = 'center';
  5139. showButton.style.justifyContent = 'center';
  5140. }, 300);
  5141. });
  5142. // Make the player draggable
  5143. let isDragging = false;
  5144. let offsetX = 0;
  5145. let offsetY = 0;
  5146. header.addEventListener('mousedown', (e) => {
  5147. isDragging = true;
  5148. offsetX = e.clientX - container.getBoundingClientRect().left;
  5149. offsetY = e.clientY - container.getBoundingClientRect().top;
  5150. container.style.transition = 'none';
  5151. });
  5152. document.addEventListener('mousemove', (e) => {
  5153. if (isDragging) {
  5154. container.style.right = 'auto';
  5155. container.style.bottom = 'auto';
  5156. container.style.left = (e.clientX - offsetX) + 'px';
  5157. container.style.top = (e.clientY - offsetY) + 'px';
  5158. }
  5159. });
  5160. document.addEventListener('mouseup', () => {
  5161. isDragging = false;
  5162. container.style.transition = 'transform 0.3s ease, opacity 0.3s ease';
  5163. });
  5164. // Button to show the player again
  5165. const showButton = document.createElement('button');
  5166. showButton.id = 'spotify-float-button';
  5167. Object.assign(showButton.style, {
  5168. position: 'fixed',
  5169. bottom: '20px',
  5170. right: '20px',
  5171. width: '50px',
  5172. height: '50px',
  5173. borderRadius: '50%',
  5174. backgroundColor: '#1DB954',
  5175. color: 'white',
  5176. border: 'none',
  5177. boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
  5178. cursor: 'pointer',
  5179. zIndex: '9999',
  5180. fontSize: '24px',
  5181. transition: 'transform 0.2s ease',
  5182. display: 'flex',
  5183. alignItems: 'center',
  5184. justifyContent: 'center'
  5185. });
  5186. showButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="white" d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>`;
  5187. document.body.appendChild(showButton);
  5188. showButton.addEventListener('mouseenter', () => {
  5189. showButton.style.transform = 'scale(1.1)';
  5190. });
  5191. showButton.addEventListener('mouseleave', () => {
  5192. showButton.style.transform = 'scale(1)';
  5193. });
  5194. showButton.addEventListener('click', () => {
  5195. container.style.display = 'block';
  5196. container.style.transform = 'translateY(0)';
  5197. container.style.opacity = '1';
  5198. showButton.style.display = 'none';
  5199. });
  5200. return container;
  5201. }
  5202. toggleSpotifyMenu() {
  5203. if (this.isSpotifyPlayerEnabled) {
  5204. this.createSimpleSpotifyPlayer();
  5205. }
  5206. else {
  5207. this.removeSimpleSpotifyPlayer();
  5208. }
  5209. }
  5210. applyCustomMainMenuStyle() {
  5211. // Sélectionner le menu principal
  5212. const startMenu = document.getElementById('start-menu');
  5213. const playButtons = document.querySelectorAll('.btn-green, #btn-help, .btn-team-option');
  5214. const playerOptions = document.getElementById('player-options');
  5215. const serverSelect = document.getElementById('server-select-main');
  5216. const nameInput = document.getElementById('player-name-input-solo');
  5217. const helpSection = document.getElementById('start-help');
  5218. if (startMenu) {
  5219. // Apply styles to the main container
  5220. Object.assign(startMenu.style, {
  5221. background: 'linear-gradient(135deg, rgba(25, 25, 35, 0.95) 0%, rgba(15, 15, 25, 0.98) 100%)',
  5222. border: '1px solid rgba(255, 255, 255, 0.1)',
  5223. borderRadius: '12px',
  5224. boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',
  5225. padding: '15px',
  5226. backdropFilter: 'blur(10px)',
  5227. margin: '0 auto'
  5228. });
  5229. }
  5230. // Style the buttons
  5231. playButtons.forEach(button => {
  5232. if (button instanceof HTMLElement) {
  5233. if (button.classList.contains('btn-green')) {
  5234. // Boutons Play
  5235. Object.assign(button.style, {
  5236. background: 'linear-gradient(135deg, #4287f5 0%, #3b76d9 100%)',
  5237. borderRadius: '8px',
  5238. border: '1px solid rgba(255, 255, 255, 0.2)',
  5239. boxShadow: '0 4px 12px rgba(0, 0, 0, 0.2)',
  5240. transition: 'all 0.2s ease',
  5241. color: 'white',
  5242. fontWeight: 'bold'
  5243. });
  5244. }
  5245. else {
  5246. // Autres boutons
  5247. Object.assign(button.style, {
  5248. background: 'rgba(40, 45, 60, 0.7)',
  5249. borderRadius: '8px',
  5250. border: '1px solid rgba(255, 255, 255, 0.1)',
  5251. transition: 'all 0.2s ease',
  5252. color: 'white'
  5253. });
  5254. }
  5255. // Hover effect for all buttons
  5256. button.addEventListener('mouseover', () => {
  5257. button.style.transform = 'translateY(-2px)';
  5258. button.style.boxShadow = '0 6px 16px rgba(0, 0, 0, 0.3)';
  5259. button.style.filter = 'brightness(1.1)';
  5260. });
  5261. button.addEventListener('mouseout', () => {
  5262. button.style.transform = 'translateY(0)';
  5263. button.style.boxShadow = button.classList.contains('btn-green') ?
  5264. '0 4px 12px rgba(0, 0, 0, 0.2)' : 'none';
  5265. button.style.filter = 'brightness(1)';
  5266. });
  5267. }
  5268. });
  5269. // Styliser le sélecteur de serveur
  5270. if (serverSelect instanceof HTMLSelectElement) {
  5271. Object.assign(serverSelect.style, {
  5272. background: 'rgba(30, 35, 50, 0.8)',
  5273. borderRadius: '8px',
  5274. border: '1px solid rgba(255, 255, 255, 0.1)',
  5275. color: 'white',
  5276. padding: '8px 12px',
  5277. outline: 'none'
  5278. });
  5279. }
  5280. // Styliser l'input du nom
  5281. if (nameInput instanceof HTMLInputElement) {
  5282. Object.assign(nameInput.style, {
  5283. background: 'rgba(30, 35, 50, 0.8)',
  5284. borderRadius: '8px',
  5285. border: '1px solid rgba(255, 255, 255, 0.1)',
  5286. color: 'white',
  5287. padding: '8px 12px',
  5288. outline: 'none'
  5289. });
  5290. // Focus style
  5291. nameInput.addEventListener('focus', () => {
  5292. nameInput.style.border = '1px solid #4287f5';
  5293. nameInput.style.boxShadow = '0 0 8px rgba(66, 135, 245, 0.5)';
  5294. });
  5295. nameInput.addEventListener('blur', () => {
  5296. nameInput.style.border = '1px solid rgba(255, 255, 255, 0.1)';
  5297. nameInput.style.boxShadow = 'none';
  5298. });
  5299. }
  5300. // Styliser la section d'aide
  5301. if (helpSection) {
  5302. Object.assign(helpSection.style, {
  5303. background: 'rgba(20, 25, 40, 0.7)',
  5304. borderRadius: '8px',
  5305. padding: '15px',
  5306. margin: '15px 0',
  5307. maxHeight: '300px',
  5308. overflowY: 'auto',
  5309. scrollbarWidth: 'thin',
  5310. scrollbarColor: '#4287f5 rgba(25, 25, 35, 0.5)'
  5311. });
  5312. // Style the help section titles
  5313. const helpTitles = helpSection.querySelectorAll('h1');
  5314. helpTitles.forEach(title => {
  5315. if (title instanceof HTMLElement) {
  5316. Object.assign(title.style, {
  5317. color: '#4287f5',
  5318. fontSize: '18px',
  5319. marginTop: '15px',
  5320. marginBottom: '8px'
  5321. });
  5322. }
  5323. });
  5324. // Style the paragraphs
  5325. const helpParagraphs = helpSection.querySelectorAll('p');
  5326. helpParagraphs.forEach(p => {
  5327. if (p instanceof HTMLElement) {
  5328. p.style.color = 'rgba(255, 255, 255, 0.8)';
  5329. p.style.fontSize = '14px';
  5330. p.style.marginBottom = '8px';
  5331. }
  5332. });
  5333. // Style the action terms and controls
  5334. const actionTerms = helpSection.querySelectorAll('.help-action');
  5335. actionTerms.forEach(term => {
  5336. if (term instanceof HTMLElement) {
  5337. term.style.color = '#ffc107'; // Yellow
  5338. term.style.fontWeight = 'bold';
  5339. }
  5340. });
  5341. const controlTerms = helpSection.querySelectorAll('.help-control');
  5342. controlTerms.forEach(term => {
  5343. if (term instanceof HTMLElement) {
  5344. term.style.color = '#4287f5'; // Bleu
  5345. term.style.fontWeight = 'bold';
  5346. }
  5347. });
  5348. }
  5349. // Apply specific style to double buttons
  5350. const btnsDoubleRow = document.querySelector('.btns-double-row');
  5351. if (btnsDoubleRow instanceof HTMLElement) {
  5352. btnsDoubleRow.style.display = 'flex';
  5353. btnsDoubleRow.style.gap = '10px';
  5354. btnsDoubleRow.style.marginTop = '10px';
  5355. }
  5356. }
  5357. MainMenuCleaning() {
  5358. // Déconnecter l'observateur précédent s'il existe
  5359. if (this.adBlockObserver) {
  5360. this.adBlockObserver.disconnect();
  5361. this.adBlockObserver = null;
  5362. }
  5363. // Select elements to hide/show
  5364. const newsWrapper = document.getElementById('news-wrapper');
  5365. const adBlockLeft = document.getElementById('ad-block-left');
  5366. const socialLeft = document.getElementById('social-share-block-wrapper');
  5367. const leftCollun = document.getElementById('left-column');
  5368. const elementsToMonitor = [
  5369. { element: newsWrapper, id: 'news-wrapper' },
  5370. { element: adBlockLeft, id: 'ad-block-left' },
  5371. { element: socialLeft, id: 'social-share-block-wrapper' },
  5372. { element: leftCollun, id: 'left-column' }
  5373. ];
  5374. // Appliquer le style personnalisé au menu principal
  5375. this.applyCustomMainMenuStyle();
  5376. if (this.isMainMenuCleaned) {
  5377. // Clean mode: hide elements
  5378. elementsToMonitor.forEach(item => {
  5379. if (item.element)
  5380. item.element.style.display = 'none';
  5381. });
  5382. // Create an observer to prevent the site from redisplaying elements
  5383. this.adBlockObserver = new MutationObserver((mutations) => {
  5384. let needsUpdate = false;
  5385. mutations.forEach(mutation => {
  5386. if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
  5387. const target = mutation.target;
  5388. // Check if the element is one of those we are monitoring
  5389. if (elementsToMonitor.some(item => item.id === target.id && target.style.display !== 'none')) {
  5390. target.style.display = 'none';
  5391. needsUpdate = true;
  5392. }
  5393. }
  5394. });
  5395. // If the site tries to redisplay an advertising element, we prevent it
  5396. if (needsUpdate) {
  5397. console.log('[KxsClient] Detection of attempt to redisplay ads - Forced hiding');
  5398. }
  5399. });
  5400. // Observe style changes on elements
  5401. elementsToMonitor.forEach(item => {
  5402. if (item.element && this.adBlockObserver) {
  5403. this.adBlockObserver.observe(item.element, {
  5404. attributes: true,
  5405. attributeFilter: ['style']
  5406. });
  5407. }
  5408. });
  5409. // Vérifier également le document body pour de nouveaux éléments ajoutés
  5410. const bodyObserver = new MutationObserver(() => {
  5411. // Réappliquer notre nettoyage après un court délai
  5412. setTimeout(() => {
  5413. if (this.isMainMenuCleaned) {
  5414. elementsToMonitor.forEach(item => {
  5415. const element = document.getElementById(item.id);
  5416. if (element && element.style.display !== 'none') {
  5417. element.style.display = 'none';
  5418. }
  5419. });
  5420. }
  5421. }, 100);
  5422. });
  5423. // Observe changes in the DOM
  5424. bodyObserver.observe(document.body, { childList: true, subtree: true });
  5425. }
  5426. else {
  5427. // Mode normal: rétablir l'affichage
  5428. elementsToMonitor.forEach(item => {
  5429. if (item.element)
  5430. item.element.style.display = 'block';
  5431. });
  5432. }
  5433. }
  5434. removeSimpleSpotifyPlayer() {
  5435. // Supprimer le conteneur principal du lecteur
  5436. const container = document.getElementById('spotify-player-container');
  5437. if (container) {
  5438. container.remove();
  5439. }
  5440. // Supprimer aussi le bouton flottant grâce à son ID
  5441. const floatButton = document.getElementById('spotify-float-button');
  5442. if (floatButton) {
  5443. floatButton.remove();
  5444. }
  5445. }
  5446. }
  5447.  
  5448. ;// ./src/LoadingScreen.ts
  5449. /**
  5450. * LoadingScreen.ts
  5451. *
  5452. * This module provides a loading animation with a logo and a rotating loading circle
  5453. * that displays during the loading of game resources.
  5454. */
  5455. class LoadingScreen {
  5456. /**
  5457. * Creates a new instance of the loading screen
  5458. * @param logoUrl URL of the Kxs logo to display
  5459. */
  5460. constructor(logoUrl) {
  5461. this.logoUrl = logoUrl;
  5462. this.container = document.createElement('div');
  5463. this.initializeStyles();
  5464. this.createContent();
  5465. }
  5466. /**
  5467. * Initializes CSS styles for the loading screen
  5468. */
  5469. initializeStyles() {
  5470. // Styles for the main container
  5471. Object.assign(this.container.style, {
  5472. position: 'fixed',
  5473. top: '0',
  5474. left: '0',
  5475. width: '100%',
  5476. height: '100%',
  5477. backgroundColor: 'rgba(0, 0, 0, 0.9)',
  5478. display: 'flex',
  5479. flexDirection: 'column',
  5480. justifyContent: 'center',
  5481. alignItems: 'center',
  5482. zIndex: '9999',
  5483. transition: 'opacity 0.5s ease-in-out',
  5484. animation: 'fadeIn 0.5s ease-in-out',
  5485. backdropFilter: 'blur(5px)'
  5486. });
  5487. }
  5488. /**
  5489. * Creates the loading screen content (logo and loading circle)
  5490. */
  5491. createContent() {
  5492. // Create container for the logo
  5493. const logoContainer = document.createElement('div');
  5494. Object.assign(logoContainer.style, {
  5495. width: '200px',
  5496. height: '200px',
  5497. marginBottom: '20px',
  5498. position: 'relative',
  5499. display: 'flex',
  5500. justifyContent: 'center',
  5501. alignItems: 'center'
  5502. });
  5503. // Create the logo element
  5504. const logo = document.createElement('img');
  5505. logo.src = this.logoUrl;
  5506. Object.assign(logo.style, {
  5507. width: '150px',
  5508. height: '150px',
  5509. objectFit: 'contain',
  5510. position: 'absolute',
  5511. zIndex: '2',
  5512. animation: 'pulse 2s ease-in-out infinite'
  5513. });
  5514. // Create the main loading circle
  5515. const loadingCircle = document.createElement('div');
  5516. Object.assign(loadingCircle.style, {
  5517. width: '180px',
  5518. height: '180px',
  5519. border: '4px solid transparent',
  5520. borderTopColor: '#3498db',
  5521. borderRadius: '50%',
  5522. animation: 'spin 1.5s linear infinite',
  5523. position: 'absolute',
  5524. zIndex: '1'
  5525. });
  5526. // Create a second loading circle (rotating in the opposite direction)
  5527. const loadingCircle2 = document.createElement('div');
  5528. Object.assign(loadingCircle2.style, {
  5529. width: '200px',
  5530. height: '200px',
  5531. border: '2px solid transparent',
  5532. borderLeftColor: '#e74c3c',
  5533. borderRightColor: '#e74c3c',
  5534. borderRadius: '50%',
  5535. animation: 'spin-reverse 3s linear infinite',
  5536. position: 'absolute',
  5537. zIndex: '0'
  5538. });
  5539. // Add animations
  5540. const styleSheet = document.createElement('style');
  5541. styleSheet.textContent = `
  5542. @keyframes spin {
  5543. 0% { transform: rotate(0deg); }
  5544. 100% { transform: rotate(360deg); }
  5545. }
  5546. @keyframes spin-reverse {
  5547. 0% { transform: rotate(0deg); }
  5548. 100% { transform: rotate(-360deg); }
  5549. }
  5550. @keyframes pulse {
  5551. 0% { transform: scale(1); }
  5552. 50% { transform: scale(1.05); }
  5553. 100% { transform: scale(1); }
  5554. }
  5555. @keyframes fadeIn {
  5556. 0% { opacity: 0; }
  5557. 100% { opacity: 1; }
  5558. }
  5559. `;
  5560. document.head.appendChild(styleSheet);
  5561. // Ajout d'un texte de chargement
  5562. const loadingText = document.createElement('div');
  5563. loadingText.textContent = 'Loading...';
  5564. Object.assign(loadingText.style, {
  5565. color: 'white',
  5566. fontFamily: 'Arial, sans-serif',
  5567. fontSize: '18px',
  5568. marginTop: '20px',
  5569. animation: 'pulse 1.5s ease-in-out infinite'
  5570. });
  5571. // Ajout d'un sous-texte
  5572. const subText = document.createElement('div');
  5573. subText.textContent = 'Initializing resources...';
  5574. Object.assign(subText.style, {
  5575. color: 'rgba(255, 255, 255, 0.7)',
  5576. fontFamily: 'Arial, sans-serif',
  5577. fontSize: '14px',
  5578. marginTop: '5px'
  5579. });
  5580. // Assemble the elements
  5581. logoContainer.appendChild(loadingCircle2);
  5582. logoContainer.appendChild(loadingCircle);
  5583. logoContainer.appendChild(logo);
  5584. this.container.appendChild(logoContainer);
  5585. this.container.appendChild(loadingText);
  5586. this.container.appendChild(subText);
  5587. }
  5588. /**
  5589. * Shows the loading screen
  5590. */
  5591. show() {
  5592. document.body.appendChild(this.container);
  5593. }
  5594. /**
  5595. * Hides the loading screen with a fade transition
  5596. */
  5597. hide() {
  5598. this.container.style.opacity = '0';
  5599. setTimeout(() => {
  5600. if (this.container.parentNode) {
  5601. document.body.removeChild(this.container);
  5602. }
  5603. }, 500); // Wait for the transition to finish before removing the element
  5604. }
  5605. }
  5606.  
  5607. ;// ./src/index.ts
  5608.  
  5609.  
  5610.  
  5611.  
  5612.  
  5613. const src_packageInfo = __webpack_require__(330);
  5614. const src_config = __webpack_require__(891);
  5615. const background_song = src_config.base_url + "/assets/Stranger_Things_Theme_Song_C418_REMIX.mp3";
  5616. const kxs_logo = src_config.base_url + "/assets/KysClientLogo.png";
  5617. const full_logo = src_config.base_url + "/assets/KysClient.gif";
  5618. const background_image = src_config.base_url + "/assets/background.jpg";
  5619. const loadingScreen = new LoadingScreen(kxs_logo);
  5620. loadingScreen.show();
  5621. const backgroundElement = document.getElementById("background");
  5622. if (backgroundElement)
  5623. backgroundElement.style.backgroundImage = `url("${background_image}")`;
  5624. const favicon = document.createElement('link');
  5625. favicon.rel = 'icon';
  5626. favicon.type = 'image/png';
  5627. favicon.href = kxs_logo;
  5628. document.head.appendChild(favicon);
  5629. document.title = "KxsClient";
  5630. intercept("audio/ambient/menu_music_01.mp3", background_song);
  5631. intercept('img/survev_logo_full.png', full_logo);
  5632. const uiStatsLogo = document.querySelector('#ui-stats-logo');
  5633. if (uiStatsLogo) {
  5634. uiStatsLogo.style.backgroundImage = `url('${full_logo}')`;
  5635. }
  5636. const newChangelogUrl = src_config.base_url;
  5637. const startBottomMiddle = document.getElementById("start-bottom-middle");
  5638. if (startBottomMiddle) {
  5639. const links = startBottomMiddle.getElementsByTagName("a");
  5640. for (let i = 0; i < links.length; i++) {
  5641. const link = links[i];
  5642. if (link.href.includes("changelogRec.html") || link.href.includes("changelog.html")) {
  5643. link.href = newChangelogUrl;
  5644. link.textContent = src_packageInfo.version;
  5645. }
  5646. if (i === 1) {
  5647. link.remove();
  5648. }
  5649. }
  5650. }
  5651. const kxsClient = new KxsClient();
  5652. const kxsClientHUD = new KxsClientHUD(kxsClient);
  5653. const mainMenu = new KxsMainClientMenu(kxsClient);
  5654. setInterval(() => {
  5655. loadingScreen.hide();
  5656. }, 1400);
  5657.  
  5658. })();
  5659.  
  5660. /******/ })()
  5661. ;

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址