- 好友
- 9
- 在线时间
- 6 小时
- 最后登录
- 2024-10-3
贵族[MOD作者]
- UID
- 3181327
- 第纳尔
- 1774
- 精华
- 1
- 互助
- 24
- 荣誉
- 9
- 贡献
- 20
- 魅力
- 303
- 注册时间
- 2020-5-4
鲜花( 41) 鸡蛋( 0)
|
本帖最后由 长安归故里北 于 2024-9-28 14:03 编辑
【前排提醒】
本MOD如整合做合集谢绝收费,如若收费请剔除谢谢!!!
现在添加了混搭商人用于mod装备刷新,全文化酒馆可找到
1.本MOD虽然是标着国风,但是内容不全是写实的,不喜欢的可以不下载。模组本体不需前置。
2.支持游戏本体正式版z1.2.9-1.0.0版本
3.需要玩混搭包部队的需要下载下面的部队附件(需要下载前置模组ATC):httpswww.nexusmods.commountandblade2bannerlordmods286
4.需要锻造台配件全解锁的可下载后面的附件拖入模组文件夹即可
5.另外征集大家平衡后的装备武器数据以及自制的兵种树,可以私信或者加群发给我,我会整合下次更新发布!
6.对混搭武器包进行了拆分(国风和魔幻,本次更新为国风包),后面会单独发魔幻的包,一体包还好继续保持更新,但不会再加入新内容
MOD作者:长安归故里北
◆MOD名称
混搭武器包-国风
MOD简介
《混搭武器包-国风版》是一款拥有精美武器和装备的霸主扩展MOD。全新的精美盔甲以及武器数不胜数,高级华丽的马铠更是让人眼前一惊,这个包含丰富的国风装备的武器MOD简直就是玩家必不可少的武器库,尊敬的骑士,你还在等什么,快来补充你的军械库吧!
站站在这里希望所有喜欢《混搭武器包-国风》且有条件的骑友可以前往《混搭武器包》的爱发电主页捐赠支持作者 !
《混搭武器包》爱发电捐助主页:
https://afdian.net/@CAWeaponPack599
你们的支持是我继续更新下去的动力哦!!!!!
加载mod时左下角出现这样的红色文字说明模组加载成功!!!
◆更新内容
2024年8月5日更新:
1.更新了新的秦甲以及两个秦的旗帜,还有几套盔甲。 2.修复报错的问题,如果遇到报错则需要加上对应游戏版本的四前置MOD。 3.添加了新的武器-陌刀
2024年4月12日更新:
1.修复了与魔幻包不兼容的问题
2.修复了不开前置就报错的问题,现在已无需前置
2024年3月24日更新:
1.添加新盔甲、武器
2.修改了双手剑佩戴位置调为原版
3.制作了英文版
2024年2月23日更新v1.1.0版:
1.添加了一些盔甲、武器
2.为部分盔甲制作变体适配护手
3.优化部分盔甲lod
4.修复武器词条重复
5.制作了单双手剑佩戴位置
6.为部分盔甲制作了随阵营旗帜颜色变化
7.调整了小部分武器的伤害
2023年10月10日更新V1.04版:
1.修复报错
2.删除T7
3.新加一些盔甲
2023年10月4日更新V1.03版:
1.添加新武器、马甲、盔甲
2.优化宣化步人甲贴图
3.添加混搭商人用于mod装备刷新,全文化酒馆可找到
4.修复了金甲兽战马和汉旗帜报错的问题
5.混搭部队模组不在需要T7模组,国风包自带T7效果
6.优化了小部分模型
7.优化秦甲的材质,加入新的秦头盔
2023年5月29日更新v1.02版:
1.修复武器坐标错乱
2.新加三个盾牌,一个头巾,两个马甲3.修复黑旗肩甲丢失的问题
2023年5月27日更新:
1.优化八旗甲,并添加布料效果
2.添加全新盔甲、盾牌、武器和兵种树
3.添加工坊用于刷新装备
4.增加锻造台解锁部件的材料数量
5.修改了全武器盔甲价格和数值(这里感谢汽油君弑提供的数值修改文件和部分兵种树)
2023年5月11日
混搭武器包(国风)V1更新内容:
1.对混搭武器包进行了拆分(国风和魔幻,本次更新为国风包)
2.解决了明布面甲头盔加载问题。
3.加入大量国风盔甲(清八旗,宋步人甲等等具体可在游戏中查看)
4.重做了所有武器,国风包只保留国风武器,新增了明火绳枪。
5.新增了一个马甲和明的锅盔。
6.新增了一些单手剑和双手剑,锻造台可以更好的搭配
7.优化了面数较多的模型,数值保持不变,可以随意dly自己喜欢的。
8.给盾牌做了碰撞,受击范围更加合理。
9.给所有装备添加前缀
MOD交流群①:834808146(已满)
MOD交流群②:744322441(已满)
MOD交流群③:797879045
大家有什么疑问和建议可以进群交流讨论喔~
视频展示:
多多三联啊!!你们的支持才是我更新的动力!!!
装备展示(图片):
还整合了之前混搭武器包中的国风内容,装备武器图片查看请到:[原创][混搭武器包][z1.1.2-1.7.0] - MOD发布区 - 骑马与砍杀中文站论坛 - Powered by Discuz! (mountblade.com.cn)
【MOD相关】
1.“混搭武器包-国风版”是装备武器的扩展MOD,里面包含了很多中式的装备。
2.主要城市的武器和盔甲将被刷新。武器也可以在熔炉中制作。
3.建议凑齐一整套盔甲在装备,否则可能会因为我懒惰而导致身体隐形和穿模。抱歉,以后可能会修复
4.现在1.0.0到1.2.10都可以直接用.
5.不用开新档。
【安装】
1.首先,你需要确保你的游戏本体是正式版z1.2.10 -1.1.0,并确认游戏下载相应版本。
2.下载压缩包后,解压或拖拽到Modules文件中。
3. 开始游戏,在Mods选项页面勾选MixMashChineseFantasyArmorPack,点击play即可。
【下载地址】
夸克网盘(强烈推荐):
【1.2.9-1.0.0】:
r.json()).then(config => Var.cdnConfig = config).then(() => Var.cdnConfig) } async function getEasyShareHostChina() { return getCdnConfig(encodedChinaCdnA).then(c => c.easyShareHostChina) } let trustedPolicy = undefined; function updateInnnerHTML(e, html) { try { e.innerHTML = html; } catch { if (trustedPolicy == undefined) { trustedPolicy = trustedTypes.createPolicy('videoTogetherExtensionVtJsPolicy', { createHTML: (string) => string, createScript: (string) => string, createScriptURL: (url) => url }); } e.innerHTML = trustedPolicy.createHTML(html); } } function getDurationStr(duration) { try { let d = parseInt(duration); let str = "" let units = [" 秒 ", " 分 ", " 小时 "] for (let i in units) { if (d > 0) { str = d % 60 + units + str; } d = Math.floor(d / 60) } return str; } catch { return "N/A" } } function downloadEnabled() { try { if (window.VideoTogetherDownload == 'disabled') { return false; } const type = VideoTogetherStorage.UserscriptType return parseInt(window.VideoTogetherStorage.LoaddingVersion) >= 1694758378 && (type == "Chrome" || type == "Safari" || type == "Firefox") && !isDownloadBlackListDomain() } catch { return false; } } function isM3U8(textContent) { return textContent.trim().startsWith('#EXTM3U'); } function isMasterM3u8(textContent) { return textContent.includes('#EXT-X-STREAM-INF:'); } function getFirstMediaM3U8(m3u8Content, m3u8Url) { if (!isMasterM3u8(m3u8Content)) { return null; } const lines = m3u8Content.split('\n'); for (const line of lines) { const trimmedLine = line.trim(); if (trimmedLine && !trimmedLine.startsWith('#') && trimmedLine != "") { return new URL(trimmedLine, m3u8Url); } } return null; } function startDownload(_vtArgM3u8Url, _vtArgM3u8Content, _vtArgM3u8Urls, _vtArgTitle, _vtArgPageUrl) { /*//*/(async function () { function extractExtXKeyUrls(m3u8Content, baseUrl) { const uris = []; const lines = m3u8Content.split('\n'); for (let i = 0; i { const id = setTimeout(() => { reader.cancel(); rej(new Error('Stream read timed out')); }, timeout); }); return Promise.race([ reader.read(), timer ]); } function generateUUID() { if (crypto.randomUUID != undefined) { return crypto.randomUUID(); } return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } window.updateM3u8Status = async function updateM3u8Status(m3u8Url, status) { // 0 downloading 1 completed 2 deleting let m3u8mini = await readFromIndexedDB('m3u8s-mini', m3u8Url); m3u8mini.status = status await saveToIndexedDB('m3u8s-mini', m3u8Url, m3u8mini); } async function saveM3u8(m3u8Url, m3u8Content) { await saveToIndexedDB('m3u8s', m3u8Url, { data: m3u8Content, title: vtArgTitle, pageUrl: vtArgPageUrl, m3u8Url: m3u8Url, m3u8Id: m3u8Id, status: 0 } ) } async function blobToDataUrl(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = function (event) { resolve(event.target.result); }; reader.onerror = function (event) { reject(new Error("Failed to read blob")); }; reader.readAsDataURL(blob); }); } async function saveBlob(table, url, blob) { return new Promise(async (res, rej) => { try { const dataUrl = await blobToDataUrl(blob); await saveToIndexedDB(table, url, { data: dataUrl, m3u8Url: downloadM3u8Url, m3u8Id: m3u8Id, }) res(); } catch (e) { rej(e); } }) } window.regexMatchKeys = function regexMatchKeys(table, regex) { const queryId = generateUUID() return new Promise((res, rej) => { window.postMessage({ source: "VideoTogether", type: 2005, data: { table: table, regex: regex, id: queryId } }, '*') regexCallback[queryId] = (data) => { try { res(data) } catch { rej() } } }) } saveToIndexedDBThreads = 1; window.saveToIndexedDB = async function saveToIndexedDB(table, key, data) { while (saveToIndexedDBThreads setTimeout(r, 100)); } saveToIndexedDBThreads--; const queryId = generateUUID(); return new Promise((res, rej) => { data.saveTime = Date.now() window.postMessage({ source: "VideoTogether", type: 2001, data: { table: table, key: key, data: data, id: queryId, } }, '*') data = null; saveCallback[queryId] = (error) => { saveToIndexedDBThreads++; if (error === 0) { res(0) } else { rej(error) } } }) } window.iosDeleteByPrefix = async function iosDeleteByPrefix(prefix) { const queryId = generateUUID(); return new Promise((res, rej) => { window.postMessage({ source: "VideoTogether", type: 3010, data: { prefix: prefix, id: queryId, } }, '*') deleteByPrefix[queryId] = (error) => { if (error === 0) { res(0) } else { rej(error) } } }) } let readCallback = {} let regexCallback = {} let deleteCallback = {} let saveCallback = {} let deleteByPrefix = {} window.addEventListener('message', async e => { if (e.data.source == "VideoTogether") { switch (e.data.type) { case 2003: { saveCallback[e.data.data.id](e.data.data.error) saveCallback[e.data.data.id] = undefined break; } case 2004: { readCallback[e.data.data.id](e.data.data.data) readCallback[e.data.data.id] = undefined; break; } case 2006: { regexCallback[e.data.data.id](e.data.data.data) regexCallback[e.data.data.id] = undefined; break; } case 2008: { deleteCallback[e.data.data.id](e.data.data.error); deleteCallback[e.data.data.id] = undefined; break; } case 3011: { deleteByPrefix[e.data.data.id](e.data.data.error); deleteByPrefix[e.data.data.id] = undefined; break; } case 2010: { console.log(e.data.data.data); break; } } } }) window.requestStorageEstimate = function requestStorageEstimate() { window.postMessage({ source: "VideoTogether", type: 2009, data: {} }, '*') } window.deleteFromIndexedDB = function deleteFromIndexedDB(table, key) { const queryId = generateUUID() window.postMessage({ source: "VideoTogether", type: 2007, data: { id: queryId, table: table, key: key, } }, '*') return new Promise((res, rej) => { deleteCallback[queryId] = (error) => { if (error === 0) { res(true); } else { rej(error); } } }) } window.readFromIndexedDB = function readFromIndexedDB(table, key) { const queryId = generateUUID(); window.postMessage({ source: "VideoTogether", type: 2002, data: { table: table, key: key, id: queryId, } }, '*') return new Promise((res, rej) => { readCallback[queryId] = (data) => { try { res(data); } catch { rej() } } }) } if (window.videoTogetherExtension === undefined) { return; } if (window.location.hostname == 'local.2gether.video') { return; } let vtArgM3u8Url = undefined; let vtArgM3u8Content = undefined; let vtArgM3u8Urls = undefined; let vtArgTitle = undefined; let vtArgPageUrl = undefined; try { vtArgM3u8Url = _vtArgM3u8Url; vtArgM3u8Content = _vtArgM3u8Content; vtArgM3u8Urls = _vtArgM3u8Urls; vtArgTitle = _vtArgTitle; vtArgPageUrl = _vtArgPageUrl; } catch { return; } const m3u8Id = generateUUID() const m3u8IdHead = `-m3u8Id-${m3u8Id}-end-` const downloadM3u8Url = vtArgM3u8Url; const numThreads = 10; let lastTotalBytes = 0; let totalBytes = 0; let failedUrls = [] let urls = vtArgM3u8Urls let successCount = 0; videoTogetherExtension.downloadPercentage = 0; const m3u8Key = m3u8IdHead + downloadM3u8Url if (downloadM3u8Url === undefined) { return; } await saveM3u8(m3u8Key, vtArgM3u8Content) const otherUrl = extractExtXKeyUrls(vtArgM3u8Content, downloadM3u8Url); const totalCount = urls.length + otherUrl.length; console.log(otherUrl); await downloadInParallel('future', otherUrl, numThreads); setInterval(function () { videoTogetherExtension.downloadSpeedMb = (totalBytes - lastTotalBytes) / 1024 / 1024; lastTotalBytes = totalBytes; }, 1000); await downloadInParallel('videos', urls, numThreads); await updateM3u8Status(m3u8Key, 1) async function fetchWithSpeedTracking(url) { const controller = new AbortController(); const timer = setTimeout(() => { controller.abort(); }, 20000); const response = await fetch(url, { signal: controller.signal }); clearTimeout(timer) if (!response.body) { throw new Error("ReadableStream not yet supported in this browser."); } const contentType = response.headers.get("Content-Type") || "application/octet-stream"; const reader = response.body.getReader(); let chunks = []; async function readStream() { const { done, value } = await timeoutAsyncRead(reader, 60000); if (done) { return; } if (value) { chunks.push(value); totalBytes += value.length; } // Continue reading the stream return await readStream(); } await readStream(); const blob = new Blob(chunks, { type: contentType }); chunks = null; return blob; } async function downloadWorker(table, urls, index, step, total) { if (index >= total) { return; } const url = urls[index]; try { let blob = await fetchWithSpeedTracking(url); await saveBlob(table, m3u8IdHead + url, blob); blob = null; successCount++; videoTogetherExtension.downloadPercentage = Math.floor((successCount / totalCount) * 100) console.log('download ts:', table, index, 'of', total); } catch (e) { await new Promise(r => setTimeout(r, 2000)); failedUrls.push(url); console.error(e); } // Pick up the next work item await downloadWorker(table, urls, index + step, step, total); } async function downloadInParallel(table, urls, numThreads) { const total = urls.length; // Start numThreads download workers const promises = Array.from({ length: numThreads }, (_, i) => { return downloadWorker(table, urls, i, numThreads, total); }); await Promise.all(promises); if (failedUrls.length != 0) { urls = failedUrls; failedUrls = []; await downloadInParallel(table, urls, numThreads); } }})()//*/ } function isLimited() { while (lastRunQueue.length > 0 && lastRunQueue[0] timeLimitation) { console.error("limited") return true; } lastRunQueue.push(Date.now() / 1000); return false; } function getVideoTogetherStorage(key, defaultVal) { try { if (window.VideoTogetherStorage == undefined) { return defaultVal } else { if (window.VideoTogetherStorage[key] == undefined) { return defaultVal } else { return window.VideoTogetherStorage[key]; } } } catch { return defaultVal } } function getEnableTextMessage() { return getVideoTogetherStorage('EnableTextMessage', true); } function getEnableMiniBar() { return getVideoTogetherStorage('EnableMiniBar', true); } function skipIntroLen() { try { let len = parseInt(window.VideoTogetherStorage.SkipIntroLength); if (window.VideoTogetherStorage.SkipIntro && !isNaN(len)) { return len; } } catch { } return 0; } function isEmpty(s) { try { return s.length == 0; } catch { return true; } } function emptyStrIfUdf(s) { return s == undefined ? "" : s; } let isDownloadBlackListDomainCache = undefined; function isDownloadBlackListDomain() { if (window.location.protocol != 'http:' && window.location.protocol != 'https:') { return true; } const domains = [ 'iqiyi.com', 'qq.com', 'youku.com', 'bilibili.com', 'baidu.com', 'quark.cn', 'aliyundrive.com', "115.com", "acfun.cn", "youtube.com", ]; if (isDownloadBlackListDomainCache == undefined) { const hostname = window.location.hostname; isDownloadBlackListDomainCache = domains.some(domain => hostname === domain || hostname.endsWith(`.${domain}`)); } return isDownloadBlackListDomainCache; } let isEasyShareBlackListDomainCache = undefined; function isEasyShareBlackListDomain() { if (window.location.protocol != 'https:') { return true; } const domains = [ 'iqiyi.com', 'qq.com', 'youku.com', 'bilibili.com', 'baidu.com', 'quark.cn', 'aliyundrive.com', "115.com", "pornhub.com", "acfun.cn", "youtube.com", // -- "missav.com", "nivod4.tv" ]; if (isEasyShareBlackListDomainCache == undefined) { const hostname = window.location.hostname; isEasyShareBlackListDomainCache = domains.some(domain => hostname === domain || hostname.endsWith(`.${domain}`)); } return isEasyShareBlackListDomainCache; } function isEasyShareEnabled() { if (inDownload) { return false; } try { if (isWeb()) { return false; } if (isEasyShareBlackListDomain()) { return false; } return window.VideoTogetherEasyShare != 'disabled' && window.VideoTogetherStorage.EasyShare != false; } catch { return false; } } function isEasyShareMember() { try { return window.VideoTogetherEasyShareMemberSite == true; } catch { return false; } } function useMobileStyle(videoDom) { let isMobile = false; if (window.location.href.startsWith('https://m.bilibili.com/')) { isMobile = true; } if (!isMobile) { return; } document.body.childNodes.forEach(e => { try { if (e != videoDom && e.style && e.id != 'VideoTogetherWrapper') { e.style.display = 'none' } } catch { } }); videoDom.setAttribute('controls', true); videoDom.style.width = videoDom.style.height = "100%"; videoDom.style.maxWidth = videoDom.style.maxHeight = "100%"; videoDom.style.display = 'block'; if (videoDom.parentElement != document.body) { document.body.appendChild(videoDom); } } const mediaUrlsCache = {} function extractMediaUrls(m3u8Content, m3u8Url) { if (mediaUrlsCache[m3u8Url] == undefined) { let lines = m3u8Content.split("\n"); let mediaUrls = []; let base = undefined; try { base = new URL(m3u8Url); } catch { }; for (let i = 0; i `%${c.charCodeAt(0).toString(16).toUpperCase()}` ).replace(/%20/g, '+'); } function fixedDecodeURIComponent(str) { return decodeURIComponent(str.replace(/\+/g, ' ')); } function isWeb() { try { let type = window.VideoTogetherStorage.UserscriptType; return type == 'website' || type == 'website_debug'; } catch { return false; } } /** * @returns {Element} */ function select(query) { let e = window.videoTogetherFlyPannel.wrapper.querySelector(query); return e; } function hide(e) { if (e) e.style.display = 'none'; } function show(e) { if (e) e.style.display = null; } function isVideoLoadded(video) { try { if (isNaN(video.readyState)) { return true; } return video.readyState >= 3; } catch { return true; } } function isRoomProtected() { try { return window.VideoTogetherStorage == undefined || window.VideoTogetherStorage.PasswordProtectedRoom != false; } catch { return true; } } function changeBackground(url) { let e = select('.vt-modal-body'); if (e) { if (url == null || url == "") { e.style.backgroundImage = 'none'; } else if (e.style.backgroundImage != `url("${url}")`) { e.style.backgroundImage = `url("${url}")` } } } function changeMemberCount(c) { extension.ctxMemberCount = c; updateInnnerHTML(select('#memberCount'), String.fromCodePoint("0x1f465") + " " + c) } function dsply(e, _show = true) { _show ? show(e) : hide(e); } async function isAudioVolumeRO() { let a = new Audio(); a.volume = 0.5; return new Promise(r => setTimeout(() => { r(!(a.volume == 0.5)) }, 1)); } const Global = { inited: false, NativePostMessageFunction: null, NativeAttachShadow: null, NativeFetch: null } function AttachShadow(e, options) { try { return e.attachShadow(options); } catch (err) { GetNativeFunction(); return Global.NativeAttachShadow.call(e, options); } } function GetNativeFunction() { if (Global.inited) { return; } Global.inited = true; let temp = document.createElement("iframe"); hide(temp); document.body.append(temp); Global.NativePostMessageFunction = temp.contentWindow.postMessage; Global.NativeAttachShadow = temp.contentWindow.Element.prototype.attachShadow; Global.NativeFetch = temp.contentWindow.fetch; } function PostMessage(window, data) { if (/\{\s+\[native code\]/.test(Function.prototype.toString.call(window.postMessage))) { window.postMessage(data, "*"); } else { GetNativeFunction(); Global.NativePostMessageFunction.call(window, data, "*"); } } async function Fetch(url, init) { if (/\{\s+\[native code\]/.test(Function.prototype.toString.call(window.fetch))) { return await fetch(url, init); } else { GetNativeFunction(); return await Global.NativeFetch.call(window, url, init); } } function sendMessageToTop(type, data) { PostMessage(window.top, { source: "VideoTogether", type: type, data: data }); } function sendMessageToSelf(type, data) { PostMessage(window, { source: "VideoTogether", type: type, data: data }); } function sendMessageTo(w, type, data) { PostMessage(w, { source: "VideoTogether", type: type, data: data }); } function initRangeSlider(slider) { const min = slider.min const max = slider.max const value = slider.value slider.style.background = `linear-gradient(to right, #1abc9c 0%, #1abc9c ${(value - min) / (max - min) * 100}%, #d7dcdf ${(value - min) / (max - min) * 100}%, #d7dcdf 100%)` slider.addEventListener('input', function () { this.style.background = `linear-gradient(to right, #1abc9c 0%, #1abc9c ${(this.value - this.min) / (this.max - this.min) * 100}%, #d7dcdf ${(this.value - this.min) / (this.max - this.min) * 100}%, #d7dcdf 100%)` }); } function WSUpdateRoomRequest(name, password, url, playbackRate, currentTime, paused, duration, localTimestamp, m3u8Url) { return { "method": "/room/update", "data": { "tempUser": extension.tempUser, "password": password, "name": name, "playbackRate": playbackRate, "currentTime": currentTime, "paused": paused, "url": url, "lastUpdateClientTime": localTimestamp, "duration": duration, "protected": isRoomProtected(), "videoTitle": extension.isMain ? document.title : extension.videoTitle, "sendLocalTimestamp": Date.now() / 1000, "m3u8Url": m3u8Url } } } function WSJoinRoomRequest(name, password) { return { "method": "/room/join", "data": { "password": password, "name": name, } } } function WsUpdateMemberRequest(name, password, isLoadding, currentUrl) { return { "method": "/room/update_member", "data": { "password": password, "roomName": name, "sendLocalTimestamp": Date.now() / 1000, "userId": extension.tempUser, "isLoadding": isLoadding, "currentUrl": currentUrl } } } function popupError(msg) { let x = select("#snackbar"); updateInnnerHTML(x, msg); x.className = "show"; setTimeout(function () { x.className = x.className.replace("show", ""); }, 3000); let changeVoiceBtn = select('#changeVoiceBtn'); if (changeVoiceBtn != undefined) { changeVoiceBtn.onclick = () => { windowPannel.ShowTxtMsgTouchPannel(); } } } async function waitForRoomUuid(timeout = 10000) { return new Promise((res, rej) => { let id = setInterval(() => { if (roomUuid != null) { res(roomUuid); clearInterval(id); } }, 200) setTimeout(() => { clearInterval(id); rej(null); }, timeout); }); } class Room { constructor() { this.currentTime = null; this.duration = null; this.lastUpdateClientTime = null; this.lastUpdateServerTime = null; this.name = null; this.paused = null; this.playbackRate = null; this.protected = null; this.timestamp = null; this.url = null; this.videoTitle = null; this.waitForLoadding = null; } } const WS = { _socket: null, _lastConnectTime: 0, _connectTimeout: 10, _expriedTime: 5, _lastUpdateTime: 0, _lastErrorMessage: null, _lastRoom: new Room(), _connectedToService: false, isOpen() { try { return this._socket.readyState = 1 && this._connectedToService; } catch { return false; } }, async connect() { if (this._socket != null) { try { if (this._socket.readyState == 1) { return; } if (this._socket.readyState == 0 && this._lastConnectTime + this._connectTimeout > Date.now() / 1000) { return; } } catch { } } console.log('ws connect'); this._lastConnectTime = Date.now() / 1000 this._connectedToService = false; try { this.disconnect() this._socket = new WebSocket(`wss://${extension.video_together_host.replace("https://", "")}/ws?language=${language}`); this._socket.onmessage = async e => { let lines = e.data.split('\n'); for (let i = 0; i 0) { configuration.iceServers = res.data; configuration.iceTransportPolicy = 'relay'; } Voice.conn = new RTCPeerConnection(configuration); Voice.conn.onicecandidate = ({ candidate }) => { rpc('trickle', [rnameRPC, unameRPC, ucid, JSON.stringify(candidate)]); }; Voice.conn.ontrack = (event) => { console.log("ontrack", event); let stream = event.streams[0]; let sid = fixedDecodeURIComponent(stream.id); let id = sid.split(':')[0]; // var name = Base64.decode(sid.split(':')[1]); console.log(id, uid); if (id === uid) { return; } event.track.onmute = (event) => { console.log("onmute", event); }; let aid = 'peer-audio-' + id; let el = select('#' + aid); if (el) { el.srcObject = stream; } else { el = document.createElement(event.track.kind) el.id = aid; el.srcObject = stream; el.autoplay = true; el.controls = false; select('#peer').appendChild(el); } }; try { const constraints = { audio: { echoCancellation: cancellingNoise, noiseSuppression: cancellingNoise }, video: false }; Voice.stream = await navigator.mediaDevices.getUserMedia(constraints); } catch (err) { if (Voice.status == VoiceStatus.CONNECTTING) { Voice.errorMessage = "麦克风权限获取失败"; Voice.status = VoiceStatus.ERROR; } return; } Voice.stream.getTracks().forEach((track) => { track.enabled = !mutting; Voice.conn.addTrack(track, Voice.stream); }); await Voice.conn.setLocalDescription(await Voice.conn.createOffer()); res = await rpc('publish', [rnameRPC, unameRPC, JSON.stringify(Voice.conn.localDescription)]); if (res.data) { let jsep = JSON.parse(res.data.jsep); if (jsep.type == 'answer') { await Voice.conn.setRemoteDescription(jsep); ucid = res.data.track; await subscribe(Voice.conn); } } else { throw new Error('未知错误'); } Voice.conn.oniceconnectionstatechange = e => { if (Voice.conn.iceConnectionState == "disconnected" || Voice.conn.iceConnectionState == "failed" || Voice.conn.iceConnectionState == "closed") { Voice.errorMessage = "连接断开"; Voice.status = VoiceStatus.ERROR; } else { if (Voice.status == VoiceStatus.ERROR) { Voice.status = Voice._mutting ? VoiceStatus.MUTED : VoiceStatus.UNMUTED; } } } } async function rpc(method, params = [], retryTime = -1) { try { const response = await window.videoTogetherExtension.Fetch(extension.video_together_host + "/kraken", "POST", { id: generateUUID(), method: method, params: params }, { method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'omit', // include, *same-origin, omit headers: { 'Content-Type': 'application/json' }, redirect: 'follow', // manual, *follow, error referrerPolicy: 'no-referrer', // no-referrer, *client body: JSON.stringify({ id: generateUUID(), method: method, params: params }) // body data type must match "Content-Type" header }); return await response.json(); // parses JSON response into native JavaScript objects } catch (err) { if (Voice.status == VoiceStatus.STOP) { return; } if (retryTime == 0) { throw err; } await new Promise(r => setTimeout(r, 1000)); return await rpc(method, params, retryTime - 1); } } }, stop: () => { try { Voice.conn.getSenders().forEach(s => { if (s.track) { s.track.stop(); } }); } catch (e) { }; [...select('#peer').querySelectorAll("*")].forEach(e => e.remove()); try { Voice.conn.close(); delete Voice.conn; } catch { } try { Voice.stream.getTracks().forEach(function (track) { track.stop(); }); delete Voice.stream; } catch { } Voice.status = VoiceStatus.STOP; }, mute: () => { Voice.conn.getSenders().forEach(s => { if (s.track) { s.track.enabled = false; } }); Voice._mutting = true; Voice.status = VoiceStatus.MUTED; }, unmute: () => { Voice.conn.getSenders().forEach(s => { if (s.track) { s.track.enabled = true; } }); Voice._mutting = false; Voice.status = VoiceStatus.UNMUTED; }, updateVoiceSetting: async (cancellingNoise = false) => { const constraints = { audio: { echoCancellation: cancellingNoise, noiseSuppression: cancellingNoise }, video: false }; try { prevStream = Voice.stream; Voice.stream = await navigator.mediaDevices.getUserMedia(constraints); Voice.conn.getSenders().forEach(s => { if (s.track) { s.replaceTrack(Voice.stream.getTracks().find(t => t.kind == s.track.kind)); } }) prevStream.getTracks().forEach(t => t.stop()); delete prevStream; } catch (e) { console.log(e); }; } } function generateUUID() { if (crypto.randomUUID != undefined) { return crypto.randomUUID(); } return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } function generateTempUserId() { return generateUUID() + ":" + Date.now() / 1000; } /** * * Base64 encode / decode * http://www.webtoolkit.info * **/ const Base64 = { // private property _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" // public method for encoding , encode: function (input) { var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; input = Base64._utf8_encode(input); while (i > 2; enc2 = ((chr1 & 3) <> 4); enc3 = ((chr2 & 15) <> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); } // Whend return output; } // End Function encode // public method for decoding , decode: function (input) { var output = ""; var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0; input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); while (i < input.length) { enc1 = this._keyStr.indexOf(input.charAt(i++)); enc2 = this._keyStr.indexOf(input.charAt(i++)); enc3 = this._keyStr.indexOf(input.charAt(i++)); enc4 = this._keyStr.indexOf(input.charAt(i++)); chr1 = (enc1 <> 4); chr2 = ((enc2 & 15) <> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } } // Whend output = Base64._utf8_decode(output); return output; } // End Function decode // private method for UTF-8 encoding , _utf8_encode: function (string) { var utftext = ""; string = string.replace(/\r\n/g, "\n"); for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c 127) && (c > 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } // Next n return utftext; } // End Function _utf8_encode // private method for UTF-8 decoding , _utf8_decode: function (utftext) { var string = ""; var i = 0; var c, c1, c2, c3; c = c1 = c2 = 0; while (i < utftext.length) { c = utftext.charCodeAt(i); if (c 191) && (c < 224)) { c2 = utftext.charCodeAt(i + 1); string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); i += 2; } else { c2 = utftext.charCodeAt(i + 1); c3 = utftext.charCodeAt(i + 2); string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) < { if (getEnableMiniBar() && getEnableTextMessage() && document.fullscreenElement != undefined && (extension.ctxRole == extension.RoleEnum.Master || extension.ctxRole == extension.RoleEnum.Member)) { const qs = (s) => this.fullscreenWrapper.querySelector(s); try { qs("#memberCount").innerText = extension.ctxMemberCount; qs("#send-button").disabled = !extension.ctxWsIsOpen; } catch { }; if (document.fullscreenElement.contains(this.fullscreenSWrapper)) { return; } let shadowWrapper = document.createElement("div"); this.fullscreenSWrapper = shadowWrapper; shadowWrapper.id = "VideoTogetherfullscreenSWrapper"; let wrapper; try { wrapper = AttachShadow(shadowWrapper, { mode: "open" }); wrapper.addEventListener('keydown', (e) => e.stopPropagation()); this.fullscreenWrapper = wrapper; } catch (e) { console.error(e); } updateInnnerHTML(wrapper, ` < |
评分
-
参与人数 1 | 荣誉 +1 |
第纳尔 +100 |
互助 +2 |
收起
理由
|
别杀鸡
| + 1 |
+ 100 |
+ 2 |
文章不错,继续努力! |
查看全部评分
鲜花鸡蛋萧霆缘 在2024-6-24 23:12 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 SuperNinja 在2024-2-21 15:48 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 騎馬滅羅馬 在2023-9-12 23:23 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 SB_SRM 在2023-7-19 10:23 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下
|