Commit a7073477 authored by nanahira's avatar nanahira

Merge branch 'master' into ai-play

parents 65a995d8 fd2bf6ea
Pipeline #41576 passed with stages
in 10 minutes and 11 seconds
...@@ -10,7 +10,7 @@ RUN apt update && \ ...@@ -10,7 +10,7 @@ RUN apt update && \
# windbot # windbot
RUN git clone --depth=1 https://code.mycard.moe/nanahira/windbot /tmp/windbot && \ RUN git clone --depth=1 https://code.mycard.moe/nanahira/windbot /tmp/windbot && \
cd /tmp/windbot && \ cd /tmp/windbot && \
xbuild /property:Configuration=Release /property:TargetFrameworkVersion="v4.0" && \ xbuild /property:Configuration=Release /property:TargetFrameworkVersion="v4.5" && \
mv /tmp/windbot/bin/Release /ygopro-server/windbot && \ mv /tmp/windbot/bin/Release /ygopro-server/windbot && \
cp -rf /ygopro-server/ygopro/cards.cdb /ygopro-server/windbot/ && \ cp -rf /ygopro-server/ygopro/cards.cdb /ygopro-server/windbot/ && \
rm -rf /tmp/windbot rm -rf /tmp/windbot
......
...@@ -38,7 +38,7 @@ RUN git clone --branch=server --recursive --depth=1 https://code.mycard.moe/nana ...@@ -38,7 +38,7 @@ RUN git clone --branch=server --recursive --depth=1 https://code.mycard.moe/nana
strip ygopro && \ strip ygopro && \
mkdir replay expansions && \ mkdir replay expansions && \
rm -rf .git* bin obj build ocgcore cmake lua premake* sound textures .travis.yml *.txt appveyor.yml LICENSE README.md *.lua strings.conf system.conf && \ rm -rf .git* bin obj build ocgcore cmake lua premake* sound textures .travis.yml *.txt appveyor.yml LICENSE README.md *.lua strings.conf system.conf && \
ls gframe | sed '/game.cpp/d' | xargs -I {} rm -rf gframe/{} ls gframe | sed '/config.h/d' | xargs -I {} rm -rf gframe/{}
# infos # infos
WORKDIR /ygopro-server WORKDIR /ygopro-server
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
"stop": false, "stop": false,
"full": "服务器已爆满", "full": "服务器已爆满",
"max_rooms_count": 0, "max_rooms_count": 0,
"max_mem_percentage": 95,
"side_timeout": false, "side_timeout": false,
"replay_delay": true, "replay_delay": true,
"hide_name": false, "hide_name": false,
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
"expansions_path": [ "expansions_path": [
"./expansions" "./expansions"
], ],
"extra_script_path": [],
"i18n": { "i18n": {
"auto_pick": false, "auto_pick": false,
"default": "zh-cn", "default": "zh-cn",
...@@ -79,7 +81,8 @@ ...@@ -79,7 +81,8 @@
"get": "https://sapi.moecube.com:444/biu-tips/tips.json", "get": "https://sapi.moecube.com:444/biu-tips/tips.json",
"get_zh": false, "get_zh": false,
"interval": 30000, "interval": 30000,
"interval_ingame": 120000 "interval_ingame": 120000,
"prefix": "Tip: "
}, },
"dialogues": { "dialogues": {
"enabled": true, "enabled": true,
...@@ -118,7 +121,8 @@ ...@@ -118,7 +121,8 @@
"TMR": true "TMR": true
}, },
"ready_time": 20, "ready_time": 20,
"hang_timeout": 90 "hang_timeout": 90,
"extra_modes": {}
}, },
"mysql": { "mysql": {
"enabled": false, "enabled": false,
...@@ -245,8 +249,9 @@ ...@@ -245,8 +249,9 @@
"endpoint": "https://api.openai.com", "endpoint": "https://api.openai.com",
"token": "sk-xxxx", "token": "sk-xxxx",
"model": "gpt-4o-mini", "model": "gpt-4o-mini",
"system_prompt": "", "system_prompt": "你是{{windbot}},一名与{{player}}实时互动的游戏对手。你的回复应简短、有趣、贴合当前情境,增强玩家沉浸感。避免冗长解释或重复内容,保持自然流畅,并且每次回复不能超过100个字。",
"comment": "{{player}} and {{opponent}} will be replaced in the prompt", "comment": "{{player}} and {{windbot}} will be replaced in the prompt",
"token_limit": 12000,
"extra_opts": {} "extra_opts": {}
}, },
"test_mode": { "test_mode": {
......
...@@ -411,8 +411,8 @@ ...@@ -411,8 +411,8 @@
"bad_user_name": "请输入正确的用户名", "bad_user_name": "请输入正确的用户名",
"server_full": "服务器已经爆满,请稍候再试", "server_full": "服务器已经爆满,请稍候再试",
"too_much_connection": "同时开启的客户端数量过多 ", "too_much_connection": "同时开启的客户端数量过多 ",
"banned_ip_login": "您的账号已被封禁", "banned_ip_login": "您的账号已被封禁。如果您没有进行违规操作且用的是流量网络,可能过几小时就好。是IP撞了。",
"banned_user_login": "您的账号已被封禁", "banned_user_login": "您的账号已被封禁。如果您没有进行违规操作且用的是流量网络,可能过几小时就好。是IP撞了。",
"bad_name_level3": "您的用户名存在不适当的内容", "bad_name_level3": "您的用户名存在不适当的内容",
"bad_name_level2": "您的用户名存在不适当的内容", "bad_name_level2": "您的用户名存在不适当的内容",
"bad_name_level1": "您的用户名存在不适当的内容,请注意更改", "bad_name_level1": "您的用户名存在不适当的内容,请注意更改",
......
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"formidable": "^1.2.6", "formidable": "^1.2.6",
"geoip-country-lite": "^1.0.0", "geoip-country-lite": "^1.0.0",
"gpt-tokenizer": "^3.0.1",
"ip6addr": "^0.2.5", "ip6addr": "^0.2.5",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"load-json-file": "^6.2.0", "load-json-file": "^6.2.0",
"lzma": "^2.3.2", "lzma": "^2.3.2",
"moment": "^2.29.1", "moment": "^2.29.1",
"mustache": "^4.2.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-os-utils": "^1.3.2", "node-os-utils": "^1.3.2",
"p-queue": "^6.6.2", "p-queue": "^6.6.2",
...@@ -34,7 +36,7 @@ ...@@ -34,7 +36,7 @@
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "^3.3.6", "underscore.string": "^3.3.6",
"ws": "^8.9.0", "ws": "^8.9.0",
"ygopro-deck-encode": "^1.0.9" "ygopro-deck-encode": "^1.0.14"
}, },
"devDependencies": { "devDependencies": {
"@types/bunyan": "^1.8.8", "@types/bunyan": "^1.8.8",
...@@ -1357,6 +1359,12 @@ ...@@ -1357,6 +1359,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gpt-tokenizer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/gpt-tokenizer/-/gpt-tokenizer-3.0.1.tgz",
"integrity": "sha512-5jdaspBq/w4sWw322SvQj1Fku+CN4OAfYZeeEg8U7CWtxBz+zkxZ3h0YOHD43ee+nZYZ5Ud70HRN0ANcdIj4qg==",
"license": "MIT"
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "1.1.14", "version": "1.1.14",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz",
...@@ -1933,6 +1941,15 @@ ...@@ -1933,6 +1941,15 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/mustache": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
"license": "MIT",
"bin": {
"mustache": "bin/mustache"
}
},
"node_modules/mv": { "node_modules/mv": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
...@@ -3687,9 +3704,9 @@ ...@@ -3687,9 +3704,9 @@
} }
}, },
"node_modules/ygopro-deck-encode": { "node_modules/ygopro-deck-encode": {
"version": "1.0.9", "version": "1.0.14",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.9.tgz", "resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.14.tgz",
"integrity": "sha512-2aw/Lr8Sg4cPXKgq71Zk/GQPTZy5GhmviptVHWqMGEW0E2qTaxwpGmsQAN2Q4OWaK1lP+3g3bZt9BaqmWYZQSw==", "integrity": "sha512-Q64f8U+okLBDKHw02eRYsdDMpALhYa55k0BhFqZ5k4ntRpPKFNvM9sNEbBlg2bmyi6LCf3rlEmISmLtlx9uDeA==",
"license": "MIT" "license": "MIT"
} }
}, },
...@@ -4678,6 +4695,11 @@ ...@@ -4678,6 +4695,11 @@
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
}, },
"gpt-tokenizer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/gpt-tokenizer/-/gpt-tokenizer-3.0.1.tgz",
"integrity": "sha512-5jdaspBq/w4sWw322SvQj1Fku+CN4OAfYZeeEg8U7CWtxBz+zkxZ3h0YOHD43ee+nZYZ5Ud70HRN0ANcdIj4qg=="
},
"graceful-fs": { "graceful-fs": {
"version": "1.1.14", "version": "1.1.14",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz",
...@@ -5111,6 +5133,11 @@ ...@@ -5111,6 +5133,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"mustache": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="
},
"mv": { "mv": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
...@@ -6446,9 +6473,9 @@ ...@@ -6446,9 +6473,9 @@
} }
}, },
"ygopro-deck-encode": { "ygopro-deck-encode": {
"version": "1.0.9", "version": "1.0.14",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.9.tgz", "resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.14.tgz",
"integrity": "sha512-2aw/Lr8Sg4cPXKgq71Zk/GQPTZy5GhmviptVHWqMGEW0E2qTaxwpGmsQAN2Q4OWaK1lP+3g3bZt9BaqmWYZQSw==" "integrity": "sha512-Q64f8U+okLBDKHw02eRYsdDMpALhYa55k0BhFqZ5k4ntRpPKFNvM9sNEbBlg2bmyi6LCf3rlEmISmLtlx9uDeA=="
} }
} }
} }
...@@ -18,11 +18,13 @@ ...@@ -18,11 +18,13 @@
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"formidable": "^1.2.6", "formidable": "^1.2.6",
"geoip-country-lite": "^1.0.0", "geoip-country-lite": "^1.0.0",
"gpt-tokenizer": "^3.0.1",
"ip6addr": "^0.2.5", "ip6addr": "^0.2.5",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"load-json-file": "^6.2.0", "load-json-file": "^6.2.0",
"lzma": "^2.3.2", "lzma": "^2.3.2",
"moment": "^2.29.1", "moment": "^2.29.1",
"mustache": "^4.2.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-os-utils": "^1.3.2", "node-os-utils": "^1.3.2",
"p-queue": "^6.6.2", "p-queue": "^6.6.2",
...@@ -36,7 +38,7 @@ ...@@ -36,7 +38,7 @@
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "^3.3.6", "underscore.string": "^3.3.6",
"ws": "^8.9.0", "ws": "^8.9.0",
"ygopro-deck-encode": "^1.0.9" "ygopro-deck-encode": "^1.0.14"
}, },
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
......
...@@ -25,6 +25,8 @@ qs = require "querystring" ...@@ -25,6 +25,8 @@ qs = require "querystring"
zlib = require 'zlib' zlib = require 'zlib'
axios = require 'axios' axios = require 'axios'
osu = require 'node-os-utils' osu = require 'node-os-utils'
mustache = require 'mustache'
gpt_tokenizer = require 'gpt-tokenizer/model/gpt-4o'
bunyan = require 'bunyan' bunyan = require 'bunyan'
log = global.log = bunyan.createLogger name: "mycard" log = global.log = bunyan.createLogger name: "mycard"
...@@ -511,7 +513,7 @@ loadLFList = (path) -> ...@@ -511,7 +513,7 @@ loadLFList = (path) ->
catch catch
try try
log.info("Reading YGOPro version.") log.info("Reading YGOPro version.")
cppversion = parseInt((await fs.promises.readFile(path.resolve(settings.modules.ygopro_path, 'gframe', 'game.cpp'), 'utf8')).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16') cppversion = parseInt((await fs.promises.readFile(path.resolve(settings.modules.ygopro_path, 'gframe', 'config.h'), 'utf8')).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16')
await setting_change(settings, "version", cppversion) await setting_change(settings, "version", cppversion)
log.info "ygopro version 0x"+settings.version.toString(16), "(from source code)" log.info "ygopro version 0x"+settings.version.toString(16), "(from source code)"
catch catch
...@@ -852,11 +854,11 @@ ROOM_find_or_create_by_name = global.ROOM_find_or_create_by_name = (name, player ...@@ -852,11 +854,11 @@ ROOM_find_or_create_by_name = global.ROOM_find_or_create_by_name = (name, player
uname=name.toUpperCase() uname=name.toUpperCase()
if settings.modules.windbot.enabled and (uname[0...2] == 'AI' or (!settings.modules.random_duel.enabled and uname == '')) if settings.modules.windbot.enabled and (uname[0...2] == 'AI' or (!settings.modules.random_duel.enabled and uname == ''))
return ROOM_find_or_create_ai(name) return ROOM_find_or_create_ai(name)
if settings.modules.random_duel.enabled and (uname == '' or uname == 'S' or uname == 'M' or uname == 'T' or uname == 'TOR' or uname == 'TR' or uname == 'OOR' or uname == 'OR' or uname == 'TOMR' or uname == 'TMR' or uname == 'OOMR' or uname == 'OMR' or uname == 'CR' or uname == 'CMR') if settings.modules.random_duel.enabled and (uname == '' or uname == 'S' or uname == 'M' or uname == 'T' or uname == 'TOR' or uname == 'TR' or uname == 'OOR' or uname == 'OR' or uname == 'TOMR' or uname == 'TMR' or uname == 'OOMR' or uname == 'OMR' or uname == 'CR' or uname == 'CMR' or settings.modules.random_duel.extra_modes[uname] != undefined)
return await ROOM_find_or_create_random(uname, player_ip) return await ROOM_find_or_create_random(uname, player_ip)
if room = ROOM_find_by_name(name) if room = ROOM_find_by_name(name)
return room return room
else if memory_usage >= 95 or (settings.modules.max_rooms_count and rooms_count >= settings.modules.max_rooms_count) else if memory_usage >= settings.modules.max_mem_percentage or (settings.modules.max_rooms_count and rooms_count >= settings.modules.max_rooms_count)
return null return null
else else
room = new Room(name) room = new Room(name)
...@@ -910,8 +912,9 @@ ROOM_find_or_create_random = global.ROOM_find_or_create_random = (type, player_i ...@@ -910,8 +912,9 @@ ROOM_find_or_create_random = global.ROOM_find_or_create_random = (type, player_i
else else
return null return null
if result.random_type=='S' then result.welcome2 = '${random_duel_enter_room_single}' if result.random_type=='S' then result.welcome2 = '${random_duel_enter_room_single}'
if result.random_type=='M' then result.welcome2 = '${random_duel_enter_room_match}' else if result.random_type=='M' then result.welcome2 = '${random_duel_enter_room_match}'
if result.random_type=='T' then result.welcome2 = '${random_duel_enter_room_tag}' else if result.random_type=='T' then result.welcome2 = '${random_duel_enter_room_tag}'
else result.welcome2 = settings.modules.random_duel.extra_modes[type]?.welcome ? ''
return result return result
ROOM_find_or_create_ai = global.ROOM_find_or_create_ai = (name)-> ROOM_find_or_create_ai = global.ROOM_find_or_create_ai = (name)->
...@@ -1626,6 +1629,11 @@ class Room ...@@ -1626,6 +1629,11 @@ class Room
path.resolve(settings.modules.ygopro_path, s) path.resolve(settings.modules.ygopro_path, s)
) )
.join(',') .join(',')
YGOPRO_EXTRA_SCRIPT: settings.modules.extra_script_path
.map((s) ->
path.resolve(settings.modules.ygopro_path, s)
)
.join(',')
} }
} }
) )
...@@ -1722,6 +1730,7 @@ class Room ...@@ -1722,6 +1730,7 @@ class Room
form_data.append 'start', @start_time form_data.append 'start', @start_time
form_data.append 'end', end_time form_data.append 'end', end_time
form_data.append 'arena', @arena form_data.append 'arena', @arena
form_data.append 'nonce', Math.random().toString()
post_score_process = () -> post_score_process = () ->
axios.post settings.modules.arena_mode.post_score, form_data, axios.post settings.modules.arena_mode.post_score, form_data,
...@@ -3369,7 +3378,7 @@ ygopro.stoc_send_random_tip = (client)-> ...@@ -3369,7 +3378,7 @@ ygopro.stoc_send_random_tip = (client)->
if settings.modules.tips.split_zh and tips.tips_zh.length and client.lang == "zh-cn" if settings.modules.tips.split_zh and tips.tips_zh.length and client.lang == "zh-cn"
tip_type = "tips_zh" tip_type = "tips_zh"
if settings.modules.tips.enabled && tips.tips.length && !client.is_local && !client.closed if settings.modules.tips.enabled && tips.tips.length && !client.is_local && !client.closed
ygopro.stoc_send_chat(client, "Tip: " + tips[tip_type][Math.floor(Math.random() * tips[tip_type].length)]) ygopro.stoc_send_chat(client, settings.modules.tips.prefix + tips[tip_type][Math.floor(Math.random() * tips[tip_type].length)])
await return await return
ygopro.stoc_send_random_tip_to_room = (room)-> ygopro.stoc_send_random_tip_to_room = (room)->
if settings.modules.tips.enabled && tips.tips.length if settings.modules.tips.enabled && tips.tips.length
...@@ -3708,14 +3717,30 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3708,14 +3717,30 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
cancel = true cancel = true
if not cancel and settings.modules.chatgpt.enabled and room.windbot and not client.is_post_watcher and client.pos < 2 and not client.is_local if not cancel and settings.modules.chatgpt.enabled and room.windbot and not client.is_post_watcher and client.pos < 2 and not client.is_local
# session_key = "#{settings.modules.chatgpt.session}:#{settings.port}:#{CLIENT_get_authorize_key(client)}" # session_key = "#{settings.modules.chatgpt.session}:#{settings.port}:#{CLIENT_get_authorize_key(client)}"
if room.is_requesting_chatgpt
return false
room.is_requesting_chatgpt = true
if not room.chatgpt_conversation
room.chatgpt_conversation = []
openai_req_body = { openai_req_body = {
messages: [ messages: Array.from(room.chatgpt_conversation),
{ role: "user", content: msg }
],
model: settings.modules.chatgpt.model model: settings.modules.chatgpt.model
} }
openai_req_body.messages.push { role: "user", content: msg }
shrink_index = 0
if settings.modules.chatgpt.system_prompt if settings.modules.chatgpt.system_prompt
openai_req_body.messages.unshift { role: "system", content: settings.modules.chatgpt.system_prompt.replace } openai_req_body.messages.unshift { role: "system", content: mustache.render(settings.modules.chatgpt.system_prompt, {
player: client.name,
windbot: room.windbot.name,
}, undefined, { escape: (v) -> v }) }
shrink_index = 1
# trim conversation if too long
shrink_count = 0
while !gpt_tokenizer.isWithinTokenLimit(openai_req_body.messages, settings.modules.chatgpt.max_tokens)
if openai_req_body.messages.length <= (1 + shrink_index)
break
openai_req_body.messages.splice(shrink_index, 2) # remove the oldest user+assistant pair
shrink_count += 2
Object.assign(openai_req_body, settings.modules.chatgpt.extra_opts) Object.assign(openai_req_body, settings.modules.chatgpt.extra_opts)
axios.post("#{settings.modules.chatgpt.endpoint}/v1/chat/completions", openai_req_body, { axios.post("#{settings.modules.chatgpt.endpoint}/v1/chat/completions", openai_req_body, {
timeout: 300000, timeout: 300000,
...@@ -3732,8 +3757,15 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3732,8 +3757,15 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos) ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos)
else else
ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos) ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos)
# save text
if shrink_count > 0
room.chatgpt_conversation.splice(0, shrink_count)
room.chatgpt_conversation.push { role: "user", content: msg }
room.chatgpt_conversation.push { role: "assistant", content: text }
).catch((err) -> ).catch((err) ->
log.error "CHATGPT ERROR", err log.error "CHATGPT ERROR", err
).finally(() ->
room.is_requesting_chatgpt = false
) )
return false return false
if !(room and (room.random_type or room.arena)) and not settings.modules.mycard.enabled if !(room and (room.random_type or room.arena)) and not settings.modules.mycard.enabled
...@@ -3899,14 +3931,10 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3899,14 +3931,10 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
else else
log.warn("GET ATHLETIC FAIL", client.name, athleticCheckResult.message) log.warn("GET ATHLETIC FAIL", client.name, athleticCheckResult.message)
if settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.deck_check if settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.deck_check
client_deck_obj = YGOProDeck.fromUpdateDeckPayload(buffer)
if settings.modules.challonge.enabled and client.challonge_info and client.challonge_info.deckbuf if settings.modules.challonge.enabled and client.challonge_info and client.challonge_info.deckbuf
trim_deckbuf = (buf) -> deck_obj = YGOProDeck.fromUpdateDeckPayload(Buffer.from(client.challonge_info.deckbuf, "base64"))
mainc = buf.readUInt32LE(0) if deck_obj.isEqual(client_deck_obj, { ignoreOrder: true })
sidec = buf.readUInt32LE(4)
# take first (2 + mainc + sidec) * 4 bytes
return buf.slice(0, (2 + mainc + sidec) * 4)
deckbuf_from_challonge = Buffer.from(client.challonge_info.deckbuf, "base64")
if trim_deckbuf(deckbuf_from_challonge).equals(trim_deckbuf(buffer))
#log.info("deck ok: " + client.name) #log.info("deck ok: " + client.name)
return deck_ok("${deck_correct_part1} #{client.challonge_info.name} ${deck_correct_part2}") return deck_ok("${deck_correct_part1} #{client.challonge_info.name} ${deck_correct_part2}")
else else
...@@ -3915,16 +3943,14 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3915,16 +3943,14 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
else else
decks = await fs.promises.readdir(settings.modules.tournament_mode.deck_path) decks = await fs.promises.readdir(settings.modules.tournament_mode.deck_path)
if decks.length if decks.length
found_deck=false found_deck = decks.find((deck) -> deck_name_match(deck, client.name))
for deck in decks
if deck_name_match(deck, client.name)
found_deck=deck
if found_deck if found_deck
deck_text = await fs.promises.readFile(settings.modules.tournament_mode.deck_path+found_deck,{encoding:"ASCII"}) deck_text = await fs.promises.readFile(settings.modules.tournament_mode.deck_path+found_deck,{encoding:"ASCII"})
deck_obj = YGOProDeck.fromYdkString(deck_text) deck_obj = YGOProDeck.fromYdkString(deck_text)
deck_main=deck_obj.main.concat(deck_obj.extra) # put extra cards to main
deck_side=deck_obj.side deck_obj.main = deck_obj.main.concat(deck_obj.extra)
if _.isEqual(buff_main, deck_main) and _.isEqual(buff_side, deck_side) deck_obj.extra = []
if client_deck_obj.isEqual(deck_obj, { ignoreOrder: true })
#log.info("deck ok: " + client.name) #log.info("deck ok: " + client.name)
return deck_ok("${deck_correct_part1} #{found_deck} ${deck_correct_part2}") return deck_ok("${deck_correct_part1} #{found_deck} ${deck_correct_part2}")
else else
......
// Generated by CoffeeScript 2.7.0 // Generated by CoffeeScript 2.7.0
(function() { (function() {
// 标准库 // 标准库
var Aragami, CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_send_vip_status, CLIENT_set_ip, CLIENT_use_cdkey, PQueue, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, VIP_generate_cdkeys, YGOProDeck, _, _async, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, url, users_cache, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib; var Aragami, CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_send_vip_status, CLIENT_set_ip, CLIENT_use_cdkey, PQueue, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, VIP_generate_cdkeys, YGOProDeck, _, _async, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, gpt_tokenizer, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, mustache, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, url, users_cache, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib;
net = require('net'); net = require('net');
...@@ -47,6 +47,10 @@ ...@@ -47,6 +47,10 @@
osu = require('node-os-utils'); osu = require('node-os-utils');
mustache = require('mustache');
gpt_tokenizer = require('gpt-tokenizer/model/gpt-4o');
bunyan = require('bunyan'); bunyan = require('bunyan');
log = global.log = bunyan.createLogger({ log = global.log = bunyan.createLogger({
...@@ -652,7 +656,7 @@ ...@@ -652,7 +656,7 @@
} }
try { try {
log.info("Reading YGOPro version."); log.info("Reading YGOPro version.");
cppversion = parseInt(((await fs.promises.readFile(path.resolve(settings.modules.ygopro_path, 'gframe', 'game.cpp'), 'utf8'))).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16'); cppversion = parseInt(((await fs.promises.readFile(path.resolve(settings.modules.ygopro_path, 'gframe', 'config.h'), 'utf8'))).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
await setting_change(settings, "version", cppversion); await setting_change(settings, "version", cppversion);
log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)"); log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
} catch (error1) { } catch (error1) {
...@@ -1091,12 +1095,12 @@ ...@@ -1091,12 +1095,12 @@
if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) { if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) {
return ROOM_find_or_create_ai(name); return ROOM_find_or_create_ai(name);
} }
if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T' || uname === 'TOR' || uname === 'TR' || uname === 'OOR' || uname === 'OR' || uname === 'TOMR' || uname === 'TMR' || uname === 'OOMR' || uname === 'OMR' || uname === 'CR' || uname === 'CMR')) { if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T' || uname === 'TOR' || uname === 'TR' || uname === 'OOR' || uname === 'OR' || uname === 'TOMR' || uname === 'TMR' || uname === 'OOMR' || uname === 'OMR' || uname === 'CR' || uname === 'CMR' || settings.modules.random_duel.extra_modes[uname] !== void 0)) {
return (await ROOM_find_or_create_random(uname, player_ip)); return (await ROOM_find_or_create_random(uname, player_ip));
} }
if (room = ROOM_find_by_name(name)) { if (room = ROOM_find_by_name(name)) {
return room; return room;
} else if (memory_usage >= 95 || (settings.modules.max_rooms_count && rooms_count >= settings.modules.max_rooms_count)) { } else if (memory_usage >= settings.modules.max_mem_percentage || (settings.modules.max_rooms_count && rooms_count >= settings.modules.max_rooms_count)) {
return null; return null;
} else { } else {
room = new Room(name); room = new Room(name);
...@@ -1113,7 +1117,7 @@ ...@@ -1113,7 +1117,7 @@
}; };
ROOM_find_or_create_random = global.ROOM_find_or_create_random = async function(type, player_ip) { ROOM_find_or_create_random = global.ROOM_find_or_create_random = async function(type, player_ip) {
var max_player, name, playerbanned, randomDuelBanRecord, result; var max_player, name, playerbanned, randomDuelBanRecord, ref, ref1, result;
if (settings.modules.mysql.enabled) { if (settings.modules.mysql.enabled) {
randomDuelBanRecord = (await dataManager.getRandomDuelBan(player_ip)); randomDuelBanRecord = (await dataManager.getRandomDuelBan(player_ip));
if (randomDuelBanRecord) { if (randomDuelBanRecord) {
...@@ -1163,12 +1167,12 @@ ...@@ -1163,12 +1167,12 @@
} }
if (result.random_type === 'S') { if (result.random_type === 'S') {
result.welcome2 = '${random_duel_enter_room_single}'; result.welcome2 = '${random_duel_enter_room_single}';
} } else if (result.random_type === 'M') {
if (result.random_type === 'M') {
result.welcome2 = '${random_duel_enter_room_match}'; result.welcome2 = '${random_duel_enter_room_match}';
} } else if (result.random_type === 'T') {
if (result.random_type === 'T') {
result.welcome2 = '${random_duel_enter_room_tag}'; result.welcome2 = '${random_duel_enter_room_tag}';
} else {
result.welcome2 = (ref = (ref1 = settings.modules.random_duel.extra_modes[type]) != null ? ref1.welcome : void 0) != null ? ref : '';
} }
return result; return result;
}; };
...@@ -2081,6 +2085,9 @@ ...@@ -2081,6 +2085,9 @@
...process.env, ...process.env,
YGOPRO_EXPANSIONS: settings.modules.expansions_path.map(function(s) { YGOPRO_EXPANSIONS: settings.modules.expansions_path.map(function(s) {
return path.resolve(settings.modules.ygopro_path, s); return path.resolve(settings.modules.ygopro_path, s);
}).join(','),
YGOPRO_EXTRA_SCRIPT: settings.modules.extra_script_path.map(function(s) {
return path.resolve(settings.modules.ygopro_path, s);
}).join(',') }).join(',')
} }
}); });
...@@ -2227,6 +2234,7 @@ ...@@ -2227,6 +2234,7 @@
form_data.append('start', this.start_time); form_data.append('start', this.start_time);
form_data.append('end', end_time); form_data.append('end', end_time);
form_data.append('arena', this.arena); form_data.append('arena', this.arena);
form_data.append('nonce', Math.random().toString());
post_score_process = function() { post_score_process = function() {
return axios.post(settings.modules.arena_mode.post_score, form_data, { return axios.post(settings.modules.arena_mode.post_score, form_data, {
validateStatus: function(status) { validateStatus: function(status) {
...@@ -4467,7 +4475,7 @@ ...@@ -4467,7 +4475,7 @@
tip_type = "tips_zh"; tip_type = "tips_zh";
} }
if (settings.modules.tips.enabled && tips.tips.length && !client.is_local && !client.closed) { if (settings.modules.tips.enabled && tips.tips.length && !client.is_local && !client.closed) {
ygopro.stoc_send_chat(client, "Tip: " + tips[tip_type][Math.floor(Math.random() * tips[tip_type].length)]); ygopro.stoc_send_chat(client, settings.modules.tips.prefix + tips[tip_type][Math.floor(Math.random() * tips[tip_type].length)]);
} }
}; };
...@@ -4697,7 +4705,7 @@ ...@@ -4697,7 +4705,7 @@
//else //else
//log.info 'BIG BROTHER OK', response.statusCode, roomname, body //log.info 'BIG BROTHER OK', response.statusCode, roomname, body
ygopro.ctos_follow('CHAT', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('CHAT', true, async function(buffer, info, client, server, datas) {
var buy_result, cancel, ccolor, cip, cmd, cmsg, cname, code, color, cvalue, isVip, j, key, len, msg, name, oldmsg, openai_req_body, player, ref, ref1, room, struct, sur_player, uname, windbot, word; var buy_result, cancel, ccolor, cip, cmd, cmsg, cname, code, color, cvalue, isVip, j, key, len, msg, name, oldmsg, openai_req_body, player, ref, ref1, room, shrink_count, shrink_index, struct, sur_player, uname, windbot, word;
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
if (!room) { if (!room) {
return; return;
...@@ -4953,20 +4961,44 @@ ...@@ -4953,20 +4961,44 @@
} }
if (!cancel && settings.modules.chatgpt.enabled && room.windbot && !client.is_post_watcher && client.pos < 2 && !client.is_local) { if (!cancel && settings.modules.chatgpt.enabled && room.windbot && !client.is_post_watcher && client.pos < 2 && !client.is_local) {
// session_key = "#{settings.modules.chatgpt.session}:#{settings.port}:#{CLIENT_get_authorize_key(client)}" // session_key = "#{settings.modules.chatgpt.session}:#{settings.port}:#{CLIENT_get_authorize_key(client)}"
if (room.is_requesting_chatgpt) {
return false;
}
room.is_requesting_chatgpt = true;
if (!room.chatgpt_conversation) {
room.chatgpt_conversation = [];
}
openai_req_body = { openai_req_body = {
messages: [ messages: Array.from(room.chatgpt_conversation),
{
role: "user",
content: msg
}
],
model: settings.modules.chatgpt.model model: settings.modules.chatgpt.model
}; };
openai_req_body.messages.push({
role: "user",
content: msg
});
shrink_index = 0;
if (settings.modules.chatgpt.system_prompt) { if (settings.modules.chatgpt.system_prompt) {
openai_req_body.messages.unshift({ openai_req_body.messages.unshift({
role: "system", role: "system",
content: settings.modules.chatgpt.system_prompt.replace content: mustache.render(settings.modules.chatgpt.system_prompt, {
player: client.name,
windbot: room.windbot.name
}, void 0, {
escape: function(v) {
return v;
}
})
}); });
shrink_index = 1;
}
// trim conversation if too long
shrink_count = 0;
while (!gpt_tokenizer.isWithinTokenLimit(openai_req_body.messages, settings.modules.chatgpt.max_tokens)) {
if (openai_req_body.messages.length <= (1 + shrink_index)) {
break;
}
openai_req_body.messages.splice(shrink_index, 2); // remove the oldest user+assistant pair
shrink_count += 2;
} }
Object.assign(openai_req_body, settings.modules.chatgpt.extra_opts); Object.assign(openai_req_body, settings.modules.chatgpt.extra_opts);
axios.post(`${settings.modules.chatgpt.endpoint}/v1/chat/completions`, openai_req_body, { axios.post(`${settings.modules.chatgpt.endpoint}/v1/chat/completions`, openai_req_body, {
...@@ -4975,30 +5007,37 @@ ...@@ -4975,30 +5007,37 @@
Authorization: `Bearer ${settings.modules.chatgpt.token}` Authorization: `Bearer ${settings.modules.chatgpt.token}`
} }
}).then(function(res) { }).then(function(res) {
var chunk, chunks, l, len1, line, lines, results, text; var chunk, chunks, l, len1, len2, line, lines, m, text;
text = res.data.choices[0].message.content; text = res.data.choices[0].message.content;
lines = text.split("\n"); lines = text.split("\n");
results = [];
for (l = 0, len1 = lines.length; l < len1; l++) { for (l = 0, len1 = lines.length; l < len1; l++) {
line = lines[l]; line = lines[l];
if (line) { if (line) {
chunks = _.chunk(line, 100); chunks = _.chunk(line, 100);
results.push((function() { for (m = 0, len2 = chunks.length; m < len2; m++) {
var len2, m, results1; chunk = chunks[m];
results1 = []; ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos);
for (m = 0, len2 = chunks.length; m < len2; m++) { }
chunk = chunks[m];
results1.push(ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos));
}
return results1;
})());
} else { } else {
results.push(ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos)); ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos);
} }
} }
return results; // save text
if (shrink_count > 0) {
room.chatgpt_conversation.splice(0, shrink_count);
}
room.chatgpt_conversation.push({
role: "user",
content: msg
});
return room.chatgpt_conversation.push({
role: "assistant",
content: text
});
}).catch(function(err) { }).catch(function(err) {
return log.error("CHATGPT ERROR", err); return log.error("CHATGPT ERROR", err);
}).finally(function() {
return room.is_requesting_chatgpt = false;
}); });
return false; return false;
} }
...@@ -5087,7 +5126,7 @@ ...@@ -5087,7 +5126,7 @@
}); });
ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) {
var athleticCheckResult, buff_main, buff_side, deck, deck_bad, deck_main, deck_obj, deck_ok, deck_side, deck_text, deckbuf_from_challonge, decks, found_deck, i, j, len, oppo_pos, recover_player_data, recoveredDeck, room, trim_deckbuf, win_pos; var athleticCheckResult, buff_main, buff_side, client_deck_obj, deck_bad, deck_obj, deck_ok, deck_text, decks, found_deck, i, oppo_pos, recover_player_data, recoveredDeck, room, win_pos;
if (settings.modules.reconnect.enabled && client.pre_reconnecting) { if (settings.modules.reconnect.enabled && client.pre_reconnecting) {
if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) { if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) {
ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
...@@ -5220,16 +5259,12 @@ ...@@ -5220,16 +5259,12 @@
} }
} }
if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check) { if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check) {
client_deck_obj = YGOProDeck.fromUpdateDeckPayload(buffer);
if (settings.modules.challonge.enabled && client.challonge_info && client.challonge_info.deckbuf) { if (settings.modules.challonge.enabled && client.challonge_info && client.challonge_info.deckbuf) {
trim_deckbuf = function(buf) { deck_obj = YGOProDeck.fromUpdateDeckPayload(Buffer.from(client.challonge_info.deckbuf, "base64"));
var mainc, sidec; if (deck_obj.isEqual(client_deck_obj, {
mainc = buf.readUInt32LE(0); ignoreOrder: true
sidec = buf.readUInt32LE(4); })) {
// take first (2 + mainc + sidec) * 4 bytes
return buf.slice(0, (2 + mainc + sidec) * 4);
};
deckbuf_from_challonge = Buffer.from(client.challonge_info.deckbuf, "base64");
if (trim_deckbuf(deckbuf_from_challonge).equals(trim_deckbuf(buffer))) {
//log.info("deck ok: " + client.name) //log.info("deck ok: " + client.name)
return deck_ok(`\${deck_correct_part1} ${client.challonge_info.name} \${deck_correct_part2}`); return deck_ok(`\${deck_correct_part1} ${client.challonge_info.name} \${deck_correct_part2}`);
} else { } else {
...@@ -5239,21 +5274,20 @@ ...@@ -5239,21 +5274,20 @@
} else { } else {
decks = (await fs.promises.readdir(settings.modules.tournament_mode.deck_path)); decks = (await fs.promises.readdir(settings.modules.tournament_mode.deck_path));
if (decks.length) { if (decks.length) {
found_deck = false; found_deck = decks.find(function(deck) {
for (j = 0, len = decks.length; j < len; j++) { return deck_name_match(deck, client.name);
deck = decks[j]; });
if (deck_name_match(deck, client.name)) {
found_deck = deck;
}
}
if (found_deck) { if (found_deck) {
deck_text = (await fs.promises.readFile(settings.modules.tournament_mode.deck_path + found_deck, { deck_text = (await fs.promises.readFile(settings.modules.tournament_mode.deck_path + found_deck, {
encoding: "ASCII" encoding: "ASCII"
})); }));
deck_obj = YGOProDeck.fromYdkString(deck_text); deck_obj = YGOProDeck.fromYdkString(deck_text);
deck_main = deck_obj.main.concat(deck_obj.extra); // put extra cards to main
deck_side = deck_obj.side; deck_obj.main = deck_obj.main.concat(deck_obj.extra);
if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) { deck_obj.extra = [];
if (client_deck_obj.isEqual(deck_obj, {
ignoreOrder: true
})) {
//log.info("deck ok: " + client.name) //log.info("deck ok: " + client.name)
return deck_ok(`\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`); return deck_ok(`\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`);
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment