feat(tools): 新版本工具链移植 + 本地镜像单包加载,中继改为原样直发与异步有序落盘
- hornet 工具链:无 ght 启动;透视冻结节点拖拽跟随、金箱标记、性能优化;雷达死亡红叉;鼠标稳定器;窗口布局持久化 - 本地镜像:切割与单包加载(pack_unpacked.js)+ SW 单包缓存 + F5 兜底刷新;入口更新为 main.9f4e7a89.js - 中继 wss_server.js:转发改 socket 反压的原样直发(零等待零缓存);落盘改单条有序异步队列(默认开启);新增反压看门狗(默认 60s)
This commit is contained in:
1 parent
2224ddc3f6
commit
4005213226
44 files changed
+122497
-114482
No files matched your search
@@ -0,0 +1,186 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
一键启动 3DTank 本地镜像(serve.js)+ 中继(wss_server.js relay 模式)
|
||||
|
||||
.DESCRIPTION
|
||||
- 本地镜像:把官方 web 客户端在 http://localhost:<MirrorPort>/ 跑起来
|
||||
· web/ 提供首页与镜像资源;/play/static/js/** 直接挂 3dtank.com 的切割版 JS
|
||||
· /config.xml 优先用 3DTank/local/config.xml(指向本地中继 9091),否则代理真实 config
|
||||
- 中继:客户端 → ws://localhost:<RelayPort>/ → 真实服务器(抓包落盘 + 实时解密/解析)
|
||||
· 产物目录:3DTank/packets/<label>/session_00N/
|
||||
- 依赖:中继需要 ws(Node 自带的是客户端 WebSocket,服务端不够用),脚本会自动装
|
||||
|
||||
.EXAMPLE
|
||||
// 最省事:装好依赖、起两个服务、打开浏览器
|
||||
powershell -ExecutionPolicy Bypass -File .\3DTank\Start-LocalAndRelay.ps1 -OpenBrowser
|
||||
|
||||
.EXAMPLE
|
||||
// 资源缺失(页面 404 很多)时先镜像资源再起(首次约 70MB)
|
||||
.\Start-LocalAndRelay.ps1 -FetchAssets -OpenBrowser
|
||||
|
||||
.EXAMPLE
|
||||
// 端口被上次残留占用时,先杀掉再起
|
||||
.\Start-LocalAndRelay.ps1 -KillExisting -OpenBrowser
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[int]$MirrorPort = 8080,
|
||||
[int]$RelayPort = 9091,
|
||||
[string]$Upstream = 'wss://c1.3dtank.com:9090/',
|
||||
[string]$Label = (Get-Date -Format 'yyyyMMdd-HHmmss'),
|
||||
[switch]$FetchAssets, # 先跑 fetch_assets.js 镜像资源(首次或资源缺失时用)
|
||||
[switch]$KillExisting, # 端口被占用时,先结束占用进程
|
||||
[switch]$OpenBrowser, # 启动后打开 http://localhost:<MirrorPort>/
|
||||
[switch]$WithRelay, # 启动本地中继(默认**不启动**:页面直连真实服务器 wss://c1.3dtank.com:9090/)
|
||||
[int]$DumpEvery = 1, # 中继:每 N 帧写一个 .bin(默认 1 = 每帧都写;0 = 不写抓包文件)
|
||||
[switch]$NoLog, # 中继:不写 log.txt(默认写)
|
||||
[switch]$NoHex, # 中继:log.txt 不写十六进制(日志体积大幅减小)
|
||||
[switch]$Quiet # 中继:只写 log.txt,不刷控制台
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$Project = $PSScriptRoot # 3DTank/
|
||||
$Tools = Join-Path $Project 'tools'
|
||||
$PacketDir = Join-Path $Project ("packets\{0}" -f $Label)
|
||||
|
||||
# ---------- 小工具 ----------
|
||||
function Get-CmdPath([string]$Name) {
|
||||
$c = Get-Command $Name -ErrorAction SilentlyContinue
|
||||
if (-not $c) { throw "找不到命令 '$Name',请先安装 Node.js(自带 npm)并加入 PATH" }
|
||||
return $c.Source
|
||||
}
|
||||
|
||||
function Test-PortFree([int]$Port) {
|
||||
$client = New-Object System.Net.Sockets.TcpClient
|
||||
try {
|
||||
$client.Connect('127.0.0.1', $Port)
|
||||
return $false # 连上了 = 已被占用
|
||||
} catch {
|
||||
return $true # 连不上 = 空闲
|
||||
} finally {
|
||||
try { $client.Close() } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-PortPid([int]$Port) {
|
||||
try {
|
||||
return (Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction Stop |
|
||||
Select-Object -First 1 -ExpandProperty OwningProcess)
|
||||
} catch { return $null }
|
||||
}
|
||||
|
||||
function Assert-PortReady([int]$Port, [string]$What) {
|
||||
if (Test-PortFree $Port) { return }
|
||||
if ($KillExisting) {
|
||||
# 注意:$pid 是 PowerShell 只读自动变量(当前进程),不能用来存占用者 PID
|
||||
$OwnerPid = Get-PortPid $Port
|
||||
if ($OwnerPid) {
|
||||
Write-Host ("[端口] {0} 被 PID={1} 占用,按 -KillExisting 结束它" -f $Port, $OwnerPid) -ForegroundColor Yellow
|
||||
Stop-Process -Id $OwnerPid -Force -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
}
|
||||
if (-not (Test-PortFree $Port)) { throw "端口 $Port 已被占用($What)。用 -KillExisting 或换端口" }
|
||||
}
|
||||
|
||||
function Test-TcpOpen([string]$HostName, [int]$Port, [int]$TimeoutMs = 2500) {
|
||||
$client = New-Object System.Net.Sockets.TcpClient
|
||||
try {
|
||||
$task = $client.ConnectAsync($HostName, $Port)
|
||||
if (-not $task.Wait($TimeoutMs)) { return $false }
|
||||
return $client.Connected
|
||||
} catch {
|
||||
return $false
|
||||
} finally {
|
||||
try { $client.Close() } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
# ---------- 0) 环境 ----------
|
||||
$NodeExe = Get-CmdPath 'node'
|
||||
$NpmExe = Get-CmdPath 'npm'
|
||||
Write-Host ("[环境] node={0} npm={1}" -f (& $NodeExe -v), (& $NpmExe -v)) -ForegroundColor DarkGray
|
||||
|
||||
# ---------- 1) 依赖:中继需要 ws(服务端) ----------
|
||||
$WsPackage = Join-Path $Tools 'node_modules\ws\package.json'
|
||||
if (-not (Test-Path $WsPackage)) {
|
||||
Write-Host '[依赖] 安装 ws 到 3DTank/tools ...' -ForegroundColor Cyan
|
||||
Push-Location $Tools
|
||||
try { & $NpmExe install --no-save ws | Out-Host } finally { Pop-Location }
|
||||
}
|
||||
if (-not (Test-Path $WsPackage)) { throw 'ws 安装失败(检查网络/代理)' }
|
||||
|
||||
# ---------- 2) 端口 ----------
|
||||
Assert-PortReady $RelayPort '中继 wss_server.js'
|
||||
Assert-PortReady $MirrorPort '本地镜像 serve.js'
|
||||
|
||||
# ---------- 3) 可选:镜像资源 ----------
|
||||
if ($FetchAssets) {
|
||||
Write-Host '[资源] fetch_assets.js 镜像资源(首次约 70MB,请耐心等)...' -ForegroundColor Cyan
|
||||
Push-Location $Tools
|
||||
try { & $NodeExe fetch_assets.js --concurrency 10 | Out-Host } finally { Pop-Location }
|
||||
}
|
||||
|
||||
# ---------- 3.5) 生成单包(unpacked.pack.json):126 个小文件 → 1 个包 ----------
|
||||
$PackScript = Join-Path (Split-Path -Parent $Project) 'tools\pack_unpacked.js'
|
||||
if (Test-Path $PackScript) {
|
||||
Write-Host '[打包] pack_unpacked.js 生成单包(unpacked.pack.json)...' -ForegroundColor Cyan
|
||||
try { & $NodeExe $PackScript | Out-Host } catch { Write-Warning ('打包失败: ' + $_.Exception.Message) }
|
||||
} else {
|
||||
Write-Warning ('未找到 ' + $PackScript + ',跳过单包(将逐文件加载)')
|
||||
}
|
||||
|
||||
# ---------- 4) 中继(可选;默认不启动 —— 页面直连真实服务器) ----------
|
||||
$RelayProc = $null
|
||||
if ($WithRelay) {
|
||||
Write-Host ("[中继] wss_server.js relay ws://localhost:{0}/ -> {1}" -f $RelayPort, $Upstream) -ForegroundColor Green
|
||||
$RelayArgs = @('wss_server.js', '--port', "$RelayPort", '--upstream', $Upstream, '--label', $Label, '--dump-every', "$DumpEvery")
|
||||
if (-not $NoLog) { $RelayArgs += @('--log', '1') }
|
||||
if ($NoHex) { $RelayArgs += @('--no-hex', '1') }
|
||||
if ($Quiet) { $RelayArgs += @('--quiet', '1') }
|
||||
# 用 cmd /k 启动:进程退出(含崩溃)后窗口不关闭,堆栈能直接看到("崩溃后 pause")
|
||||
$RelayProc = Start-Process -FilePath 'cmd.exe' `
|
||||
-ArgumentList (@('/k', 'node') + $RelayArgs) `
|
||||
-WorkingDirectory $Tools -PassThru
|
||||
} else {
|
||||
Write-Host '[中继] 已跳过(默认直连真实服务器;要中继/抓包请加 -WithRelay)' -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
# ---------- 5) 启动本地镜像 ----------
|
||||
# 默认加 --real-config:/config.xml 取真实站点,游戏因此直连 wss://c1.3dtank.com:9090/
|
||||
# 走中继(-WithRelay)时不加它,改用 local/config.xml 把客户端指向本机 127.0.0.1:<RelayPort>
|
||||
$MirrorArgs = @('serve.js', '--port', "$MirrorPort")
|
||||
if (-not $WithRelay) { $MirrorArgs += '--real-config' }
|
||||
Write-Host ("[镜像] serve.js http://localhost:{0}/ {1}" -f $MirrorPort, ($(if ($WithRelay) {'(config → 本地中继)'} else {'(config → 真实服务器,直连)'}))) -ForegroundColor Green
|
||||
$MirrorProc = Start-Process -FilePath 'cmd.exe' `
|
||||
-ArgumentList (@('/k', 'node') + $MirrorArgs) `
|
||||
-WorkingDirectory $Tools -PassThru
|
||||
|
||||
# ---------- 6) 健康检查 ----------
|
||||
Start-Sleep -Milliseconds 1200
|
||||
$RelayOk = if ($WithRelay) { Test-TcpOpen '127.0.0.1' $RelayPort } else { $null }
|
||||
$MirrorOk = Test-TcpOpen '127.0.0.1' $MirrorPort
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '================= 已启动 =================' -ForegroundColor Yellow
|
||||
Write-Host ("浏览器打开 : http://localhost:{0}/" -f $MirrorPort) -ForegroundColor White
|
||||
Write-Host ("工具链 : 默认已注入(纯净页 http://localhost:{0}/#nohornet);切勿加查询参数 ?xxx —— 会被游戏当成 config 参数,导致握手失败 1005" -f $MirrorPort) -ForegroundColor White
|
||||
if ($WithRelay) {
|
||||
Write-Host ("连接路径 : 页面 → ws://localhost:{0}/ (中继)→ {1}" -f $RelayPort, $Upstream) -ForegroundColor White
|
||||
$DiskInfo = if ($DumpEvery -gt 0 -or -not $NoLog) { "dump-every=$DumpEvery log=$(if ($NoLog) {'off'} else {'on'}) hex=$(if ($NoHex) {'off'} else {'on'})" } else { '不落盘(只转发 + 实时解析)' }
|
||||
Write-Host ("抓包目录 : {0} (仅落盘时使用)" -f $PacketDir) -ForegroundColor White
|
||||
Write-Host ("落盘策略 : {0} (默认落盘保存;不落盘加 -DumpEvery 0 -NoLog)" -f $DiskInfo) -ForegroundColor White
|
||||
Write-Host ("进程 : 中继 PID={0} 镜像 PID={1}" -f $RelayProc.Id, $MirrorProc.Id) -ForegroundColor White
|
||||
Write-Host ("自检 : 中继={0} 镜像={1}" -f ($(if ($RelayOk) {'OK'} else {'未监听'})), ($(if ($MirrorOk) {'OK'} else {'未监听'}))) -ForegroundColor White
|
||||
} else {
|
||||
Write-Host '连接路径 : 页面 → config 取自真实站点 → 直连 wss://c1.3dtank.com:9090/(未启动中继)' -ForegroundColor White
|
||||
Write-Host ("进程 : 镜像 PID={0}" -f $MirrorProc.Id) -ForegroundColor White
|
||||
Write-Host ("自检 : 镜像={0}" -f ($(if ($MirrorOk) {'OK'} else {'未监听'}))) -ForegroundColor White
|
||||
}
|
||||
Write-Host '停止 : 关掉 node 窗口,或 Stop-Process -Id <PID>' -ForegroundColor DarkGray
|
||||
Write-Host '=========================================' -ForegroundColor Yellow
|
||||
|
||||
if ($WithRelay -and -not $RelayOk) { Write-Warning '中继未监听,查看它的 node 窗口报错(常见:ws 未装上/端口被占)' }
|
||||
if (-not $MirrorOk) { Write-Warning '本地镜像未监听,查看它的 node 窗口报错' }
|
||||
|
||||
if ($OpenBrowser -and $MirrorOk) { Start-Process ("http://localhost:{0}/" -f $MirrorPort) }
|
||||
@@ -1,2 +1,2 @@
|
||||
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.Launcher=n():t.Launcher=n()}(globalThis,()=>(()=>{var __webpack_modules__={17:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/31.2d481c05.webp"},146:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/neutral-g.38b68a23.svg"},164:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/gold.e0b82d44.svg"},214:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/btnBarrelUp.300e56c4.svg"},349:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/armor.d6fc6ef4.svg"},405:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/08.6a9e421e.webp"},410:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/speedIcon.3aaad0d9.svg"},430:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/18.0fcfcee7.webp"},465:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/stabilized_lightning.5b5469d1.svg"},806:(t,n,i)=>{"use strict";var r=i(19487),e={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},u={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},s={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},o={};function _(t){return r.isMemo(t)?s:o[t.$$typeof]||e}o[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},o[r.Memo]=s;var a=Object.defineProperty,h=Object.getOwnPropertyNames,c=Object.getOwnPropertySymbols,l=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,v=Object.prototype;t.exports=function t(n,i,r){if("string"!=typeof i){if(v){var e=f(i);e&&e!==v&&t(n,e,r)}var s=h(i);c&&(s=s.concat(c(i)));for(var o=_(n),w=_(i),p=0;p<s.length;++p){var d=s[p];if(!(u[d]||r&&r[d]||w&&w[d]||o&&o[d])){var g=l(i,d);try{a(n,d,g)}catch(t){}}}}return n}},894:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/05.4baa68b2.webp"},899:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/13.0ad436cb.webp"},905:t=>{"use strict";t.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},906:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/Gauss.da869a90.svg"},909:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/contract.90d7cd8f.svg"},911:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/neutral-b.678833d3.svg"},964:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/unavailable.5c3ecd75.svg"},1039:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/armor.960e021b.svg"},1042:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/freeze_resistance.33bdf642.svg"},1067:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/battle_main_pick_match.f9aabe76.webp"},1076:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/bgSecondaryButton.d770f6f8.svg"},1127:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/overdrive.c8de54da.svg"},1153:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/overheat.89c0e772.svg"},1196:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/ctf_blue_base_no_flag.94a2bf33.svg"},1254:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/Smoky.a2623c59.svg"},1257:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/rgb_blue_delivering.6c8a284b.svg"},1311:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/lock.301e2c47.svg"},1461:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/claimAllButton.b9e9611f.webp"},1498:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/revolver.3f7f2a0e.svg"},1502:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/25.60b5ac7d.webp"},1507:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/22.39ef9ff5.webp"},1510:(t,n,i)=>{!function(t,n,i,r,e){"use strict";var u,s,o,_,a,h,c,l,f,v,w,p,d,g,m,y,k=n.$_$.nb,b=n.$_$.w4,q=i.$_$.e,$=n.$_$.ge,j=n.$_$.vj,x=n.$_$.h5,z=n.$_$.o1,S=n.$_$.fd,C=i.$_$.d,E=n.$_$.r5,T=n.$_$.td,I=i.$_$.f,A=n.$_$.mf,R=r.$_$.s1,P=e.$_$.n,N=n.$_$.qf,O=n.$_$.cd,M=n.$_$.qj,D=i.$_$.r,L=i.$_$.b,B=e.$_$.f,U=n.$_$.xb,F=n.$_$.c,G=e.$_$.f1,H=n.$_$.fe,W=e.$_$.l,V=n.$_$.lj,K=n.$_$.je;function Y(t){var n=t.zur_1;if(null!=n)return n;k("codec_appId")}function X(){}function J(){}function Z(t){var n=t.cus_1;if(null!=n)return n;k("codec_questToAchievementMap")}function Q(){}function tt(t){var n=t.fus_1;if(null!=n)return n;k("codec_itemIdMap")}function nt(){}function it(){this.ius_1=new R(A(I),null),this.jus_1=new R(A(P),null)}function rt(){B.call(this),this.nus_1=new R(A(I),null),this.ous_1=new R(A(P),null),this.qus_1=new M(-621796162,1132145095),this.rus_1=new M(1635469714,1785333818),this.sus_1=new M(-773564903,1989636776),this.tus_1=new M(497901439,366177258),this.taw(),this.uus_1=this.qus_1}function et(t){var n=N;return t.xus_1.e2b(t,O("protocol",1,n,function(t){return et(t)},null))}function ut(){this.xus_1=new R(A(I),null),this.zus_1=new M(-1272608814,1097348888)}function st(){return t=H($(ot)),ot.call(t),t;var t}function ot(){}function _t(t){var n=N;return t.fut_1.e2b(t,O("protocol",1,n,function(t){return _t(t)},null))}funcLine truncated
|
||||
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.Launcher=n():t.Launcher=n()}(globalThis,()=>(()=>{var __webpack_modules__={17:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/31.2d481c05.webp"},146:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/neutral-g.38b68a23.svg"},164:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/gold.e0b82d44.svg"},214:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/btnBarrelUp.300e56c4.svg"},349:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/armor.d6fc6ef4.svg"},405:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/08.6a9e421e.webp"},410:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/speedIcon.3aaad0d9.svg"},430:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/18.0fcfcee7.webp"},465:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/stabilized_lightning.5b5469d1.svg"},806:(t,n,i)=>{"use strict";var r=i(19487),e={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},u={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},s={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},o={};function _(t){return r.isMemo(t)?s:o[t.$$typeof]||e}o[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},o[r.Memo]=s;var a=Object.defineProperty,h=Object.getOwnPropertyNames,c=Object.getOwnPropertySymbols,l=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,v=Object.prototype;t.exports=function t(n,i,r){if("string"!=typeof i){if(v){var e=f(i);e&&e!==v&&t(n,e,r)}var s=h(i);c&&(s=s.concat(c(i)));for(var o=_(n),w=_(i),p=0;p<s.length;++p){var d=s[p];if(!(u[d]||r&&r[d]||w&&w[d]||o&&o[d])){var g=l(i,d);try{a(n,d,g)}catch(t){}}}}return n}},894:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/05.4baa68b2.webp"},899:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/13.0ad436cb.webp"},905:t=>{"use strict";t.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},906:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/Gauss.da869a90.svg"},909:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/contract.90d7cd8f.svg"},911:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/neutral-b.678833d3.svg"},964:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/unavailable.5c3ecd75.svg"},1039:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/armor.960e021b.svg"},1042:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/freeze_resistance.33bdf642.svg"},1067:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/battle_main_pick_match.f9aabe76.webp"},1076:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/bgSecondaryButton.d770f6f8.svg"},1127:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/overdrive.c8de54da.svg"},1153:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/overheat.89c0e772.svg"},1196:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/ctf_blue_base_no_flag.94a2bf33.svg"},1254:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/Smoky.a2623c59.svg"},1257:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/rgb_blue_delivering.6c8a284b.svg"},1311:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/lock.301e2c47.svg"},1461:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/claimAllButton.b9e9611f.webp"},1498:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/revolver.3f7f2a0e.svg"},1502:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/25.60b5ac7d.webp"},1507:(t,n,i)=>{"use strict";t.exports=i.p+"static/images/22.39ef9ff5.webp"},1510:(t,n,i)=>{!function(t,n,i,r,e){"use strict";var u,s,o,_,a,h,c,l,f,v,w,p,d,g,m,y,k=n.$_$.nb,b=n.$_$.w4,q=i.$_$.e,$=n.$_$.ge,j=n.$_$.vj,x=n.$_$.h5,z=n.$_$.o1,S=n.$_$.fd,C=i.$_$.d,E=n.$_$.r5,T=n.$_$.td,I=i.$_$.f,A=n.$_$.mf,R=r.$_$.s1,P=e.$_$.n,N=n.$_$.qf,O=n.$_$.cd,M=n.$_$.qj,D=i.$_$.r,L=i.$_$.b,B=e.$_$.f,U=n.$_$.xb,F=n.$_$.c,G=e.$_$.f1,H=n.$_$.fe,W=e.$_$.l,V=n.$_$.lj,K=n.$_$.je;function Y(t){var n=t.zur_1;if(null!=n)return n;k("codec_appId")}function X(){}function J(){}function Z(t){var n=t.cus_1;if(null!=n)return n;k("codec_questToAchievementMap")}function Q(){}function tt(t){var n=t.fus_1;if(null!=n)return n;k("codec_itemIdMap")}function nt(){}function it(){this.ius_1=new R(A(I),null),this.jus_1=new R(A(P),null)}function rt(){B.call(this),this.nus_1=new R(A(I),null),this.ous_1=new R(A(P),null),this.qus_1=new M(-621796162,1132145095),this.rus_1=new M(1635469714,1785333818),this.sus_1=new M(-773564903,1989636776),this.tus_1=new M(497901439,366177258),this.taw(),this.uus_1=this.qus_1}function et(t){var n=N;return t.xus_1.e2b(t,O("protocol",1,n,function(t){return et(t)},null))}function ut(){this.xus_1=new R(A(I),null),this.zus_1=new M(-1272608814,1097348888)}function st(){return t=H($(ot)),ot.call(t),t;var t}function ot(){}function _t(t){var n=N;return t.fut_1.e2b(t,O("protocol",1,n,function(t){return _t(t)},null))}funcLine truncated
|
||||
//# sourceMappingURL=main.6469b966.js.map
|
||||
+4590
-135
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"GeneratedAt": "2026-09-16T15:20:29.988Z",
|
||||
"GeneratedAt": "2026-09-18T00:46:01.327Z",
|
||||
"In": "D:\\Users\\TermiNexus\\Desktop\\TankIC\\3DTank\\src",
|
||||
"Out": "D:\\Users\\TermiNexus\\Desktop\\TankIC\\3DTank\\src_named",
|
||||
"DryRun": false,
|
||||
@@ -7,6 +7,7 @@
|
||||
"ModuleCount": 126,
|
||||
"OtherFilesCopied": [
|
||||
"index.json",
|
||||
"module_92980.js.txt",
|
||||
"resources.json"
|
||||
],
|
||||
"Note": [
|
||||
@@ -19,6 +20,11 @@
|
||||
"命令字段(uplink_table 的 555 条负载槽位)在源码里没有保留可读名,全部计入证据缺失。",
|
||||
"闭包名 / 数据类名用与 mine_evidence.js 同源但更抗格式化的 AST 规则重新推导,并与证据交叉核对(见 Recheck)。",
|
||||
" 证据里的条目必须 100% 被 AST 复现(*EvidenceMissed 应为空);AST 反向多出来的只是同一模式的漏配(如 prettier 换行导致正则抓不到)。",
|
||||
"【类注册名】<别名>(<构造器短名>, \"<真名>\", …),别名 = <运行时命名空间>.$_$.{fd|kd|id}。",
|
||||
" 只认经 module_37036 源码证明「第 2 实参是名字」的 fd(class) / kd(object) / id(interface);",
|
||||
" 同族导出 gd(=ee→\"Companion\") / jd(=re→\"Lambda\") / hd(内联 Qr→\"Coroutine\") 的第 2 实参写死,已排除。",
|
||||
" 该通道优先级低于「数据类名」:同短名两通道一致时由「数据类名」应用(见 ClassRegistrationsSameAsDataClass),",
|
||||
" 不一致时记 Conflict 跳过;空串不是名字,一律丢弃。",
|
||||
"【派生命名】只有 --aliases 打开时才回填;来自 command_alias.json,是「读源码证实语义后起的别名」而非原始名,单独记在 Aliases 段,不计入上面的证据改名统计。"
|
||||
],
|
||||
"Renamed": {
|
||||
@@ -118,6 +124,102 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"类注册名": {
|
||||
"Entries": 585,
|
||||
"Edits": 6516,
|
||||
"Examples": [
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Fr",
|
||||
"Long": "SerializationStrategy",
|
||||
"Count": 7
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Gr",
|
||||
"Long": "DeserializationStrategy",
|
||||
"Count": 4
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Ur",
|
||||
"Long": "KSerializer",
|
||||
"Count": 55
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "mu",
|
||||
"Long": "AbstractPolymorphicSerializer",
|
||||
"Count": 11
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Vr",
|
||||
"Long": "PolymorphicSerializer",
|
||||
"Count": 9
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Kr",
|
||||
"Long": "SealedClassSerializer",
|
||||
"Count": 4
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "xe",
|
||||
"Long": "SerialDescriptor",
|
||||
"Count": 12
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Ae",
|
||||
"Long": "ClassSerialDescriptorBuilder",
|
||||
"Count": 6
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "ju",
|
||||
"Long": "CachedNames",
|
||||
"Count": 6
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Pe",
|
||||
"Long": "SerialDescriptorImpl",
|
||||
"Count": 20
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Fe",
|
||||
"Long": "SerialKind",
|
||||
"Count": 14
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "De",
|
||||
"Long": "ENUM",
|
||||
"Count": 4
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Be",
|
||||
"Long": "CONTEXTUAL",
|
||||
"Count": 3
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "We",
|
||||
"Long": "PolymorphicKind",
|
||||
"Count": 7
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "Ge",
|
||||
"Long": "SEALED",
|
||||
"Count": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"闭包名": {
|
||||
"Entries": 0,
|
||||
"Edits": 0,
|
||||
@@ -712,6 +814,12 @@
|
||||
"Whitelist": 4,
|
||||
"MissingEvidence": 0
|
||||
},
|
||||
"类注册名": {
|
||||
"Conflict": 77,
|
||||
"InStringLiteral": 48,
|
||||
"Whitelist": 3,
|
||||
"MissingEvidence": 0
|
||||
},
|
||||
"闭包名": {
|
||||
"Conflict": 55,
|
||||
"InStringLiteral": 46,
|
||||
@@ -1234,6 +1342,136 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"类注册名|Conflict": {
|
||||
"Count": 77,
|
||||
"Examples": [
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "SerializationException",
|
||||
"Long": "SerializationException",
|
||||
"Detail": "目标名与短名相同"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "UnknownFieldException",
|
||||
"Long": "UnknownFieldException",
|
||||
"Detail": "目标名与短名相同"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "MissingFieldException",
|
||||
"Long": "MissingFieldException",
|
||||
"Detail": "目标名与短名相同"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "io",
|
||||
"Long": "PrimitiveSerialDescriptor",
|
||||
"Detail": "与「数据类名」通道的 PrimitiveDescriptor 不一致"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "Yn",
|
||||
"Long": "AttributeEnum",
|
||||
"Detail": "全模块有 2 处同名绑定(存在遮蔽),改名无法保证一致"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "Jn",
|
||||
"Long": "Attribute",
|
||||
"Detail": "全模块有 2 处同名绑定(存在遮蔽),改名无法保证一致"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "Zn",
|
||||
"Long": "StringAttribute",
|
||||
"Detail": "全模块有 2 处同名绑定(存在遮蔽),改名无法保证一致"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "Qn",
|
||||
"Long": "StringSetAttribute",
|
||||
"Detail": "全模块有 2 处同名绑定(存在遮蔽),改名无法保证一致"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "ti",
|
||||
"Long": "BooleanAttribute",
|
||||
"Detail": "全模块有 2 处同名绑定(存在遮蔽),改名无法保证一致"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "ni",
|
||||
"Long": "TickerAttribute",
|
||||
"Detail": "全模块有 2 处同名绑定(存在遮蔽),改名无法保证一致"
|
||||
}
|
||||
]
|
||||
},
|
||||
"类注册名|InStringLiteral": {
|
||||
"Count": 48,
|
||||
"Examples": [
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "ru",
|
||||
"Long": "PrimitiveKind",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "gu",
|
||||
"Long": "CompositeEncoder",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "ws",
|
||||
"Long": "PluginGeneratedSerialDescriptor",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "gs",
|
||||
"Long": "GeneratedSerializer",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "is",
|
||||
"Long": "NoOpEncoder",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "es",
|
||||
"Long": "NothingSerialDescriptor",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "us",
|
||||
"Long": "NullableSerializer",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "ss",
|
||||
"Long": "SerialDescriptorForNullable",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "os",
|
||||
"Long": "ObjectSerializer",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "ms",
|
||||
"Long": "SerializerFactory",
|
||||
"Detail": "短名出现在字符串字面量里"
|
||||
}
|
||||
]
|
||||
},
|
||||
"数据类名|Conflict": {
|
||||
"Count": 367,
|
||||
"Examples": [
|
||||
@@ -1357,6 +1595,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"类注册名|Whitelist": {
|
||||
"Count": 3,
|
||||
"Examples": [
|
||||
{
|
||||
"Module": "63383",
|
||||
"Short": "Xs",
|
||||
"Long": "Image",
|
||||
"Detail": "目标名命中白名单:宿主/内置 API 名"
|
||||
},
|
||||
{
|
||||
"Module": "82347",
|
||||
"Short": "d3",
|
||||
"Long": "BattleFinishStyle",
|
||||
"Detail": "短名命中白名单:Kotlin/JS 运行时关键名"
|
||||
},
|
||||
{
|
||||
"Module": "89613",
|
||||
"Short": "xr",
|
||||
"Long": "Symbol",
|
||||
"Detail": "目标名命中白名单:宿主/内置 API 名"
|
||||
}
|
||||
]
|
||||
},
|
||||
"闭包名|Whitelist": {
|
||||
"Count": 1,
|
||||
"Examples": [
|
||||
@@ -1567,10 +1828,94 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"ClassRegistrationsSameAsDataClass": {
|
||||
"Count": 16,
|
||||
"Examples": [
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "je",
|
||||
"Long": "ContextDescriptor"
|
||||
},
|
||||
{
|
||||
"Module": "9539",
|
||||
"Short": "fo",
|
||||
"Long": "MapEntry"
|
||||
},
|
||||
{
|
||||
"Module": "24923",
|
||||
"Short": "cn",
|
||||
"Long": "UsedCssInfo"
|
||||
},
|
||||
{
|
||||
"Module": "24923",
|
||||
"Short": "ln",
|
||||
"Long": "CssInfo"
|
||||
},
|
||||
{
|
||||
"Module": "24923",
|
||||
"Short": "gn",
|
||||
"Long": "MemoizedResult"
|
||||
},
|
||||
{
|
||||
"Module": "24923",
|
||||
"Short": "Un",
|
||||
"Long": "RulesGroup"
|
||||
},
|
||||
{
|
||||
"Module": "59131",
|
||||
"Short": "Kn",
|
||||
"Long": "SingletonStringMap"
|
||||
},
|
||||
{
|
||||
"Module": "61430",
|
||||
"Short": "or",
|
||||
"Long": "JsonConfiguration"
|
||||
},
|
||||
{
|
||||
"Module": "63383",
|
||||
"Short": "rs",
|
||||
"Long": "RGBA"
|
||||
},
|
||||
{
|
||||
"Module": "63383",
|
||||
"Short": "es",
|
||||
"Long": "HSLA"
|
||||
},
|
||||
{
|
||||
"Module": "63383",
|
||||
"Short": "Cs",
|
||||
"Long": "Margin"
|
||||
},
|
||||
{
|
||||
"Module": "63383",
|
||||
"Short": "Es",
|
||||
"Long": "Padding"
|
||||
},
|
||||
{
|
||||
"Module": "63383",
|
||||
"Short": "Ts",
|
||||
"Long": "Rule"
|
||||
},
|
||||
{
|
||||
"Module": "89613",
|
||||
"Short": "Bn",
|
||||
"Long": "CompletedContinuation"
|
||||
},
|
||||
{
|
||||
"Module": "92980",
|
||||
"Short": "rz",
|
||||
"Long": "ImGUIStyle"
|
||||
}
|
||||
],
|
||||
"Note": "「类注册名」与「数据类名」给出同一个名字:按优先级由「数据类名」通道决定是否应用,本通道不重复改名"
|
||||
},
|
||||
"Recheck": {
|
||||
"ClassNamesEvidence": 921,
|
||||
"ClassNamesFromAst": 1559,
|
||||
"ClassNamesEvidenceMissed": [],
|
||||
"ClassRegistrationsEvidence": 729,
|
||||
"ClassRegistrationsFromAst": 729,
|
||||
"ClassRegistrationsEvidenceMissed": [],
|
||||
"ClosuresEvidence": 477,
|
||||
"ClosuresFromAst": 829,
|
||||
"ClosuresEvidenceMissed": [],
|
||||
|
||||
+142
-3
@@ -169,6 +169,43 @@ function StringTokenList(Text) {
|
||||
|
||||
const ParseSrc = (Text) => Acorn.parse(Text, { ecmaVersion: 'latest', sourceType: 'script', allowReturnOutsideFunction: true });
|
||||
|
||||
// ---------------------------------------------------------------- 类注册名通道
|
||||
// 依据 src/module_37036.js 源码(导出表在 10148~10155 行):
|
||||
// Zr(t, n, i, r, e, u) 造 $metadata$,其中 simpleName 取第 2 实参
|
||||
// te(kind, ctor, simpleName, …) 把 Zr 的结果挂到 ctor.$metadata$ 上
|
||||
// Qr(t, n, …) → te("class", t, n, …) ⇒ Qr 的第 2 实参 = 名字(class)
|
||||
// ne(t, n, …) → te("object", t, n, …) ⇒ ne 的第 2 实参 = 名字(object)
|
||||
// ie(t, n, …) → te("interface", t, n, …) ⇒ ie 的第 2 实参 = 名字(interface)
|
||||
// 导出表证明:t.$_$.fd = Qr、t.$_$.kd = ne、t.$_$.id = ie。
|
||||
// ⇒ 只有 fd / kd / id 这 3 个导出的「第 2 实参」是名字,其余同族导出必须排除:
|
||||
// · t.$_$.gd = ee :ee(t, n, i, r) 调 ne(t, "Companion", E, n, i, r, …),
|
||||
// 第 2 实参写死为 "Companion",形参 n 落到了 defaultConstructor 位(第 4 实参);
|
||||
// · t.$_$.jd = re :re(t, n, i, r) 调 Qr(t, "Lambda", E, n, i, r, …),同上,n 落到第 4 实参位;
|
||||
// · t.$_$.hd = function (t, n, i, r) { Qr(t, "Coroutine", E, n, i, r, E, E) },
|
||||
// 第 2 实参写死为 "Coroutine",形参 n 落到 Qr 的第 4 实参位。
|
||||
// 调用点形态:<别名>(<构造器短名>, "<真名>", …),别名由 `Local = <运行时命名空间>.$_$.<fd|kd|id>` 引入。
|
||||
const RegHelperKind = { fd: 'class', kd: 'object', id: 'interface' };
|
||||
const RUNTIME_MODULE = 37036;
|
||||
|
||||
// 模块 IIFE 里绑定到 module_37036 的形参名(导出表所在模块的命名空间)
|
||||
// 形态:!(function (a, b, c, …) { … })(t.exports, i(37036), i(32088), …);
|
||||
function RuntimeNamespaceNames(Ast) {
|
||||
const Out = new Set();
|
||||
WalkWithParent(Ast, null, (Node) => {
|
||||
if (Node.type !== 'CallExpression' || !Node.arguments || !Node.arguments.length) return;
|
||||
if (!IsFnNode(Node.callee) || !Node.callee.params) return;
|
||||
for (let I = 0; I < Node.arguments.length; I++) {
|
||||
const A = Node.arguments[I];
|
||||
if (A.type !== 'CallExpression' || !IdentOf(A.callee) || A.arguments.length !== 1) continue;
|
||||
const Lit = A.arguments[0];
|
||||
if (Lit.type !== 'Literal' || Lit.value !== RUNTIME_MODULE) continue;
|
||||
const P = Node.callee.params[I];
|
||||
if (P && P.type === 'Identifier') Out.add(P.name);
|
||||
}
|
||||
});
|
||||
return Out;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- 单模块扫描
|
||||
// 一次遍历同时得到:属性位名字 / 值位名字 / 简写属性 / 绑定表 / 闭包原名 / 数据类名 / 枚举三元组
|
||||
function ScanModule(Text, Ast) {
|
||||
@@ -180,6 +217,7 @@ function ScanModule(Text, Ast) {
|
||||
Bindings: NewTable(),
|
||||
Closures: NewTable(), // 短名 → Set(callableName)(AST 版,比 mine_evidence 的正则更全)
|
||||
ClassNames: NewTable(), // 类短名 → Set(toString 里的真名)
|
||||
ClassRegistrations: NewTable(), // 构造器短名 → Set(类注册调用里的真名)
|
||||
Enums: [], // { Cls, Field, Member, Value, Site }
|
||||
};
|
||||
const Push = (Table, Name, Node) => { if (!Table[Name]) Table[Name] = []; Table[Name].push(Node); };
|
||||
@@ -234,9 +272,66 @@ function ScanModule(Text, Ast) {
|
||||
}
|
||||
});
|
||||
Mod.Bindings = CollectBindings(Ast, 0, Text.length, NewTable());
|
||||
ScanClassRegistrations(Mod, Ast);
|
||||
return Mod;
|
||||
}
|
||||
|
||||
// 类注册名:<别名>(<构造器短名>, "<真名>", …),别名 = <运行时命名空间>.$_$.{fd|kd|id}
|
||||
// 只认经源码证明「第 2 实参是名字」的 fd / kd / id(证明见上方注释),gd / jd / hd 的第 2 实参不是名字。
|
||||
// Kotlin/JS 会在内层函数里复用同名短标识符,因此调用点必须落回「别名本身那处绑定」的作用域才算数。
|
||||
function InnermostBinding(List, Pos) {
|
||||
let Best = null;
|
||||
for (const X of List || []) {
|
||||
if (X.Start > Pos || X.End < Pos) continue;
|
||||
if (!Best || X.End - X.Start < Best.End - Best.Start) Best = X;
|
||||
}
|
||||
return Best;
|
||||
}
|
||||
function ScanClassRegistrations(Mod, Ast) {
|
||||
const Namespaces = RuntimeNamespaceNames(Ast);
|
||||
if (!Namespaces.size) return;
|
||||
const HelperOf = (Node) => {
|
||||
if (!Node || Node.type !== 'MemberExpression' || Node.computed) return null;
|
||||
const Helper = IdentOf(Node.property);
|
||||
if (!RegHelperKind[Helper]) return null;
|
||||
const Obj = Node.object;
|
||||
if (!Obj || Obj.type !== 'MemberExpression' || Obj.computed) return null;
|
||||
if (IdentOf(Obj.property) !== '$_$') return null;
|
||||
if (!Namespaces.has(IdentOf(Obj.object))) return null;
|
||||
return Helper;
|
||||
};
|
||||
const Alias = NewTable(); // 别名 → 注册器
|
||||
const AliasScope = NewTable(); // 别名 → 该别名的绑定作用域(用于识别内层同名遮蔽)
|
||||
const Bad = new Set();
|
||||
WalkWithParent(Ast, null, (Node) => {
|
||||
let Name = null;
|
||||
let Val = null;
|
||||
if (Node.type === 'VariableDeclarator' && Node.id.type === 'Identifier') { Name = Node.id.name; Val = Node.init; }
|
||||
else if (Node.type === 'AssignmentExpression' && Node.left.type === 'Identifier') { Name = Node.left.name; Val = Node.right; }
|
||||
if (!Name) return;
|
||||
const Helper = HelperOf(Val);
|
||||
if (!Helper) return;
|
||||
if (Alias[Name] && Alias[Name] !== Helper) { Bad.add(Name); return; }
|
||||
Alias[Name] = Helper;
|
||||
AliasScope[Name] = InnermostBinding(Mod.Bindings[Name], Node.start);
|
||||
});
|
||||
const Aliases = new Set(Object.keys(Alias).filter((N) => !Bad.has(N) && AliasScope[N]));
|
||||
if (!Aliases.size) return;
|
||||
const SameScope = (A, B) => !!A && !!B && A.Start === B.Start && A.End === B.End;
|
||||
WalkWithParent(Ast, null, (Node) => {
|
||||
if (Node.type !== 'CallExpression' || !Node.arguments || Node.arguments.length < 2) return;
|
||||
const Callee = IdentOf(Node.callee);
|
||||
if (!Callee || !Aliases.has(Callee)) return;
|
||||
if (!SameScope(InnermostBinding(Mod.Bindings[Callee], Node.callee.start), AliasScope[Callee])) return;
|
||||
const A0 = Node.arguments[0];
|
||||
const A1 = Node.arguments[1];
|
||||
if (A0.type !== 'Identifier') return;
|
||||
if (A1.type !== 'Literal' || typeof A1.value !== 'string' || !A1.value) return; // 空串不是名字
|
||||
if (!Mod.ClassRegistrations[A0.name]) Mod.ClassRegistrations[A0.name] = new Set();
|
||||
Mod.ClassRegistrations[A0.name].add(A1.value);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- 载入证据
|
||||
function LoadJson(File, Must) {
|
||||
const P = path.join(NamesDir, File);
|
||||
@@ -278,10 +373,11 @@ const EvidenceByModule = NewTable();
|
||||
for (const [Key, Val] of Object.entries(Evidence.byModule || {})) EvidenceByModule[String(Number(Key))] = Val;
|
||||
|
||||
// ---------------------------------------------------------------- 计划容器
|
||||
const Categories = ['数据类名', '闭包名', '枚举成员', '字段→组件名', '属性名', '命令字段', '别名类名', '别名方法', '别名字段'];
|
||||
const Categories = ['数据类名', '类注册名', '闭包名', '枚举成员', '字段→组件名', '属性名', '命令字段', '别名类名', '别名方法', '别名字段'];
|
||||
const Reasons = ['Conflict', 'InStringLiteral', 'Whitelist', 'MissingEvidence'];
|
||||
const Plans = [];
|
||||
const Skips = [];
|
||||
const ClassRegSame = []; // 「类注册名」与「数据类名」给出同一个名字的条目(后者优先,前者不重复应用)
|
||||
const AddPlan = (Module, Category, Namespace, Short, Long, Nodes) => {
|
||||
Plans.push({ Module, Category, Namespace, Short, Long, Nodes: Nodes || [] });
|
||||
};
|
||||
@@ -405,6 +501,28 @@ for (const M of Object.values(Modules)) {
|
||||
if (!M.Mod.ClassNames[Cls]) AddSkip(M.Id, '数据类名', 'Local', Cls, Name, 'MissingEvidence', '证据里有但源码里复核不到该 toString 模式');
|
||||
}
|
||||
|
||||
// ---- 类注册名:<别名>(<构造器短名>, "<真名>", …),优先级低于「数据类名」
|
||||
const EvRegs = Ev.classRegistrations || {};
|
||||
for (const [Cls, Names] of Object.entries(M.Mod.ClassRegistrations)) {
|
||||
const L = [...Names];
|
||||
if (L.length > 1) { AddSkip(M.Id, '类注册名', 'Local', Cls, L.join('/'), 'Conflict', '同一个类注册短名对应多个注册名'); continue; }
|
||||
const Name = L[0];
|
||||
const Data = M.Mod.ClassNames[Cls] ? [...M.Mod.ClassNames[Cls]] : [];
|
||||
if (Data.length === 1) {
|
||||
if (Data[0] !== Name) { AddSkip(M.Id, '类注册名', 'Local', Cls, Name, 'Conflict', '与「数据类名」通道的 ' + Data[0] + ' 不一致'); continue; }
|
||||
// 两通道同名:按优先级交给「数据类名」通道决定是否应用,本通道不重复改名(否则同一批节点会被替换两次)
|
||||
ClassRegSame.push({ Module: M.Id, Short: Cls, Long: Name });
|
||||
continue;
|
||||
}
|
||||
if (EvRegs[Cls] && EvRegs[Cls].Name !== Name) { AddSkip(M.Id, '类注册名', 'Local', Cls, Name, 'Conflict', '与证据 ' + EvRegs[Cls].Name + ' 不一致'); continue; }
|
||||
Try(Cls, Name, '类注册名');
|
||||
}
|
||||
for (const [Cls, Rec] of Object.entries(EvRegs)) {
|
||||
if (!M.Mod.ClassRegistrations[Cls] || !M.Mod.ClassRegistrations[Cls].has(Rec.Name)) {
|
||||
AddSkip(M.Id, '类注册名', 'Local', Cls, Rec.Name, 'MissingEvidence', '证据里有但源码里复核不到该注册调用');
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 闭包名:X.callableName = "…"
|
||||
for (const [Short, Names] of Object.entries(M.Mod.Closures)) {
|
||||
const L = [...Names];
|
||||
@@ -665,6 +783,7 @@ for (const [K, V] of Object.entries(SkipGroups)) SkipExamples[K] = { Count: V.Co
|
||||
// 证据复核:AST 重新推导 vs 证据。要求「证据里的条目 100% 被 AST 复现」,反向多出来的必须是同源模式
|
||||
const Recheck = {
|
||||
ClassNamesEvidence: 0, ClassNamesFromAst: 0, ClassNamesEvidenceMissed: [],
|
||||
ClassRegistrationsEvidence: 0, ClassRegistrationsFromAst: 0, ClassRegistrationsEvidenceMissed: [],
|
||||
ClosuresEvidence: 0, ClosuresFromAst: 0, ClosuresEvidenceMissed: [],
|
||||
EnumMembersEvidence: 0, EnumMembersFromAst: 0, EnumMembersEvidenceMissed: [],
|
||||
};
|
||||
@@ -675,6 +794,10 @@ for (const [Id, Ev] of Object.entries(EvidenceByModule)) {
|
||||
Recheck.ClassNamesEvidence++;
|
||||
if (!M.Mod.ClassNames[Cls] || !M.Mod.ClassNames[Cls].has(Name)) Recheck.ClassNamesEvidenceMissed.push('module_' + Id + ' ' + Cls + '=' + Name);
|
||||
}
|
||||
for (const [Cls, Rec] of Object.entries(Ev.classRegistrations || {})) {
|
||||
Recheck.ClassRegistrationsEvidence++;
|
||||
if (!M.Mod.ClassRegistrations[Cls] || !M.Mod.ClassRegistrations[Cls].has(Rec.Name)) Recheck.ClassRegistrationsEvidenceMissed.push('module_' + Id + ' ' + Cls + '=' + Rec.Name);
|
||||
}
|
||||
for (const [Short, Names] of Object.entries(Ev.closures || {})) {
|
||||
for (const N of Names) {
|
||||
Recheck.ClosuresEvidence++;
|
||||
@@ -690,6 +813,7 @@ for (const [Id, Ev] of Object.entries(EvidenceByModule)) {
|
||||
}
|
||||
for (const M of Object.values(Modules)) {
|
||||
Recheck.ClassNamesFromAst += Object.keys(M.Mod.ClassNames).length;
|
||||
Recheck.ClassRegistrationsFromAst += Object.keys(M.Mod.ClassRegistrations).length;
|
||||
Recheck.ClosuresFromAst += Object.values(M.Mod.Closures).reduce((A, V) => A + V.size, 0);
|
||||
Recheck.EnumMembersFromAst += M.Mod.Enums.length;
|
||||
}
|
||||
@@ -712,11 +836,21 @@ const Report = {
|
||||
'命令字段(uplink_table 的 555 条负载槽位)在源码里没有保留可读名,全部计入证据缺失。',
|
||||
'闭包名 / 数据类名用与 mine_evidence.js 同源但更抗格式化的 AST 规则重新推导,并与证据交叉核对(见 Recheck)。',
|
||||
' 证据里的条目必须 100% 被 AST 复现(*EvidenceMissed 应为空);AST 反向多出来的只是同一模式的漏配(如 prettier 换行导致正则抓不到)。',
|
||||
'【类注册名】<别名>(<构造器短名>, "<真名>", …),别名 = <运行时命名空间>.$_$.{fd|kd|id}。',
|
||||
' 只认经 module_37036 源码证明「第 2 实参是名字」的 fd(class) / kd(object) / id(interface);',
|
||||
' 同族导出 gd(=ee→"Companion") / jd(=re→"Lambda") / hd(内联 Qr→"Coroutine") 的第 2 实参写死,已排除。',
|
||||
' 该通道优先级低于「数据类名」:同短名两通道一致时由「数据类名」应用(见 ClassRegistrationsSameAsDataClass),',
|
||||
' 不一致时记 Conflict 跳过;空串不是名字,一律丢弃。',
|
||||
'【派生命名】只有 --aliases 打开时才回填;来自 command_alias.json,是「读源码证实语义后起的别名」而非原始名,单独记在 Aliases 段,不计入上面的证据改名统计。',
|
||||
],
|
||||
Renamed,
|
||||
Skipped,
|
||||
SkipExamples,
|
||||
ClassRegistrationsSameAsDataClass: {
|
||||
Count: ClassRegSame.length,
|
||||
Examples: ClassRegSame.slice(0, 15),
|
||||
Note: '「类注册名」与「数据类名」给出同一个名字:按优先级由「数据类名」通道决定是否应用,本通道不重复改名',
|
||||
},
|
||||
Recheck,
|
||||
Aliases: AliasReport,
|
||||
Validation,
|
||||
@@ -734,6 +868,9 @@ for (const C of Categories) {
|
||||
const R = Renamed[C];
|
||||
console.log(' ' + C.padEnd(7) + ' Entries ' + String(R.Entries).padStart(5) + ' Edits ' + String(R.Edits).padStart(7));
|
||||
for (const E of R.Examples.slice(0, 4)) console.log(' 例: ' + C + ' ' + E.Short + ' → ' + E.Long + ' [' + (E.Module === '*' ? '全局' : 'module_' + E.Module) + ' ×' + E.Count + ']');
|
||||
if (C === '类注册名') {
|
||||
console.log(' 与「数据类名」同名 ' + ClassRegSame.length + ' 条(由「数据类名」应用,本通道不重复改名)');
|
||||
}
|
||||
}
|
||||
console.log('');
|
||||
console.log('=== 跳过统计 ===');
|
||||
@@ -776,11 +913,13 @@ console.log(' ① node --check : 通过 ' + Validation.SyntaxChecked + '
|
||||
console.log(' ② 字符串字面量集合 : 一致 ' + Validation.StringIdentical + ' / ' + Object.keys(Modules).length + (Validation.StringMismatch.length ? ' 不一致: ' + Validation.StringMismatch.slice(0, 5).join(', ') : ' ✓'));
|
||||
console.log(' ③ 标识符计数自检 : 通过 ' + Validation.CountChecked + ' / ' + Object.keys(Modules).length + ';标识符总数不变 ' + (Validation.TotalIdentSame ? '✓' : '✗') + (Validation.CountMismatch.length ? ' 异常: ' + Validation.CountMismatch.slice(0, 5).join(' | ') : ' ✓'));
|
||||
console.log(' ④ 证据复核(AST 复现): 数据类名 ' + Recheck.ClassNamesEvidence + '→' + Recheck.ClassNamesFromAst +
|
||||
'(漏 ' + Recheck.ClassNamesEvidenceMissed.length + ');闭包名 ' + Recheck.ClosuresEvidence + '→' + Recheck.ClosuresFromAst +
|
||||
'(漏 ' + Recheck.ClassNamesEvidenceMissed.length + ');类注册名 ' + Recheck.ClassRegistrationsEvidence + '→' + Recheck.ClassRegistrationsFromAst +
|
||||
'(漏 ' + Recheck.ClassRegistrationsEvidenceMissed.length + ');闭包名 ' + Recheck.ClosuresEvidence + '→' + Recheck.ClosuresFromAst +
|
||||
'(漏 ' + Recheck.ClosuresEvidenceMissed.length + ');枚举成员 ' + Recheck.EnumMembersEvidence + '→' + Recheck.EnumMembersFromAst +
|
||||
'(漏 ' + Recheck.EnumMembersEvidenceMissed.length + ')');
|
||||
const Ok = !Validation.SyntaxFailed.length && !Validation.StringMismatch.length && !Validation.CountMismatch.length && Validation.TotalIdentSame &&
|
||||
!Recheck.ClassNamesEvidenceMissed.length && !Recheck.ClosuresEvidenceMissed.length && !Recheck.EnumMembersEvidenceMissed.length;
|
||||
!Recheck.ClassNamesEvidenceMissed.length && !Recheck.ClassRegistrationsEvidenceMissed.length &&
|
||||
!Recheck.ClosuresEvidenceMissed.length && !Recheck.EnumMembersEvidenceMissed.length;
|
||||
console.log('');
|
||||
console.log(Ok ? '全部校验通过。报告: ' + ReportPath : '校验未通过,请看上面的异常列表。报告: ' + ReportPath);
|
||||
if (!Ok) process.exitCode = 1;
|
||||
@@ -8,6 +8,7 @@
|
||||
// 4) 数据类 toString : Q(类).toString = function () { return "<类名>(" + ... }
|
||||
// 5) 枚举构造 : E = new 枚举类("<成员名>", 0)
|
||||
// 6) 字符串常量频次(辅助命名)
|
||||
// 7) 类注册名 : <别名>(<构造器短名>, "<真名>", …)(见下方「类注册器证明」)
|
||||
//
|
||||
// 结构说明:**类名/局部名都是模块内作用域**,因此按模块分域存放;
|
||||
// 属性名(字段)是全局共享字符串,故全局聚合。
|
||||
@@ -31,18 +32,122 @@ function Push(Target, Key, Value) {
|
||||
if (Target[Key].indexOf(Value) < 0) Target[Key].push(Value);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- 类注册器证明
|
||||
// 依据 src/module_37036.js 源码(导出表在 10148~10155 行):
|
||||
// Zr(t, n, i, r, e, u) 造 $metadata$,其中 simpleName 取第 2 实参
|
||||
// te(kind, ctor, simpleName, …) 把 Zr 的结果挂到 ctor.$metadata$ 上
|
||||
// Qr(t, n, …) → te("class", t, n, …) ⇒ Qr 的第 2 实参 = 名字(class)
|
||||
// ne(t, n, …) → te("object", t, n, …) ⇒ ne 的第 2 实参 = 名字(object)
|
||||
// ie(t, n, …) → te("interface", t, n, …) ⇒ ie 的第 2 实参 = 名字(interface)
|
||||
// 导出表证明:t.$_$.fd = Qr、t.$_$.kd = ne、t.$_$.id = ie。
|
||||
// ⇒ 只有 fd / kd / id 这 3 个导出的「第 2 实参」是名字,其余同族导出必须排除:
|
||||
// · t.$_$.gd = ee :ee(t, n, i, r) 调 ne(t, "Companion", E, n, i, r, …),
|
||||
// 第 2 实参写死为 "Companion",形参 n 落到了 defaultConstructor 位(第 4 实参);
|
||||
// · t.$_$.jd = re :re(t, n, i, r) 调 Qr(t, "Lambda", E, n, i, r, …),同上,n 落到第 4 实参位;
|
||||
// · t.$_$.hd = function (t, n, i, r) { Qr(t, "Coroutine", E, n, i, r, E, E) },
|
||||
// 第 2 实参写死为 "Coroutine",形参 n 落到 Qr 的第 4 实参位。
|
||||
const RegHelperKind = { fd: 'class', kd: 'object', id: 'interface' };
|
||||
const RUNTIME_MODULE = 37036;
|
||||
|
||||
const EscapeRe = (S) => S.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
// 行首偏移表 + 位置 → "行:列"
|
||||
function LineStarts(Text) {
|
||||
const Starts = [0];
|
||||
for (let I = 0; I < Text.length; I++) if (Text[I] === '\n') Starts.push(I + 1);
|
||||
return Starts;
|
||||
}
|
||||
function SiteOf(Starts, Pos) {
|
||||
let Lo = 0;
|
||||
let Hi = Starts.length - 1;
|
||||
while (Lo < Hi) {
|
||||
const Mid = (Lo + Hi + 1) >> 1;
|
||||
if (Starts[Mid] <= Pos) Lo = Mid;
|
||||
else Hi = Mid - 1;
|
||||
}
|
||||
return Lo + 1 + ':' + (Pos - Starts[Lo] + 1);
|
||||
}
|
||||
|
||||
// 字符串字面量原文 → 值(空串返回 '',由调用方丢弃)
|
||||
function LiteralValue(Lit) {
|
||||
const Body = Lit.slice(1, -1);
|
||||
if (Body.indexOf('\\') < 0) return Body;
|
||||
try { return JSON.parse(Lit); } catch (Err) { return null; }
|
||||
}
|
||||
|
||||
// 模块 IIFE 里绑定到 module_37036 的形参名集合(导出表所在模块的命名空间)
|
||||
// 形态:!(function (a, b, c, …) { … })(t.exports, i(37036), i(32088), …);
|
||||
function RuntimeNamespaceNames(Text) {
|
||||
const Out = new Set();
|
||||
const Fn = /!\(\s*function\s*\(([\s\S]*?)\)\s*\{/.exec(Text);
|
||||
if (!Fn) return Out;
|
||||
const Params = Fn[1].split(',').map((S) => S.trim());
|
||||
const Tail = /\}\)\s*\(\s*t\.exports\s*,([\s\S]*?)\)\s*;\s*\}/.exec(Text);
|
||||
if (!Tail) return Out;
|
||||
const Args = [];
|
||||
const ArgRe = /(?:\([^()]*\)|[^,()])+/g;
|
||||
let M;
|
||||
while ((M = ArgRe.exec(Tail[1])) !== null) Args.push(M[0].trim());
|
||||
for (let I = 0; I < Args.length; I++) {
|
||||
if (!/^[A-Za-z_$][\w$]*\(\s*37036\s*\)$/.test(Args[I])) continue;
|
||||
const P = Params[I + 1]; // 第 1 个实参 t.exports 对应第 1 个形参,此处从第 2 个实参起算
|
||||
if (P && /^[A-Za-z_$][\w$]*$/.test(P)) Out.add(P);
|
||||
}
|
||||
return Out;
|
||||
}
|
||||
|
||||
// <别名>(<构造器短名>, "<真名>", …) → { 短名: { Name, Kind, Site, Helper } }
|
||||
function CollectClassRegistrations(Text) {
|
||||
const Map = {};
|
||||
const Namespaces = RuntimeNamespaceNames(Text);
|
||||
if (!Namespaces.size) return Map;
|
||||
// 别名解析:Local = <运行时命名空间>.$_$.<fd|kd|id>(同一别名被赋成两个注册器则整体弃用)
|
||||
const Alias = {};
|
||||
const Bad = new Set();
|
||||
const AliasRe = /(?<![\w$])([A-Za-z_$][\w$]*)\s*=\s*([A-Za-z_$][\w$]*)\s*\.\s*\$_\$\s*\.\s*(fd|kd|id)(?![\w$])/g;
|
||||
let M;
|
||||
while ((M = AliasRe.exec(Text)) !== null) {
|
||||
if (!Namespaces.has(M[2])) continue;
|
||||
if (Alias[M[1]] && Alias[M[1]] !== M[3]) { Bad.add(M[1]); continue; }
|
||||
Alias[M[1]] = M[3];
|
||||
}
|
||||
for (const N of Bad) delete Alias[N];
|
||||
const AliasNames = Object.keys(Alias);
|
||||
if (!AliasNames.length) return Map;
|
||||
|
||||
const Starts = LineStarts(Text);
|
||||
const CallRe = new RegExp(
|
||||
'(?<![\\w$])(?:' + AliasNames.map(EscapeRe).join('|') + ')\\s*\\(\\s*([A-Za-z_$][\\w$]*)\\s*,\\s*("(?:[^"\\\\]|\\\\.)*")',
|
||||
'g',
|
||||
);
|
||||
while ((M = CallRe.exec(Text)) !== null) {
|
||||
const Head = /^[A-Za-z_$][\w$]*/.exec(M[0]);
|
||||
const Helper = Head ? Alias[Head[0]] : null;
|
||||
if (!Helper) continue;
|
||||
const Name = LiteralValue(M[2]);
|
||||
if (!Name) continue; // 空串不是名字,丢弃
|
||||
const Short = M[1];
|
||||
if (Map[Short] && Map[Short].Name !== Name) continue; // 同模块同短名多个名字:保留首见
|
||||
if (Map[Short]) continue;
|
||||
Map[Short] = { Name, Kind: RegHelperKind[Helper], Site: SiteOf(Starts, M.index), Helper };
|
||||
}
|
||||
return Map;
|
||||
}
|
||||
|
||||
function Run() {
|
||||
const Files = fs.readdirSync(SRC_DIR).filter((F) => /^module_\d+\.js$/.test(F)).sort();
|
||||
const ByModule = {}; // 模块ID → 各类证据
|
||||
const FieldsGlobal = new Map(); // 字段 → 组件/服务名(全局)
|
||||
const Services = new Set();
|
||||
const Strings = new Map();
|
||||
const Stats = { modules: 0, fields: 0, classNames: 0, enumMembers: 0, closures: 0, exports: 0 };
|
||||
const Stats = { modules: 0, fields: 0, classNames: 0, enumMembers: 0, closures: 0, exports: 0, classRegistrations: 0 };
|
||||
const RegNames = new Set(); // 类注册名的去重集合
|
||||
const RegByHelper = {}; // 注册器 → 条数
|
||||
|
||||
for (const F of Files) {
|
||||
const Text = fs.readFileSync(path.join(SRC_DIR, F), 'utf8');
|
||||
const Id = (F.match(/module_(\d+)/) || [])[1];
|
||||
const Mod = { classNames: {}, closures: {}, enums: {}, exports: {}, componentGetters: {} };
|
||||
const Mod = { classNames: {}, closures: {}, enums: {}, exports: {}, componentGetters: {}, classRegistrations: {} };
|
||||
let M;
|
||||
|
||||
// 1) 懒加载组件 getter(容忍换行/空格)
|
||||
@@ -78,18 +183,26 @@ function Run() {
|
||||
// 7) 导出表 (t.$_$.xx = LocalName)
|
||||
for (M of Text.matchAll(/t\.\$_\$\.([A-Za-z_$][\w$]*)\s*=\s*([A-Za-z_$][\w$]*)/g)) Mod.exports[M[1]] = M[2];
|
||||
|
||||
// 8) 类注册名:<别名>(<构造器短名>, "<真名>", …)
|
||||
Mod.classRegistrations = CollectClassRegistrations(Text);
|
||||
|
||||
if (Object.keys(Mod.classNames).length) Stats.classNames += Object.keys(Mod.classNames).length;
|
||||
for (const K of Object.keys(Mod.enums)) Stats.enumMembers += Mod.enums[K].length;
|
||||
for (const K of Object.keys(Mod.closures)) Stats.closures += Mod.closures[K].length;
|
||||
Stats.exports += Object.keys(Mod.exports).length;
|
||||
Stats.fields += Object.keys(Mod.componentGetters).length;
|
||||
for (const [K, V] of Object.entries(Mod.classRegistrations)) {
|
||||
Stats.classRegistrations++;
|
||||
RegNames.add(V.Name);
|
||||
RegByHelper[V.Helper] = (RegByHelper[V.Helper] || 0) + 1;
|
||||
}
|
||||
Stats.modules++;
|
||||
|
||||
// 只保留有内容的模块,减小体积
|
||||
if (
|
||||
Object.keys(Mod.classNames).length || Object.keys(Mod.enums).length ||
|
||||
Object.keys(Mod.closures).length || Object.keys(Mod.exports).length ||
|
||||
Object.keys(Mod.componentGetters).length
|
||||
Object.keys(Mod.componentGetters).length || Object.keys(Mod.classRegistrations).length
|
||||
) {
|
||||
ByModule[Id] = Mod;
|
||||
}
|
||||
@@ -126,6 +239,17 @@ function Run() {
|
||||
}
|
||||
console.log('--- 服务名(前 12)---');
|
||||
console.log(' ' + [...Services].sort().slice(0, 12).join(', '));
|
||||
console.log('--- 类注册名(通道 7:fd/kd/id)---');
|
||||
console.log(' 条目 ' + Stats.classRegistrations + ';不重复名字 ' + RegNames.size +
|
||||
';按注册器 ' + ['fd', 'kd', 'id'].map((K) => K + '(' + RegHelperKind[K] + ') ' + (RegByHelper[K] || 0)).join(' '));
|
||||
C = 0;
|
||||
for (const [Id, V] of Object.entries(ByModule)) {
|
||||
for (const [Short, Rec] of Object.entries(V.classRegistrations || {})) {
|
||||
if (C++ >= 8) break;
|
||||
console.log(' module_' + Id + ' ' + Short + ' = ' + Rec.Name + ' [' + Rec.Kind + ' / ' + Rec.Helper + ' @' + Rec.Site + ']');
|
||||
}
|
||||
if (C >= 8) break;
|
||||
}
|
||||
console.log('输出: ' + OUT);
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,24 @@ const Server = http.createServer((Req, Res) => {
|
||||
Res.writeHead(200, { 'Content-Type': 'application/javascript; charset=utf-8' }).end('/* noop */\n');
|
||||
return;
|
||||
}
|
||||
// /hornet_sw.js:Service Worker 本体。放在根路径 + 放行 Service-Worker-Allowed,
|
||||
// 作用域才能覆盖 /,从而接管首页 / 发起的 /play/... 碎请求(unpacked 单包缓存)
|
||||
if (UrlPath.split('?')[0] === '/hornet_sw.js') {
|
||||
const SwFile = path.join(ROOT, 'tools', 'hornet_sw.js');
|
||||
if (!fs.existsSync(SwFile)) {
|
||||
Res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' }).end('hornet_sw.js not found');
|
||||
return;
|
||||
}
|
||||
const Sw = fs.readFileSync(SwFile);
|
||||
Res.writeHead(200, {
|
||||
'Content-Type': 'application/javascript; charset=utf-8',
|
||||
'Content-Length': Sw.length,
|
||||
'Cache-Control': 'no-cache',
|
||||
'Service-Worker-Allowed': '/',
|
||||
'X-Hornet-Sw': 'local',
|
||||
}).end(Sw);
|
||||
return;
|
||||
}
|
||||
// /config.xml 本地覆盖:存在 local/config.xml 时用它,把游戏指向本地 wss_server
|
||||
if (!REAL_CONFIG && UrlPath.split('?')[0] === '/config.xml' && fs.existsSync(LOCAL_CONFIG)) {
|
||||
const Conf = fs.readFileSync(LOCAL_CONFIG);
|
||||
|
||||
+216
-42
@@ -8,6 +8,8 @@
|
||||
// 挂载: 客户端 config.xml 指向本服务器(local/config.xml + serve.js 的 /config.xml 本地覆盖)
|
||||
// <server address="localhost" wsProtocol="WS"> + <port>9091</port> → ws://localhost:9091/
|
||||
// 产物: 3DTank/packets/<label>/session_00N/{log.txt, c2s_%04d.bin, s2c_%04d.bin}
|
||||
// 注意:默认**落盘保存**(每帧一个 .bin + log.txt,统一走有序异步写队列,不阻塞转发);
|
||||
// 要纯转发不落盘请加 --dump-every 0 --log 0
|
||||
//
|
||||
// 协议(逆向自 module_61860 + sockets/):
|
||||
// 帧 = [2 或 4 字节大端长度][帧体];b0 & 0x80 → 4 字节头;b0 & 0x40 → 帧体 zlib 压缩
|
||||
@@ -42,6 +44,35 @@ const UPSTREAM = Arg('upstream', 'wss://c1.3dtank.com:9090/');
|
||||
const LABEL = Arg('label', new Date().toISOString().replace(/[:.]/g, '-'));
|
||||
const PACKET_DIR = path.resolve(Arg('dir', path.join(PROJECT, 'packets', LABEL)));
|
||||
|
||||
// 落盘/日志策略:**默认落盘保存**(统一走有序异步写队列,绝不阻塞转发路径)
|
||||
// --dump-every N 写 .bin 抓包文件(每 N 帧一个;默认 1 = 每帧都写;0 = 不写)
|
||||
// --log 1 写 log.txt(默认 1 = 写)
|
||||
// --no-hex 1 log.txt 不写十六进制
|
||||
// --quiet 1 只写 log.txt,不刷控制台
|
||||
const DUMP_EVERY = Number(Arg('dump-every', '1'));
|
||||
const WRITE_LOG = Arg('log', '1') === '1';
|
||||
const WRITE_HEX = Arg('no-hex', '0') !== '1';
|
||||
const QUIET = Arg('quiet', '0') === '1';
|
||||
const NeedDisk = DUMP_EVERY > 0 || WRITE_LOG;
|
||||
|
||||
// 转发策略(零等待、零缓存):
|
||||
// 上游就绪 → 客户端帧**原样直发**;未就绪 → **暂停读客户端 socket**(反压,字节留在内核缓冲),
|
||||
// 就绪后立刻恢复。应用层不攒帧、不回放,因此既不丢也不乱序。
|
||||
// --reconnect N 上游断开后的重连间隔(ms,默认 600)
|
||||
const RECONNECT_MS = Number(Arg('reconnect', '600'));
|
||||
// 反压看门狗:socket 被暂停时连关闭帧也读不到,若长时间无法转发就主动收摊(避免僵尸会话)
|
||||
const PAUSE_TIMEOUT_MS = Number(Arg('pause-timeout', '60000'));
|
||||
|
||||
// ===== 崩溃可见性 & 稳定性 =====
|
||||
// 未捕获异常/未处理拒绝一律打印完整堆栈并**保持进程存活**,避免长对局中途"后端悄悄崩了";
|
||||
// 需要看现场时窗口也不会关(ps1 用 cmd /k 启动)。
|
||||
process.on('uncaughtException', (Err) => {
|
||||
console.error('[崩溃] 未捕获异常:', (Err && Err.stack) || Err);
|
||||
});
|
||||
process.on('unhandledRejection', (Err) => {
|
||||
console.error('[崩溃] 未处理的 Promise 拒绝:', (Err && Err.stack) || Err);
|
||||
});
|
||||
|
||||
// 字段表:names/codec_fields.json(codec 字段)+ names/uplink_table.json(上行命令名 / 负载字段)
|
||||
const Tables = LoadTables(path.join(PROJECT, 'names'));
|
||||
const Reader = MakeReader(Tables, { EnumBytes: 4 });
|
||||
@@ -370,36 +401,93 @@ class StreamDecoder {
|
||||
// 会话与落盘
|
||||
// ============================================================
|
||||
|
||||
fs.mkdirSync(PACKET_DIR, { recursive: true });
|
||||
if (NeedDisk) fs.mkdirSync(PACKET_DIR, { recursive: true });
|
||||
|
||||
let SessionSeq = 0;
|
||||
|
||||
function NewSession() {
|
||||
const Used = fs
|
||||
.readdirSync(PACKET_DIR, { withFileTypes: true })
|
||||
.filter((D) => D.isDirectory() && D.name.startsWith('session_'))
|
||||
.map((D) => Number(D.name.slice('session_'.length)))
|
||||
.filter((N) => !Number.isNaN(N));
|
||||
const Next = (Used.length ? Math.max.apply(null, Used) : 0) + 1;
|
||||
const Dir = path.join(PACKET_DIR, 'session_' + String(Next).padStart(3, '0'));
|
||||
fs.mkdirSync(Dir, { recursive: true });
|
||||
SessionSeq++;
|
||||
let Dir = null;
|
||||
let Name = 'session_' + String(SessionSeq).padStart(3, '0');
|
||||
if (NeedDisk) {
|
||||
// 只有需要落盘时才读/建目录(无谓的磁盘访问一律避免),并与已有抓包目录错开编号
|
||||
let Used = [];
|
||||
try {
|
||||
Used = fs
|
||||
.readdirSync(PACKET_DIR, { withFileTypes: true })
|
||||
.filter((D) => D.isDirectory() && D.name.startsWith('session_'))
|
||||
.map((D) => Number(D.name.slice('session_'.length)))
|
||||
.filter((N) => !Number.isNaN(N));
|
||||
} catch (Err) {}
|
||||
Name = 'session_' + String((Used.length ? Math.max.apply(null, Used) : 0) + 1).padStart(3, '0');
|
||||
Dir = path.join(PACKET_DIR, Name);
|
||||
fs.mkdirSync(Dir, { recursive: true });
|
||||
}
|
||||
|
||||
const State = { Dir, Stream: fs.createWriteStream(path.join(Dir, 'log.txt'), { flags: 'w' }), C2s: 0, S2c: 0 };
|
||||
const State = { Dir, Name, Stream: null, C2s: 0, S2c: 0, Frames: 0 };
|
||||
if (NeedDisk && WRITE_LOG) {
|
||||
State.Stream = fs.createWriteStream(path.join(Dir, 'log.txt'), { flags: 'w' });
|
||||
}
|
||||
State.Log = (Msg) => {
|
||||
const Line = '[' + new Date().toISOString() + '] ' + Msg;
|
||||
console.log(Line);
|
||||
State.Stream.write(Line + '\n');
|
||||
if (!QUIET) console.log(Line);
|
||||
if (State.Stream) State.Stream.write(Line + '\n');
|
||||
};
|
||||
return State;
|
||||
}
|
||||
|
||||
// 原始字节落盘 + 记录顺序(解析交给 StreamDecoder)
|
||||
// ===== 本地保存:单条**有序**异步写队列 =====
|
||||
// 抓包/日志的落盘不参与转发路径:帧按接收顺序入队,队列内串行写盘(不并发、不阻塞事件循环),
|
||||
// 因此落盘顺序 == 收发顺序,绝不错序;转发路径本身零等待零缓存。
|
||||
let SaveQueue = [];
|
||||
let SaveQueueBusy = false;
|
||||
let SaveQueueBytes = 0;
|
||||
const SAVE_QUEUE_MAX_BYTES = 64 * 1024 * 1024; // 积压上限,超过则丢弃最旧的落盘任务(只影响抓包文件)
|
||||
|
||||
function PumpSaveQueue() {
|
||||
if (SaveQueueBusy) return;
|
||||
const Task = SaveQueue.shift();
|
||||
if (!Task) return;
|
||||
SaveQueueBusy = true;
|
||||
SaveQueueBytes -= Task.Bytes;
|
||||
Task.Run(() => {
|
||||
SaveQueueBusy = false;
|
||||
PumpSaveQueue();
|
||||
});
|
||||
}
|
||||
|
||||
function EnqueueSave(Bytes, Run) {
|
||||
if (SaveQueueBytes + Bytes > SAVE_QUEUE_MAX_BYTES) {
|
||||
const Dropped = SaveQueue.shift();
|
||||
if (Dropped) SaveQueueBytes -= Dropped.Bytes;
|
||||
}
|
||||
SaveQueue.push({ Bytes: Bytes, Run: Run });
|
||||
SaveQueueBytes += Bytes;
|
||||
PumpSaveQueue();
|
||||
}
|
||||
|
||||
// 原始字节落盘(默认开启,每帧一个 .bin)+ 记录顺序(解析交给 StreamDecoder)
|
||||
// 注意:写入走 EnqueueSave 的有序队列(异步、串行)——writeFileSync 会阻塞事件循环,
|
||||
// 长对局里目录越来越大、写入越来越慢,转发随之变慢,表现为"游戏越玩越卡"。
|
||||
// 要纯转发不落盘请加 --dump-every 0 --log 0。
|
||||
function SaveFrame(State, Direction, Buf, Note) {
|
||||
const Seq = Direction === 'c2s' ? State.C2s++ : State.S2c++;
|
||||
fs.writeFileSync(path.join(State.Dir, Direction + '_' + String(Seq).padStart(4, '0') + '.bin'), Buf);
|
||||
State.Frames++;
|
||||
const Tag = Direction + '_' + String(Seq).padStart(4, '0');
|
||||
if (DUMP_EVERY > 0 && State.Dir && State.Frames % DUMP_EVERY === 0) {
|
||||
const OutPath = path.join(State.Dir, Tag + '.bin');
|
||||
EnqueueSave(Buf.length, (Done) => {
|
||||
fs.writeFile(OutPath, Buf, (Err) => {
|
||||
if (Err) console.log('[dump] 写入失败: ' + Err.message);
|
||||
Done();
|
||||
});
|
||||
});
|
||||
}
|
||||
State.Log(
|
||||
(Direction === 'c2s' ? '>>>' : '<<<') + ' ' + Direction + '_' + String(Seq).padStart(4, '0') + '.bin ' +
|
||||
(Direction === 'c2s' ? '>>>' : '<<<') + ' ' + Tag + (State.Dir ? '.bin' : '') + ' ' +
|
||||
Buf.length + ' 字节' + (Note ? ' ' + Note : ''),
|
||||
);
|
||||
State.Stream.write(Buf.toString('hex') + '\n');
|
||||
if (WRITE_HEX && State.Stream) State.Stream.write(Buf.toString('hex') + '\n');
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -426,43 +514,127 @@ WsServer.on('connection', (Client, Req) => {
|
||||
|
||||
const Decoders = { c2s: new StreamDecoder(State, 'c2s'), s2c: new StreamDecoder(State, 's2c') };
|
||||
let Upstream = null;
|
||||
const Pending = []; // 上游未就绪时暂存(握手帧常比上游 TLS 建连更早到达)
|
||||
let ReconnectTimer = null;
|
||||
let PauseTimer = null;
|
||||
let Closed = false;
|
||||
let DroppedFrames = 0;
|
||||
let LastDropLogAt = 0;
|
||||
const Pending = []; // 竞态保护:暂停生效前已进入的前几帧(原序补发)
|
||||
let PendingBytes = 0;
|
||||
const MAX_RACE_FRAMES = 64;
|
||||
|
||||
Upstream = new Ws(UPSTREAM, { headers: UPSTREAM_HEADERS, rejectUnauthorized: false });
|
||||
Upstream.binaryType = 'nodebuffer';
|
||||
Upstream.on('open', () => {
|
||||
State.Log('上游已连接: ' + UPSTREAM + ',补发暂存 ' + Pending.length + ' 帧');
|
||||
while (Pending.length) Upstream.send(Pending.shift());
|
||||
});
|
||||
Upstream.on('message', (Data) => {
|
||||
const Buf = Buffer.from(Data);
|
||||
SaveFrame(State, 's2c', Buf);
|
||||
Decoders.s2c.Feed(Buf);
|
||||
SyncKeys(Decoders);
|
||||
if (Client.readyState === Ws.OPEN) Client.send(Buf);
|
||||
});
|
||||
Upstream.on('close', (Code) => {
|
||||
State.Log('上游关闭 code=' + Code);
|
||||
Client.close();
|
||||
});
|
||||
Upstream.on('error', (Err) => State.Log('上游错误: ' + Err.message));
|
||||
// ===== 转发路径:零等待、零缓存(靠 socket 反压保证不丢不乱序)=====
|
||||
// 上游没就绪就**暂停读客户端 socket**(字节留在内核接收缓冲里,应用层不攒帧、不回放),
|
||||
// 就绪后立刻恢复 → 客户端字节按原序直发上游。这样既不会丢帧,也不会乱序,也不存在"暂存待补发"。
|
||||
function PauseClient(Why) {
|
||||
const Sock = Client._socket;
|
||||
if (Sock && !Sock.isPaused()) {
|
||||
Sock.pause();
|
||||
State.Log('客户端读取已暂停(' + Why + ')');
|
||||
if (!PauseTimer) {
|
||||
// 注意:暂停后连客户端的关闭帧也读不到 → 必须有看门狗兜底,否则会话会僵住
|
||||
PauseTimer = setTimeout(() => {
|
||||
PauseTimer = null;
|
||||
State.Log('客户端长时间无法转发(>' + Math.round(PAUSE_TIMEOUT_MS / 1000) + 's),关闭会话以便游戏重连');
|
||||
CloseSession();
|
||||
}, PAUSE_TIMEOUT_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ResumeClient() {
|
||||
const Sock = Client._socket;
|
||||
if (PauseTimer) { clearTimeout(PauseTimer); PauseTimer = null; }
|
||||
if (Sock && Sock.isPaused()) {
|
||||
Sock.resume();
|
||||
State.Log('上游就绪,恢复客户端转发');
|
||||
}
|
||||
}
|
||||
|
||||
function CloseSession() {
|
||||
Closed = true;
|
||||
if (PauseTimer) { clearTimeout(PauseTimer); PauseTimer = null; }
|
||||
if (ReconnectTimer) { clearTimeout(ReconnectTimer); ReconnectTimer = null; }
|
||||
if (State.Stream) State.Stream.end(); // 不落盘时 Stream 为 null,必须判空
|
||||
if (Upstream && (Upstream.readyState === Ws.OPEN || Upstream.readyState === Ws.CONNECTING)) Upstream.close();
|
||||
try { Client.terminate(); } catch (E) {}
|
||||
}
|
||||
|
||||
PauseClient('等待上游就绪'); // 立刻反压:只有能转发时才把客户端字节读进来
|
||||
|
||||
function ScheduleReconnect() {
|
||||
if (Closed || ReconnectTimer) return;
|
||||
ReconnectTimer = setTimeout(() => {
|
||||
ReconnectTimer = null;
|
||||
if (Closed) return;
|
||||
State.Log('尝试重连上游: ' + UPSTREAM);
|
||||
ConnectUpstream();
|
||||
}, RECONNECT_MS);
|
||||
}
|
||||
|
||||
function ConnectUpstream() {
|
||||
if (Closed) return;
|
||||
if (Upstream && (Upstream.readyState === Ws.OPEN || Upstream.readyState === Ws.CONNECTING)) return;
|
||||
Upstream = new Ws(UPSTREAM, { headers: UPSTREAM_HEADERS, rejectUnauthorized: false });
|
||||
Upstream.binaryType = 'nodebuffer';
|
||||
Upstream.on('open', () => {
|
||||
State.Log('上游已连接: ' + UPSTREAM + (Pending.length ? ',补发竞态帧 ' + Pending.length + ' 帧 / ' + PendingBytes + ' 字节' : ''));
|
||||
while (Pending.length) {
|
||||
const Stashed = Pending.shift();
|
||||
PendingBytes -= Stashed.length;
|
||||
Upstream.send(Stashed);
|
||||
}
|
||||
ResumeClient(); // 反压解除:客户端字节按原序继续直发
|
||||
});
|
||||
Upstream.on('message', (Data) => {
|
||||
const Buf = Buffer.from(Data);
|
||||
SaveFrame(State, 's2c', Buf);
|
||||
Decoders.s2c.Feed(Buf);
|
||||
SyncKeys(Decoders);
|
||||
if (Client.readyState === Ws.OPEN) Client.send(Buf);
|
||||
});
|
||||
Upstream.on('close', (Code) => {
|
||||
// 「持续等待」:不踢客户端;立刻反压,等重连好再继续转发(期间不攒帧、不回放)
|
||||
State.Log('上游关闭 code=' + Code + ',保持客户端连接并等待重连');
|
||||
PauseClient('上游断开,等待重连');
|
||||
ScheduleReconnect();
|
||||
});
|
||||
Upstream.on('error', (Err) => {
|
||||
State.Log('上游错误: ' + Err.message);
|
||||
PauseClient('上游错误,等待重连');
|
||||
ScheduleReconnect();
|
||||
});
|
||||
}
|
||||
|
||||
ConnectUpstream();
|
||||
|
||||
Client.on('message', (Data) => {
|
||||
const Buf = Buffer.from(Data);
|
||||
SaveFrame(State, 'c2s', Buf);
|
||||
Decoders.c2s.Feed(Buf);
|
||||
SyncKeys(Decoders);
|
||||
if (Upstream && Upstream.readyState === Ws.OPEN) Upstream.send(Buf);
|
||||
else {
|
||||
State.Log('上游尚未就绪,暂存 ' + Buf.length + ' 字节待补发');
|
||||
Pending.push(Buf);
|
||||
if (Upstream && Upstream.readyState === Ws.OPEN) {
|
||||
Upstream.send(Buf); // 原样直发,不等待、不缓存
|
||||
return;
|
||||
}
|
||||
// 只有"暂停生效前"已进入的帧会走到这里(正常 0~1 帧):按原序暂存,连上后立即补发
|
||||
if (Pending.length < MAX_RACE_FRAMES) {
|
||||
Pending.push(Buf);
|
||||
PendingBytes += Buf.length;
|
||||
State.Log('竞态窗口帧(暂停生效前)暂存:' + Buf.length + ' 字节(队列 ' + Pending.length + ' 帧)');
|
||||
} else {
|
||||
DroppedFrames++;
|
||||
State.Log('竞态队列已满,丢弃该帧:' + Buf.length + ' 字节 累计丢弃 ' + DroppedFrames + ' 帧');
|
||||
}
|
||||
PauseClient('上游未就绪');
|
||||
});
|
||||
|
||||
Client.on('close', (Code) => {
|
||||
State.Log('客户端断开 code=' + Code + ' 收 ' + State.C2s + ' 条 / 发 ' + State.S2c + ' 条');
|
||||
State.Stream.end();
|
||||
if (Upstream && Upstream.readyState === Ws.OPEN) Upstream.close();
|
||||
State.Log(
|
||||
'客户端断开 code=' + Code + ' 收 ' + State.C2s + ' 条 / 发 ' + State.S2c + ' 条' +
|
||||
(DroppedFrames ? ' 丢弃 ' + DroppedFrames + ' 帧' : ''),
|
||||
);
|
||||
CloseSession();
|
||||
});
|
||||
Client.on('error', (Err) => State.Log('客户端错误: ' + Err.message));
|
||||
});
|
||||
@@ -471,5 +643,7 @@ Server.listen(PORT, () => {
|
||||
console.log('游戏通信服务器已启动: ws://localhost:' + PORT + '/');
|
||||
console.log(' 模式 : relay → ' + UPSTREAM);
|
||||
console.log(' 抓包目录: ' + PACKET_DIR);
|
||||
console.log(' 落盘策略: ' + (NeedDisk ? ('dump-every=' + DUMP_EVERY + ' log=' + (WRITE_LOG ? 'on' : 'off')) : '不落盘(只转发+实时解析;要抓包加 --dump-every 1 --log 1)'));
|
||||
console.log(' 转发策略: 原样直发(零等待零缓存);上游未就绪时反压暂停客户端读取,断开后每 ' + RECONNECT_MS + 'ms 重连');
|
||||
console.log(' 实时解析: 明文直解;加密段自动穷举密钥后实时解密;zlib 压缩帧自动解压');
|
||||
});
|
||||
@@ -1,60 +0,0 @@
|
||||
var __script_base_url__=(typeof document!=="undefined"&&document.currentScript&&document.currentScript.src)?document.currentScript.src.replace(/[^\/]+$/,""):"./";!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.Launcher=n():t.Launcher=n()}(globalThis,async()=>{
|
||||
|
||||
// ===== 切割版模块加载器 =====
|
||||
window.__modules__ = {};
|
||||
const __base_url__ = window.__script_base_url__ || './';
|
||||
|
||||
// 6.1 加载资源模块 (从 resources.json 批量注册)
|
||||
const __resource_resp__ = await fetch(__base_url__ + 'unpacked/resources.json');
|
||||
if (!__resource_resp__.ok) throw new Error('resources.json load failed: HTTP ' + __resource_resp__.status);
|
||||
const __resource_data__ = await __resource_resp__.json();
|
||||
const __resource_map__ = __resource_data__.resourceMap;
|
||||
for (const __id__ in __resource_map__) {
|
||||
if (!Object.prototype.hasOwnProperty.call(__resource_map__, __id__)) continue;
|
||||
const __path__ = __resource_map__[__id__];
|
||||
const __id_num__ = Number(__id__);
|
||||
window.__modules__[__id_num__] = (function(__p__) {
|
||||
return (t, n, i) => {
|
||||
"use strict";
|
||||
t.exports = i.p + __p__;
|
||||
};
|
||||
})(__path__);
|
||||
}
|
||||
|
||||
// 6.2 加载代码模块 (fetch + eval 独立文件)
|
||||
const __code_ids__ = [806,905,1510,1901,3535,3569,7426,7552,7793,9345,9539,9963,10032,10283,10849,12218,13431,13532,13754,14766,15152,15330,15831,16100,17259,17323,18334,19074,19487,21300,21973,24635,24923,25377,26482,27736,28485,29518,29545,29554,30285,31509,31584,31620,31908,32088,36659,36734,37036,37504,38335,40293,41164,42920,43319,44740,44794,45555,45686,47243,48576,50824,51233,51400,51887,52943,54199,55088,55520,55920,56077,57128,57328,58309,59131,59411,60273,60824,61378,61430,61860,63383,64280,64477,65201,66610,67222,69682,70130,70298,71105,71426,72834,73932,74897,75453,76074,77249,77672,78231,78931,79763,80397,80693,81886,82347,84441,85183,85196,85667,85745,87072,88693,89613,89679,89803,90225,90875,92980,94090,94965,96480,97556,97675,99295,99527];
|
||||
await Promise.all(__code_ids__.map(async (__id__) => {
|
||||
const __padded__ = typeof __id__ === 'number' ? String(__id__).padStart(5, '0') : __id__;
|
||||
const __url__ = __base_url__ + 'unpacked/module_' + __padded__ + '.js';
|
||||
const __resp__ = await fetch(__url__);
|
||||
if (!__resp__.ok) throw new Error('Module ' + __id__ + ' load failed: HTTP ' + __resp__.status + ' @ ' + __url__);
|
||||
const __code__ = await __resp__.text();
|
||||
(0, eval)(__code__);
|
||||
}));
|
||||
|
||||
var __webpack_modules__ = window.__modules__;
|
||||
|
||||
// ===== 原 webpack runtime (一字未改) =====
|
||||
;var __webpack_module_cache__={};function __webpack_require__(t){var n=__webpack_module_cache__[t];if(void 0!==n)return n.exports;var i=__webpack_module_cache__[t]={id:t,loaded:!1,exports:{}};return __webpack_modules__[t].call(i.exports,i,i.exports,__webpack_require__),i.loaded=!0,i.exports}__webpack_require__.n=t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return __webpack_require__.d(n,{a:n}),n},__webpack_require__.d=(t,n)=>{for(var i in n)__webpack_require__.o(n,i)&&!__webpack_require__.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:n[i]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),__webpack_require__.hmd=t=>((t=Object.create(t)).children||(t.children=[]),Object.defineProperty(t,"exports",{enumerable:!0,set:()=>{throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+t.id)}}),t),__webpack_require__.o=(t,n)=>Object.prototype.hasOwnProperty.call(t,n),__webpack_require__.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},__webpack_require__.p="/play/",__webpack_require__(76074),__webpack_require__(13431),__webpack_require__(26482);var __webpack_exports__=__webpack_require__(78231);
|
||||
// ===== 暴露 webpack require(hornet 工具链 hook_gamemode/hornet_lib 依赖)=====
|
||||
window.__wp_require__ = __webpack_require__;
|
||||
|
||||
// ===== 加载 hornet_bundle(默认关闭:URL 加 ?hornet=1 才加载,避免日志遮挡)=====
|
||||
if (/[?&]hornet=1(&|$)/.test(location.search)) {
|
||||
try {
|
||||
const __hornet_url__ = __base_url__ + 'unpacked/hornet_bundle.js';
|
||||
const __hornet_resp__ = await fetch(__hornet_url__);
|
||||
if (__hornet_resp__.ok) {
|
||||
const __hornet_code__ = await __hornet_resp__.text();
|
||||
(0, eval)(__hornet_code__);
|
||||
console.log('[Hornet] bundle 已加载');
|
||||
} else {
|
||||
console.warn('[Hornet] bundle 加载失败: HTTP ' + __hornet_resp__.status);
|
||||
}
|
||||
} catch (__hornet_err__) {
|
||||
console.error('[Hornet] bundle 加载异常:', __hornet_err__);
|
||||
}
|
||||
}
|
||||
|
||||
return __webpack_exports__;
|
||||
})//# sourceMappingURL=main.6469b966.js.map
|
||||
@@ -0,0 +1,146 @@
|
||||
console.log('Launcher loaded');
|
||||
|
||||
var __script_base_url__=(typeof document!=="undefined"&&document.currentScript&&document.currentScript.src)?document.currentScript.src.replace(/[^\/]+$/,""):"./";!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.Launcher=n():t.Launcher=n()}(globalThis,async()=>{
|
||||
|
||||
// ===== 切割版模块加载器 =====
|
||||
window.__modules__ = {};
|
||||
const __base_url__ = window.__script_base_url__ || './';
|
||||
|
||||
// 6.0 单包(unpacked.pack.json):一次请求拿到 resources.json + 全部代码模块,
|
||||
// 避免 126 个小文件碎请求;没有包时自动回退逐文件加载(见 6.2)
|
||||
const __pack_files__ = await (async () => {
|
||||
try {
|
||||
const __pack_resp__ = await fetch(__base_url__ + 'unpacked.pack.json', { cache: 'no-cache' });
|
||||
if (!__pack_resp__.ok) {
|
||||
console.warn('[Hornet] 单包不可用(HTTP ' + __pack_resp__.status + '),回退逐文件加载');
|
||||
return null;
|
||||
}
|
||||
const __pack__ = await __pack_resp__.json();
|
||||
console.log('[Hornet] 单包已载入: ' + (__pack__.count || 0) + ' 个文件 版本=' + __pack__.version);
|
||||
return __pack__.files || null;
|
||||
} catch (__pack_err__) {
|
||||
console.warn('[Hornet] 单包不可用,回退逐文件加载: ' + (__pack_err__ && __pack_err__.message));
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
// 6.1 加载资源模块 (resources.json;优先从单包里取)
|
||||
let __resource_data__ = null;
|
||||
if (__pack_files__ && typeof __pack_files__['resources.json'] === 'string') {
|
||||
__resource_data__ = JSON.parse(__pack_files__['resources.json']);
|
||||
} else {
|
||||
const __resource_resp__ = await fetch(__base_url__ + 'unpacked/resources.json');
|
||||
if (!__resource_resp__.ok) throw new Error('resources.json load failed: HTTP ' + __resource_resp__.status);
|
||||
__resource_data__ = await __resource_resp__.json();
|
||||
}
|
||||
const __resource_map__ = __resource_data__.resourceMap;
|
||||
for (const __id__ in __resource_map__) {
|
||||
if (!Object.prototype.hasOwnProperty.call(__resource_map__, __id__)) continue;
|
||||
const __path__ = __resource_map__[__id__];
|
||||
const __id_num__ = Number(__id__);
|
||||
window.__modules__[__id_num__] = (function(__p__) {
|
||||
return (t, n, i) => {
|
||||
"use strict";
|
||||
t.exports = i.p + __p__;
|
||||
};
|
||||
})(__path__);
|
||||
}
|
||||
|
||||
// 6.2 加载代码模块:单包命中直接 eval(无网络请求);缺的/没包时回退逐文件 fetch
|
||||
const __code_ids__ = [806,905,1510,1901,3535,3569,7426,7552,7793,9345,9539,9963,10032,10283,10849,12218,13431,13532,13754,14766,15152,15330,15831,16100,17259,17323,18334,19074,19487,21300,21973,24635,24923,25377,26482,27736,28485,29518,29545,29554,30285,31509,31584,31620,31908,32088,36659,36734,37036,37504,38335,40293,41164,42920,43319,44740,44794,45555,45686,47243,48576,50824,51233,51400,51887,52943,54199,55088,55520,55920,56077,57128,57328,58309,59131,59411,60273,60824,61378,61430,61860,63383,64280,64477,65201,66610,67222,69682,70130,70298,71105,71426,72834,73932,74897,75453,76074,77249,77672,78231,78931,79763,80397,80693,81886,82347,84441,85183,85196,85667,85745,87072,88693,89613,89679,89803,90225,90875,92980,94090,94965,96480,97556,97675,99295,99527];
|
||||
const __mod_name__ = (__id__) => 'module_' + (typeof __id__ === 'number' ? String(__id__).padStart(5, '0') : __id__) + '.js';
|
||||
const __missing__ = [];
|
||||
for (const __id__ of __code_ids__) {
|
||||
const __name__ = __mod_name__(__id__);
|
||||
const __src__ = __pack_files__ ? __pack_files__[__name__] : null;
|
||||
if (typeof __src__ === 'string') (0, eval)(__src__);
|
||||
else __missing__.push(__id__);
|
||||
}
|
||||
if (__missing__.length) {
|
||||
if (__pack_files__) console.warn('[Hornet] 单包缺少 ' + __missing__.length + ' 个模块,回退逐文件加载');
|
||||
await Promise.all(__missing__.map(async (__id__) => {
|
||||
const __url__ = __base_url__ + 'unpacked/' + __mod_name__(__id__);
|
||||
const __resp__ = await fetch(__url__);
|
||||
if (!__resp__.ok) throw new Error('Module ' + __id__ + ' load failed: HTTP ' + __resp__.status + ' @ ' + __url__);
|
||||
(0, eval)(await __resp__.text());
|
||||
}));
|
||||
}
|
||||
|
||||
var __webpack_modules__ = window.__modules__;
|
||||
|
||||
// ===== 原 webpack runtime (一字未改) =====
|
||||
;var __webpack_module_cache__={};function __webpack_require__(t){var n=__webpack_module_cache__[t];if(void 0!==n)return n.exports;var i=__webpack_module_cache__[t]={id:t,loaded:!1,exports:{}};return __webpack_modules__[t].call(i.exports,i,i.exports,__webpack_require__),i.loaded=!0,i.exports}__webpack_require__.n=t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return __webpack_require__.d(n,{a:n}),n},__webpack_require__.d=(t,n)=>{for(var i in n)__webpack_require__.o(n,i)&&!__webpack_require__.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:n[i]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),__webpack_require__.hmd=t=>((t=Object.create(t)).children||(t.children=[]),Object.defineProperty(t,"exports",{enumerable:!0,set:()=>{throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+t.id)}}),t),__webpack_require__.o=(t,n)=>Object.prototype.hasOwnProperty.call(t,n),__webpack_require__.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},__webpack_require__.p="/play/",__webpack_require__(76074),__webpack_require__(13431),__webpack_require__(26482);var __webpack_exports__=__webpack_require__(78231);
|
||||
// ===== 暴露 webpack require(hornet 工具链 hook_gamemode/hornet_lib 依赖)=====
|
||||
window.__wp_require__ = __webpack_require__;
|
||||
|
||||
// ===== 出错时不自动刷新页面 =====
|
||||
// 游戏在致命错误/断线后会调用 location.reload(),err toast 一闪就被刷掉、看不到原因。
|
||||
// 这里拦截自动刷新并保留页面:
|
||||
// ① 直接接管 location.reload(Chrome 上 Location 成员可能不可写,写入失败则走 ②)
|
||||
// ② 兜底装 beforeunload 守卫(浏览器会问"确定离开?",取消即可留在页面看 toast)
|
||||
// 需要刷新时按 F5:会先放行一次守卫,再用原始 reload 真正刷新。
|
||||
var __hornetRealReload__ = window.location.reload.bind(window.location);
|
||||
var __reloadHijacked__ = false;
|
||||
try {
|
||||
window.location.reload = function () {
|
||||
console.warn('[Hornet] 已拦截自动刷新(保留页面,便于查看 err toast)。调用栈:\n' + new Error().stack);
|
||||
};
|
||||
__reloadHijacked__ = (window.location.reload !== __hornetRealReload__);
|
||||
} catch (__reloadErr__) { __reloadHijacked__ = false; }
|
||||
window.addEventListener('beforeunload', function (e) {
|
||||
if (window.__hornetAllowUnload__) { window.__hornetAllowUnload__ = false; return; } // F5 放行一次
|
||||
if (__reloadHijacked__) return; // 已由 ① 接管
|
||||
e.preventDefault();
|
||||
e.returnValue = '';
|
||||
});
|
||||
console.log('[Hornet] 自动刷新拦截: ' + (__reloadHijacked__ ? 'location.reload 已接管' : 'beforeunload 守卫'));
|
||||
|
||||
// ===== F5 刷新页面(游戏会吞掉 F5,这里在捕获阶段兜底)=====
|
||||
window.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'F5') {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
window.__hornetAllowUnload__ = true;
|
||||
__hornetRealReload__();
|
||||
}
|
||||
}, true);
|
||||
|
||||
// ===== 加载 hornet_bundle(默认加载;纯净页面用 #nohornet)=====
|
||||
// 开关必须用 hash,不能用查询串:游戏在 module_13431 里把 location.search 的**所有**查询参数
|
||||
// 注册成 config 参数,于是 ?hornet=1 会让 Hash Request 多出一个资源名 "hornet",真实服务器直接关闭连接(1005)。
|
||||
if (/[?&]hornet=1(&|$)/.test(location.search)) {
|
||||
console.warn('[Hornet] 请勿使用 ?hornet=1:查询参数会被游戏当成 config 参数,导致上游握手失败(1005)');
|
||||
}
|
||||
if (!/#nohornet/.test(location.hash) && !window.__hornetTools__) {
|
||||
try {
|
||||
const __hornet_url__ = __base_url__ + 'unpacked/hornet_bundle.js';
|
||||
const __hornet_resp__ = await fetch(__hornet_url__);
|
||||
if (__hornet_resp__.ok) {
|
||||
const __hornet_code__ = await __hornet_resp__.text();
|
||||
(0, eval)(__hornet_code__);
|
||||
console.log('[Hornet] bundle 已加载');
|
||||
} else {
|
||||
console.warn('[Hornet] bundle 加载失败: HTTP ' + __hornet_resp__.status);
|
||||
}
|
||||
} catch (__hornet_err__) {
|
||||
console.error('[Hornet] bundle 加载异常:', __hornet_err__);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 注册 Service Worker(仅本机镜像)
|
||||
// 作用域必须是 /:首页 / 发起的 /play/... 请求才会被接管(serve.js 已放行 Service-Worker-Allowed)
|
||||
// 用途:把 unpacked 下的散装小文件用单包就地命中(hornet_sw.js 内置单包缓存)
|
||||
if ('serviceWorker' in navigator && /^(localhost|127\.0\.0\.1|\[::1\])$/.test(location.hostname)) {
|
||||
navigator.serviceWorker
|
||||
.register('/hornet_sw.js', { scope: '/', updateViaCache: 'none' })
|
||||
.then(function (Reg) {
|
||||
console.log('[Hornet] Service Worker 就绪(作用域 ' + Reg.scope + '),unpacked 小文件将由单包命中');
|
||||
return Reg.update();
|
||||
})
|
||||
.catch(function (Err) {
|
||||
console.warn('[Hornet] Service Worker 注册失败: ' + (Err && Err.message));
|
||||
});
|
||||
}
|
||||
|
||||
return __webpack_exports__;
|
||||
})//# sourceMappingURL=main.9f4e7a89.js.map
|
||||
File diff suppressed because it is too large.
Load diff
+25157
-25148
File diff suppressed because it is too large.
Load diff
@@ -94,32 +94,32 @@
|
||||
It = y.$_$.h3,
|
||||
At = k.$_$.a,
|
||||
Rt = y.$_$.g3,
|
||||
Pt = b.$_$.m1e,
|
||||
Pt = b.$_$.o1e,
|
||||
Nt = y.$_$.u,
|
||||
Ot = b.$_$.mo,
|
||||
Mt = b.$_$.at,
|
||||
Dt = b.$_$.ss,
|
||||
Lt = b.$_$.n1d,
|
||||
Bt = b.$_$.m1f,
|
||||
Ut = b.$_$.u1d,
|
||||
Ft = b.$_$.k1f,
|
||||
Gt = b.$_$.t1d,
|
||||
Ht = b.$_$.z1e,
|
||||
Wt = b.$_$.t1c,
|
||||
Vt = b.$_$.s1c,
|
||||
Kt = b.$_$.ho,
|
||||
Ot = b.$_$.no,
|
||||
Mt = b.$_$.bt,
|
||||
Dt = b.$_$.ts,
|
||||
Lt = b.$_$.p1d,
|
||||
Bt = b.$_$.o1f,
|
||||
Ut = b.$_$.w1d,
|
||||
Ft = b.$_$.m1f,
|
||||
Gt = b.$_$.v1d,
|
||||
Ht = b.$_$.b1f,
|
||||
Wt = b.$_$.v1c,
|
||||
Vt = b.$_$.u1c,
|
||||
Kt = b.$_$.io,
|
||||
Yt = y.$_$.q1,
|
||||
Xt = y.$_$.e4,
|
||||
Jt = b.$_$.fo,
|
||||
Zt = b.$_$.go,
|
||||
Qt = b.$_$.bl,
|
||||
Jt = b.$_$.go,
|
||||
Zt = b.$_$.ho,
|
||||
Qt = b.$_$.cl,
|
||||
tn = b.$_$.fi,
|
||||
nn = b.$_$.w18,
|
||||
nn = b.$_$.x18,
|
||||
rn = m.$_$.jb,
|
||||
en = m.$_$.vj,
|
||||
un = q.$_$.o,
|
||||
sn = m.$_$.td,
|
||||
on = b.$_$.en,
|
||||
on = b.$_$.fn,
|
||||
_n = m.$_$.ua,
|
||||
an = m.$_$.jd,
|
||||
hn = m.$_$.c,
|
||||
@@ -127,11 +127,11 @@
|
||||
ln = y.$_$.e3,
|
||||
vn = y.$_$.k3,
|
||||
wn = y.$_$.y2,
|
||||
pn = b.$_$.c1f,
|
||||
pn = b.$_$.e1f,
|
||||
dn = y.$_$.b4,
|
||||
gn = b.$_$.l1f,
|
||||
gn = b.$_$.n1f,
|
||||
mn = y.$_$.z2,
|
||||
yn = b.$_$.n1f,
|
||||
yn = b.$_$.p1f,
|
||||
kn = y.$_$.a3,
|
||||
bn = y.$_$.c2,
|
||||
qn = y.$_$.q,
|
||||
@@ -157,7 +157,7 @@
|
||||
Fn = z.$_$.f7,
|
||||
Gn = j.$_$.y9,
|
||||
Hn = b.$_$.af,
|
||||
Wn = b.$_$.zk,
|
||||
Wn = b.$_$.al,
|
||||
Vn = j.$_$.o8,
|
||||
Kn = j.$_$.w3,
|
||||
Yn = j.$_$.n8,
|
||||
@@ -177,15 +177,15 @@
|
||||
ai = b.$_$.df,
|
||||
hi = b.$_$.gg,
|
||||
ci = b.$_$.hf,
|
||||
li = b.$_$.c1g,
|
||||
fi = b.$_$.gm,
|
||||
li = b.$_$.e1g,
|
||||
fi = b.$_$.hm,
|
||||
vi = j.$_$.d4,
|
||||
wi = b.$_$.jv,
|
||||
wi = b.$_$.kv,
|
||||
pi = E.$_$.f,
|
||||
di = b.$_$.kv,
|
||||
di = b.$_$.lv,
|
||||
gi = E.$_$.i,
|
||||
mi = E.$_$.j,
|
||||
yi = b.$_$.lv,
|
||||
yi = b.$_$.mv,
|
||||
ki = E.$_$.k,
|
||||
bi = E.$_$.o,
|
||||
qi = T.$_$.b,
|
||||
@@ -227,7 +227,7 @@
|
||||
ur = m.$_$.rg,
|
||||
sr = j.$_$.x9,
|
||||
or = m.$_$.ad,
|
||||
_r = b.$_$.in,
|
||||
_r = b.$_$.jn,
|
||||
ar = j.$_$.c4,
|
||||
hr = J.$_$.j,
|
||||
cr = Z.$_$.k,
|
||||
@@ -239,7 +239,7 @@
|
||||
dr = Q.$_$.v,
|
||||
gr = tt.$_$.a,
|
||||
mr = z.$_$.b7,
|
||||
yr = b.$_$.w1r,
|
||||
yr = b.$_$.y1r,
|
||||
kr = nt.$_$.a,
|
||||
br = it.$_$.h,
|
||||
qr = rt.$_$.h2,
|
||||
@@ -248,9 +248,9 @@
|
||||
xr = Q.$_$.s,
|
||||
zr = T.$_$.y,
|
||||
Sr = it.$_$.c,
|
||||
Cr = b.$_$.a1p,
|
||||
Er = b.$_$.o1c,
|
||||
Tr = b.$_$.r1c,
|
||||
Cr = b.$_$.c1p,
|
||||
Er = b.$_$.q1c,
|
||||
Tr = b.$_$.t1c,
|
||||
Ir = y.$_$.c4,
|
||||
Ar = m.$_$.qj,
|
||||
Rr = m.$_$.yb,
|
||||
@@ -258,7 +258,7 @@
|
||||
Nr = m.$_$.sb,
|
||||
Or = rt.$_$.k8,
|
||||
Mr = j.$_$.a4,
|
||||
Dr = ut.$_$.yj,
|
||||
Dr = ut.$_$.zj,
|
||||
Lr = m.$_$.hd,
|
||||
Br = m.$_$.g7,
|
||||
Ur = j.$_$.t7,
|
||||
@@ -278,7 +278,7 @@
|
||||
ie = j.$_$.h1,
|
||||
re = j.$_$.i1,
|
||||
ee = j.$_$.j1,
|
||||
ue = b.$_$.r1r,
|
||||
ue = b.$_$.t1r,
|
||||
se = m.$_$.qf,
|
||||
oe = st.$_$.b,
|
||||
_e = y.$_$.t3,
|
||||
@@ -362,17 +362,17 @@
|
||||
);
|
||||
}
|
||||
function mu(t, n, i, r, e, u, s, o, _, a, h) {
|
||||
((this.d1wf_1 = t),
|
||||
(this.e1wf_1 = n),
|
||||
(this.f1wf_1 = i),
|
||||
(this.g1wf_1 = r),
|
||||
(this.h1wf_1 = e),
|
||||
(this.i1wf_1 = u),
|
||||
(this.j1wf_1 = s),
|
||||
(this.k1wf_1 = o),
|
||||
(this.l1wf_1 = _),
|
||||
(this.m1wf_1 = a),
|
||||
(this.n1wf_1 = h));
|
||||
((this.e1wf_1 = t),
|
||||
(this.f1wf_1 = n),
|
||||
(this.g1wf_1 = i),
|
||||
(this.h1wf_1 = r),
|
||||
(this.i1wf_1 = e),
|
||||
(this.j1wf_1 = u),
|
||||
(this.k1wf_1 = s),
|
||||
(this.l1wf_1 = o),
|
||||
(this.m1wf_1 = _),
|
||||
(this.n1wf_1 = a),
|
||||
(this.o1wf_1 = h));
|
||||
}
|
||||
function yu(t) {
|
||||
var n = document.visibilityState;
|
||||
@@ -458,13 +458,13 @@
|
||||
function Uu() {
|
||||
var t;
|
||||
(qn(ku, this),
|
||||
(this.a1wg_1 = (function () {
|
||||
(this.b1wg_1 = (function () {
|
||||
var t = function (t) {
|
||||
return (yu(), Ct);
|
||||
};
|
||||
return ((t.callableName = "onVisibilityChanged"), t);
|
||||
})()),
|
||||
(this.b1wg_1 =
|
||||
(this.c1wg_1 =
|
||||
(((t = function (t) {
|
||||
return (
|
||||
null != (n = document.activeElement) &&
|
||||
@@ -478,7 +478,7 @@
|
||||
var n;
|
||||
}).callableName = "onResize"),
|
||||
t)),
|
||||
(this.c1wg_1 = (function () {
|
||||
(this.d1wg_1 = (function () {
|
||||
var t = function (t) {
|
||||
return (
|
||||
(function (t, n) {
|
||||
@@ -491,8 +491,8 @@
|
||||
};
|
||||
return ((t.callableName = "onFocusOut"), t);
|
||||
})()),
|
||||
(this.d1wg_1 = !1),
|
||||
$n().w1su());
|
||||
(this.e1wg_1 = !1),
|
||||
$n().x1su());
|
||||
}
|
||||
function Fu() {
|
||||
return (ps(), ct);
|
||||
@@ -760,13 +760,13 @@
|
||||
return (_r.rt0(), Ct);
|
||||
}
|
||||
function ss(t, n) {
|
||||
((this.m1wg_1 = t), rn.call(this, n));
|
||||
((this.n1wg_1 = t), rn.call(this, n));
|
||||
}
|
||||
function os(t) {
|
||||
return (ps(), t.e2b(null, or("store", dt, !1)));
|
||||
}
|
||||
function _s(t) {
|
||||
this.o1wg_1 = t;
|
||||
this.p1wg_1 = t;
|
||||
}
|
||||
function as(t) {
|
||||
return (ps(), t.e2b(null, or("store", dt, !1)));
|
||||
@@ -788,7 +788,7 @@
|
||||
return Nr(t, i) > 0;
|
||||
}
|
||||
function vs(t, n, i) {
|
||||
(rn.call(this, i), (this.x1wg_1 = t), (this.y1wg_1 = n));
|
||||
(rn.call(this, i), (this.y1wg_1 = t), (this.z1wg_1 = n));
|
||||
}
|
||||
function ws() {}
|
||||
function ps() {
|
||||
@@ -819,11 +819,11 @@
|
||||
((i = t), i.e2b(null, or("store", dt, !1))).qao(new ue(p));
|
||||
}
|
||||
function gs(t, n) {
|
||||
((this.z1wg_1 = t), (this.a1wh_1 = n));
|
||||
((this.a1wh_1 = t), (this.b1wh_1 = n));
|
||||
}
|
||||
function ms(t) {
|
||||
var n = se;
|
||||
return t.g1wh_1.e2b(
|
||||
return t.h1wh_1.e2b(
|
||||
t,
|
||||
gt(
|
||||
"keyboardShortcutService",
|
||||
@@ -838,7 +838,7 @@
|
||||
}
|
||||
function ys(t) {
|
||||
if (t.props.runLoader) return Ct;
|
||||
(Nt().kap().qao(new Tr(!0)), null != t.m1i9_1.a1wh_1 && (ce().jqx(), location.reload()));
|
||||
(Nt().kap().qao(new Tr(!0)), null != t.m1i9_1.b1wh_1 && (ce().jqx(), location.reload()));
|
||||
}
|
||||
function ks(t, n, i) {
|
||||
return new gs(t.pao_1.lpr_1.zqx_1, t.pao_1.opp_1.rt2_1);
|
||||
@@ -872,7 +872,7 @@
|
||||
(e = xs),
|
||||
(u = oe.xum(e)).tuo().lp2(Hs().e1hc()),
|
||||
(function (t, n) {
|
||||
if (t.m1i9_1.z1wg_1 && Hn.tqw()) {
|
||||
if (t.m1i9_1.a1wh_1 && Hn.tqw()) {
|
||||
var i =
|
||||
((f = g),
|
||||
function (t) {
|
||||
@@ -881,14 +881,14 @@
|
||||
r = oe.xum(i),
|
||||
e = r.tuo();
|
||||
(ae(e, _e(224)), n.can(r.s9j()));
|
||||
} else if (t.m1i9_1.z1wg_1 && !Hn.tqw()) {
|
||||
} else if (t.m1i9_1.a1wh_1 && !Hn.tqw()) {
|
||||
var u = (function (t, n) {
|
||||
return function (t) {
|
||||
return new me(ge(["alt", null, "src", n]), t);
|
||||
};
|
||||
})(0, w),
|
||||
s = oe.xum(u);
|
||||
(s.tuo().lp2(Hs().s1wh(t.m1i9_1.z1wg_1)), n.can(s.s9j()));
|
||||
(s.tuo().lp2(Hs().t1wh(t.m1i9_1.a1wh_1)), n.can(s.s9j()));
|
||||
var o = (function (t, n) {
|
||||
return function (t) {
|
||||
return new me(ge(["alt", null, "src", n]), t);
|
||||
@@ -903,7 +903,7 @@
|
||||
};
|
||||
})(0, w),
|
||||
h = oe.xum(a);
|
||||
(h.tuo().lp2(Hs().s1wh(t.m1i9_1.z1wg_1)), n.can(h.s9j()));
|
||||
(h.tuo().lp2(Hs().t1wh(t.m1i9_1.a1wh_1)), n.can(h.s9j()));
|
||||
var c = (function (t, n) {
|
||||
return function (t) {
|
||||
return new me(ge(["alt", null, "src", n]), t);
|
||||
@@ -926,7 +926,7 @@
|
||||
o = oe.xum(s);
|
||||
(o.tuo().lp2(Hs().u1qx()), u.can(o.s9j()), r.can(u.s9j()), n.can(r.s9j()));
|
||||
})(0, u)
|
||||
: i.m1i9_1.z1wg_1 ||
|
||||
: i.m1i9_1.a1wh_1 ||
|
||||
(function (t, n) {
|
||||
var i = Es,
|
||||
r = oe.xum(i);
|
||||
@@ -965,13 +965,13 @@
|
||||
function Is() {
|
||||
var t;
|
||||
(qn(ks, this),
|
||||
(this.e1wh_1 =
|
||||
(this.f1wh_1 =
|
||||
((t = this),
|
||||
function (n) {
|
||||
return (ys(t), Ct);
|
||||
})),
|
||||
(this.f1wh_1 = null),
|
||||
(this.g1wh_1 = new Dn(St(ke), null)));
|
||||
(this.g1wh_1 = null),
|
||||
(this.h1wh_1 = new Dn(St(ke), null)));
|
||||
}
|
||||
function As(t) {
|
||||
return (t.lp2(Se().o1hb()), t.lp2(be().s1hj()), Ee(t, Ce().pp3_1), Ie(t, Te()), Re(t, Ae()), Ct);
|
||||
@@ -1030,7 +1030,7 @@
|
||||
((ft = this), wu.call(this, pu(St(Gs).o())));
|
||||
var t = this.auq([], As),
|
||||
n = se;
|
||||
this.m1wh_1 = t.suo(
|
||||
this.n1wh_1 = t.suo(
|
||||
this,
|
||||
gt(
|
||||
"mainContainer",
|
||||
@@ -1044,7 +1044,7 @@
|
||||
);
|
||||
var i = this.auq([], Rs),
|
||||
r = se;
|
||||
this.n1wh_1 = i.suo(
|
||||
this.o1wh_1 = i.suo(
|
||||
this,
|
||||
gt(
|
||||
"loadingBlock",
|
||||
@@ -1058,7 +1058,7 @@
|
||||
);
|
||||
var e = this.auq([], Ps),
|
||||
u = se;
|
||||
this.o1wh_1 = e.suo(
|
||||
this.p1wh_1 = e.suo(
|
||||
this,
|
||||
gt(
|
||||
"logoTankOnline",
|
||||
@@ -1072,7 +1072,7 @@
|
||||
);
|
||||
var s = this.auq([], Ns),
|
||||
o = se;
|
||||
this.p1wh_1 = s.suo(
|
||||
this.q1wh_1 = s.suo(
|
||||
this,
|
||||
gt(
|
||||
"text",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
);
|
||||
var _ = this.auq([], Os),
|
||||
a = se;
|
||||
this.q1wh_1 = _.suo(
|
||||
this.r1wh_1 = _.suo(
|
||||
this,
|
||||
gt(
|
||||
"loaderContainer",
|
||||
@@ -1100,7 +1100,7 @@
|
||||
);
|
||||
var h = this.auq([], Ms),
|
||||
c = se;
|
||||
this.r1wh_1 = h.suo(
|
||||
this.s1wh_1 = h.suo(
|
||||
this,
|
||||
gt(
|
||||
"circleLoader",
|
||||
@@ -1129,60 +1129,60 @@
|
||||
(kt(mu).toString = function () {
|
||||
return (
|
||||
"State(isUserPropertiesLoaded=" +
|
||||
this.d1wf_1 +
|
||||
this.e1wf_1 +
|
||||
", currentScreen=" +
|
||||
mt(this.e1wf_1) +
|
||||
mt(this.f1wf_1) +
|
||||
", fatalError=" +
|
||||
yt(this.f1wf_1) +
|
||||
yt(this.g1wf_1) +
|
||||
", inBattle=" +
|
||||
this.g1wf_1 +
|
||||
", graphicsQualityDetectCompleted=" +
|
||||
this.h1wf_1 +
|
||||
", isInPartnerEnvironment=" +
|
||||
", graphicsQualityDetectCompleted=" +
|
||||
this.i1wf_1 +
|
||||
", partnerId=" +
|
||||
", isInPartnerEnvironment=" +
|
||||
this.j1wf_1 +
|
||||
", isPressedAnyButton=" +
|
||||
", partnerId=" +
|
||||
this.k1wf_1 +
|
||||
", isDisplayMainEntranceScreen=" +
|
||||
", isPressedAnyButton=" +
|
||||
this.l1wf_1 +
|
||||
", controlsForChina=" +
|
||||
", isDisplayMainEntranceScreen=" +
|
||||
this.m1wf_1 +
|
||||
", isDisplayClientInfo=" +
|
||||
", controlsForChina=" +
|
||||
this.n1wf_1 +
|
||||
", isDisplayClientInfo=" +
|
||||
this.o1wf_1 +
|
||||
")"
|
||||
);
|
||||
}),
|
||||
(kt(mu).hashCode = function () {
|
||||
var t = bt(this.d1wf_1);
|
||||
var t = bt(this.e1wf_1);
|
||||
return (
|
||||
(t = (vt(t, 31) + qt(this.e1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + (null == this.f1wf_1 ? 0 : qt(this.f1wf_1))) | 0),
|
||||
(t = (vt(t, 31) + bt(this.g1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + (null == this.h1wf_1 ? 0 : bt(this.h1wf_1))) | 0),
|
||||
(t = (vt(t, 31) + bt(this.i1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + (null == this.j1wf_1 ? 0 : $t(this.j1wf_1))) | 0),
|
||||
(t = (vt(t, 31) + bt(this.k1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + qt(this.f1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + (null == this.g1wf_1 ? 0 : qt(this.g1wf_1))) | 0),
|
||||
(t = (vt(t, 31) + bt(this.h1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + (null == this.i1wf_1 ? 0 : bt(this.i1wf_1))) | 0),
|
||||
(t = (vt(t, 31) + bt(this.j1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + (null == this.k1wf_1 ? 0 : $t(this.k1wf_1))) | 0),
|
||||
(t = (vt(t, 31) + bt(this.l1wf_1)) | 0),
|
||||
(t = (vt(t, 31) + bt(this.m1wf_1)) | 0),
|
||||
(vt(t, 31) + bt(this.n1wf_1)) | 0
|
||||
(t = (vt(t, 31) + bt(this.n1wf_1)) | 0),
|
||||
(vt(t, 31) + bt(this.o1wf_1)) | 0
|
||||
);
|
||||
}),
|
||||
(kt(mu).equals = function (t) {
|
||||
return (
|
||||
this === t ||
|
||||
(t instanceof mu &&
|
||||
this.d1wf_1 === t.d1wf_1 &&
|
||||
!!jt(this.e1wf_1, t.e1wf_1) &&
|
||||
this.e1wf_1 === t.e1wf_1 &&
|
||||
!!jt(this.f1wf_1, t.f1wf_1) &&
|
||||
this.g1wf_1 === t.g1wf_1 &&
|
||||
this.h1wf_1 == t.h1wf_1 &&
|
||||
this.i1wf_1 === t.i1wf_1 &&
|
||||
this.j1wf_1 == t.j1wf_1 &&
|
||||
this.k1wf_1 === t.k1wf_1 &&
|
||||
!!jt(this.g1wf_1, t.g1wf_1) &&
|
||||
this.h1wf_1 === t.h1wf_1 &&
|
||||
this.i1wf_1 == t.i1wf_1 &&
|
||||
this.j1wf_1 === t.j1wf_1 &&
|
||||
this.k1wf_1 == t.k1wf_1 &&
|
||||
this.l1wf_1 === t.l1wf_1 &&
|
||||
this.m1wf_1 === t.m1wf_1 &&
|
||||
this.n1wf_1 === t.n1wf_1)
|
||||
this.n1wf_1 === t.n1wf_1 &&
|
||||
this.o1wf_1 === t.o1wf_1)
|
||||
);
|
||||
}),
|
||||
(kt(qu).f7d = function (t, n) {
|
||||
@@ -1213,33 +1213,33 @@
|
||||
}),
|
||||
(kt(qu).g7d = function (t, n) {
|
||||
var i = new qu(n);
|
||||
return ((i.w1wf_1 = t), i);
|
||||
return ((i.x1wf_1 = t), i);
|
||||
}),
|
||||
(kt(Uu).n1h7 = function () {
|
||||
(jn().dot(xn()), gu().e2e().equals(Sn()) && zn().h1sv() && zn().g1sv(bu));
|
||||
(jn().dot(xn()), gu().e2e().equals(Sn()) && zn().i1sv() && zn().h1sv(bu));
|
||||
var t = document;
|
||||
Cn(t, "visibilitychange", this.a1wg_1);
|
||||
Cn(t, "visibilitychange", this.b1wg_1);
|
||||
var n = window;
|
||||
Cn(n, "resize", this.b1wg_1);
|
||||
Cn(n, "resize", this.c1wg_1);
|
||||
var i = window;
|
||||
(Cn(i, "focusout", this.c1wg_1), yu());
|
||||
(Cn(i, "focusout", this.d1wg_1), yu());
|
||||
}),
|
||||
(kt(Uu).componentDidMount = function () {
|
||||
return this.n1h7();
|
||||
}),
|
||||
(kt(Uu).uar = function () {
|
||||
var t = document;
|
||||
En(t, "visibilitychange", this.a1wg_1);
|
||||
En(t, "visibilitychange", this.b1wg_1);
|
||||
var n = window;
|
||||
En(n, "resize", this.b1wg_1);
|
||||
En(n, "resize", this.c1wg_1);
|
||||
var i = window;
|
||||
En(i, "focusout", this.c1wg_1);
|
||||
En(i, "focusout", this.d1wg_1);
|
||||
}),
|
||||
(kt(Uu).tan = function (t) {
|
||||
var n, i;
|
||||
!0 === this.m1i9_1.h1wf_1 ||
|
||||
this.d1wg_1 ||
|
||||
((this.d1wg_1 = !0),
|
||||
!0 === this.m1i9_1.i1wf_1 ||
|
||||
this.e1wg_1 ||
|
||||
((this.e1wg_1 = !0),
|
||||
In(
|
||||
Tn,
|
||||
hn,
|
||||
@@ -1253,9 +1253,9 @@
|
||||
));
|
||||
var r,
|
||||
e,
|
||||
u = this.m1i9_1.f1wf_1,
|
||||
u = this.m1i9_1.g1wf_1,
|
||||
s = St(An);
|
||||
if ((t.ian(s, $u), this.m1i9_1.k1wf_1 && null == u)) {
|
||||
if ((t.ian(s, $u), this.m1i9_1.l1wf_1 && null == u)) {
|
||||
var o = St(Rn);
|
||||
t.ian(
|
||||
o,
|
||||
@@ -1266,8 +1266,8 @@
|
||||
var i = St(ln);
|
||||
t.ian(i, xu);
|
||||
var r = St(vn);
|
||||
if ((t.ian(r, zu), e.m1i9_1.i1wf_1 && null == e.m1i9_1.j1wf_1)) return Ct;
|
||||
var u = e.m1i9_1.e1wf_1;
|
||||
if ((t.ian(r, zu), e.m1i9_1.j1wf_1 && null == e.m1i9_1.k1wf_1)) return Ct;
|
||||
var u = e.m1i9_1.f1wf_1;
|
||||
if (u instanceof Lt) {
|
||||
var s = St(kn);
|
||||
t.ian(s, Su);
|
||||
@@ -1288,8 +1288,8 @@
|
||||
(function (t) {
|
||||
return function (n) {
|
||||
return (
|
||||
(n.currentScreen = t.m1i9_1.e1wf_1),
|
||||
(n.controlsForChina = t.m1i9_1.m1wf_1),
|
||||
(n.currentScreen = t.m1i9_1.f1wf_1),
|
||||
(n.controlsForChina = t.m1i9_1.n1wf_1),
|
||||
Ct
|
||||
);
|
||||
};
|
||||
@@ -1302,8 +1302,8 @@
|
||||
);
|
||||
} else
|
||||
!(function (t, n) {
|
||||
var i = t.m1i9_1.e1wf_1;
|
||||
if (!0 !== t.m1i9_1.h1wf_1 || !t.m1i9_1.d1wf_1) {
|
||||
var i = t.m1i9_1.f1wf_1;
|
||||
if (!0 !== t.m1i9_1.i1wf_1 || !t.m1i9_1.e1wf_1) {
|
||||
var r = St(zt);
|
||||
return (n.ian(r, Ru), Ct);
|
||||
}
|
||||
@@ -1314,10 +1314,10 @@
|
||||
!(function (t) {
|
||||
return (
|
||||
!!(
|
||||
t.m1i9_1.g1wf_1 ||
|
||||
t.m1i9_1.e1wf_1 instanceof Lt ||
|
||||
t.m1i9_1.e1wf_1 instanceof Bt
|
||||
) || t.m1i9_1.e1wf_1 instanceof Ut
|
||||
t.m1i9_1.h1wf_1 ||
|
||||
t.m1i9_1.f1wf_1 instanceof Lt ||
|
||||
t.m1i9_1.f1wf_1 instanceof Bt
|
||||
) || t.m1i9_1.f1wf_1 instanceof Ut
|
||||
);
|
||||
})(t))
|
||||
) {
|
||||
@@ -1340,14 +1340,14 @@
|
||||
);
|
||||
})(0, i)
|
||||
)
|
||||
if (t.m1i9_1.g1wf_1) {
|
||||
if (t.m1i9_1.h1wf_1) {
|
||||
var _ = St(At);
|
||||
n.ian(_, Mu);
|
||||
} else {
|
||||
var a = St(It);
|
||||
n.ian(a, Du);
|
||||
}
|
||||
else if (t.m1i9_1.l1wf_1) {
|
||||
else if (t.m1i9_1.m1wf_1) {
|
||||
var h = St(zt);
|
||||
n.ian(h, Lu);
|
||||
} else {
|
||||
@@ -1372,7 +1372,7 @@
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (this.m1i9_1.n1wf_1) {
|
||||
if (this.m1i9_1.o1wf_1) {
|
||||
var c = St(On);
|
||||
t.ian(c, Au);
|
||||
}
|
||||
@@ -1391,7 +1391,7 @@
|
||||
switch (this.j9_1) {
|
||||
case 0:
|
||||
((this.k9_1 = 3),
|
||||
Hu(this.m1wg_1),
|
||||
Hu(this.n1wg_1),
|
||||
ar(Fu()),
|
||||
Fi() && (window._cmd = is),
|
||||
hr(),
|
||||
@@ -1422,7 +1422,7 @@
|
||||
continue t;
|
||||
case 2:
|
||||
if (Qn().x74() < 3) return (Ju(), Ct);
|
||||
(Xu(), Zu(), Qu(this.m1wg_1));
|
||||
(Xu(), Zu(), Qu(this.n1wg_1));
|
||||
var i = new Dn(St(xr), null);
|
||||
return ((rs(i).n83_1 = es), (rs(i).m83_1 = us), zr(Fu()), Sr().iwa(), Ct);
|
||||
case 3:
|
||||
@@ -1435,15 +1435,15 @@
|
||||
}
|
||||
}),
|
||||
(kt(ss).g7d = function (t, n) {
|
||||
var i = new ss(this.m1wg_1, n);
|
||||
return ((i.n1wg_1 = t), i);
|
||||
var i = new ss(this.n1wg_1, n);
|
||||
return ((i.o1wg_1 = t), i);
|
||||
}),
|
||||
(kt(_s).z7r = function (t) {
|
||||
var n = this.o1wg_1.m();
|
||||
var n = this.p1wg_1.m();
|
||||
t.g3("bridge", n);
|
||||
var i = this.o1wg_1.pok().hok_1.toString();
|
||||
var i = this.p1wg_1.pok().hok_1.toString();
|
||||
t.g3("bridge_version", i);
|
||||
var r = this.o1wg_1.pok().iok_1.toString();
|
||||
var r = this.p1wg_1.pok().iok_1.toString();
|
||||
t.g3("bridge_native_version", r);
|
||||
}),
|
||||
(kt(vs).r9 = function () {
|
||||
@@ -1452,7 +1452,7 @@
|
||||
try {
|
||||
switch (this.j9_1) {
|
||||
case 0:
|
||||
if (((this.k9_1 = 3), fs(this.y1wg_1))) {
|
||||
if (((this.k9_1 = 3), fs(this.z1wg_1))) {
|
||||
if (((Or.u1fm_1 = Mr()), (this.j9_1 = 1), (t = Dr().wpc(this)) === _n())) return t;
|
||||
continue t;
|
||||
}
|
||||
@@ -1477,19 +1477,19 @@
|
||||
return ((i.l9_1 = Ct), (i.m9_1 = null), i.r9());
|
||||
}),
|
||||
(kt(gs).toString = function () {
|
||||
return "State(controlsForChina=" + this.z1wg_1 + ", fatalError=" + yt(this.a1wh_1) + ")";
|
||||
return "State(controlsForChina=" + this.a1wh_1 + ", fatalError=" + yt(this.b1wh_1) + ")";
|
||||
}),
|
||||
(kt(gs).hashCode = function () {
|
||||
var t = bt(this.z1wg_1);
|
||||
return (vt(t, 31) + (null == this.a1wh_1 ? 0 : qt(this.a1wh_1))) | 0;
|
||||
var t = bt(this.a1wh_1);
|
||||
return (vt(t, 31) + (null == this.b1wh_1 ? 0 : qt(this.b1wh_1))) | 0;
|
||||
}),
|
||||
(kt(gs).equals = function (t) {
|
||||
return this === t || (t instanceof gs && this.z1wg_1 === t.z1wg_1 && !!jt(this.a1wh_1, t.a1wh_1));
|
||||
return this === t || (t instanceof gs && this.a1wh_1 === t.a1wh_1 && !!jt(this.b1wh_1, t.b1wh_1));
|
||||
}),
|
||||
(kt(Is).par = function () {
|
||||
var t;
|
||||
(this.props.runLoader &&
|
||||
(this.f1wh_1 = setTimeout(
|
||||
(this.g1wh_1 = setTimeout(
|
||||
((t = this),
|
||||
function () {
|
||||
return (Gn().k2a(t, new le()), Ct);
|
||||
@@ -1504,7 +1504,7 @@
|
||||
})(this),
|
||||
));
|
||||
var n = window;
|
||||
Cn(n, "click", this.e1wh_1);
|
||||
Cn(n, "click", this.f1wh_1);
|
||||
}),
|
||||
(kt(Is).componentWillMount = function () {
|
||||
return this.par();
|
||||
@@ -1512,11 +1512,11 @@
|
||||
(kt(Is).uar = function () {
|
||||
ms(this).p2l();
|
||||
var t = window;
|
||||
(En(t, "click", this.e1wh_1), clearTimeout(this.f1wh_1));
|
||||
(En(t, "click", this.f1wh_1), clearTimeout(this.g1wh_1));
|
||||
}),
|
||||
(kt(Is).n1h7 = function () {
|
||||
this.props.runLoader ||
|
||||
((1 == window.skipEntranceAnyKey || ce().iqx() || this.m1i9_1.z1wg_1) && ys(this));
|
||||
((1 == window.skipEntranceAnyKey || ce().iqx() || this.m1i9_1.a1wh_1) && ys(this));
|
||||
}),
|
||||
(kt(Is).componentDidMount = function () {
|
||||
return this.n1h7();
|
||||
@@ -1530,7 +1530,7 @@
|
||||
u = oe.xum(e);
|
||||
u.tuo().lp2(be().x1na());
|
||||
var s = St(qe);
|
||||
if ((u.ian(s, $s(this)), i.can(u.s9j()), this.m1i9_1.z1wg_1 && !Hn.tqw())) {
|
||||
if ((u.ian(s, $s(this)), i.can(u.s9j()), this.m1i9_1.a1wh_1 && !Hn.tqw())) {
|
||||
var o = this.war($e().t1lx()),
|
||||
_ = js,
|
||||
a = oe.xum(_);
|
||||
@@ -1540,7 +1540,7 @@
|
||||
}),
|
||||
(kt(Gs).e1hc = function () {
|
||||
var t = se;
|
||||
return this.m1wh_1.dk(
|
||||
return this.n1wh_1.dk(
|
||||
this,
|
||||
gt(
|
||||
"mainContainer",
|
||||
@@ -1555,7 +1555,7 @@
|
||||
}),
|
||||
(kt(Gs).t1qx = function () {
|
||||
var t = se;
|
||||
return this.n1wh_1.dk(
|
||||
return this.o1wh_1.dk(
|
||||
this,
|
||||
gt(
|
||||
"loadingBlock",
|
||||
@@ -1568,7 +1568,7 @@
|
||||
),
|
||||
);
|
||||
}),
|
||||
(kt(Gs).s1wh = function (t) {
|
||||
(kt(Gs).t1wh = function (t) {
|
||||
return (
|
||||
(n = t),
|
||||
function (t) {
|
||||
@@ -1579,7 +1579,7 @@
|
||||
}),
|
||||
(kt(Gs).b1nr = function () {
|
||||
var t = se;
|
||||
return this.o1wh_1.dk(
|
||||
return this.p1wh_1.dk(
|
||||
this,
|
||||
gt(
|
||||
"logoTankOnline",
|
||||
@@ -1594,7 +1594,7 @@
|
||||
}),
|
||||
(kt(Gs).qcj = function () {
|
||||
var t = se;
|
||||
return this.p1wh_1.dk(
|
||||
return this.q1wh_1.dk(
|
||||
this,
|
||||
gt(
|
||||
"text",
|
||||
@@ -1609,7 +1609,7 @@
|
||||
}),
|
||||
(kt(Gs).s1hx = function () {
|
||||
var t = se;
|
||||
return this.q1wh_1.dk(
|
||||
return this.r1wh_1.dk(
|
||||
this,
|
||||
gt(
|
||||
"loaderContainer",
|
||||
@@ -1624,7 +1624,7 @@
|
||||
}),
|
||||
(kt(Gs).u1qx = function () {
|
||||
var t = se;
|
||||
return this.r1wh_1.dk(
|
||||
return this.s1wh_1.dk(
|
||||
this,
|
||||
gt(
|
||||
"circleLoader",
|
||||
@@ -1725,7 +1725,7 @@
|
||||
ps();
|
||||
var t = new Object();
|
||||
((t.dsn = "https://8b56fda09ce04b029e94b7713327120a@sentry.tankionline.com/33"),
|
||||
(t.release = "83fabafa6dc46cc3940ff1fd9aee94f3b8752bb1"),
|
||||
(t.release = "903317d564e517a51ee888cb6bb2a74f3a9b5def"),
|
||||
(t.environment = "china"),
|
||||
(t.debug = !1),
|
||||
wt(t));
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -32,34 +32,34 @@
|
||||
T = r.$_$.l,
|
||||
I = n.$_$.je;
|
||||
function A(t) {
|
||||
var n = t.d1wc_1;
|
||||
var n = t.e1wc_1;
|
||||
if (null != n) return n;
|
||||
s("codec_modelsData");
|
||||
}
|
||||
function R(t) {
|
||||
var n = t.e1wc_1;
|
||||
var n = t.f1wc_1;
|
||||
if (null != n) return n;
|
||||
s("codec_objects");
|
||||
}
|
||||
function P() {}
|
||||
function N(t) {
|
||||
var n = t.j1wc_1;
|
||||
var n = t.k1wc_1;
|
||||
if (null != n) return n;
|
||||
s("codec_resources");
|
||||
}
|
||||
function O() {}
|
||||
function M(t) {
|
||||
var n = t.m1wc_1;
|
||||
var n = t.n1wc_1;
|
||||
if (null != n) return n;
|
||||
s("codec_data");
|
||||
}
|
||||
function D() {}
|
||||
function L() {
|
||||
((this.p1wc_1 = new y(o(m), null)), (this.q1wc_1 = new y(o(k), null)));
|
||||
((this.q1wc_1 = new y(o(m), null)), (this.r1wc_1 = new y(o(k), null)));
|
||||
}
|
||||
function B(t) {
|
||||
var n = b;
|
||||
return t.u1wc_1.e2b(
|
||||
return t.v1wc_1.e2b(
|
||||
t,
|
||||
q(
|
||||
"protocol",
|
||||
@@ -74,19 +74,19 @@
|
||||
}
|
||||
function U() {
|
||||
(x.call(this),
|
||||
(this.u1wc_1 = new y(o(m), null)),
|
||||
(this.v1wc_1 = new y(o(k), null)),
|
||||
(this.x1wc_1 = new $(163351191, 191355032)),
|
||||
(this.y1wc_1 = new $(1488436371, 748816660)),
|
||||
(this.a1wd_1 = new $(1862164506, 1779039460)),
|
||||
(this.c1wd_1 = new $(705359222, 1904359626)),
|
||||
(this.e1wd_1 = new $(54326167, 2104499555)),
|
||||
(this.v1wc_1 = new y(o(m), null)),
|
||||
(this.w1wc_1 = new y(o(k), null)),
|
||||
(this.y1wc_1 = new $(163351191, 191355032)),
|
||||
(this.z1wc_1 = new $(1488436371, 748816660)),
|
||||
(this.b1wd_1 = new $(1862164506, 1779039460)),
|
||||
(this.d1wd_1 = new $(705359222, 1904359626)),
|
||||
(this.f1wd_1 = new $(54326167, 2104499555)),
|
||||
this.taw(),
|
||||
(this.g1wd_1 = this.x1wc_1));
|
||||
(this.h1wd_1 = this.y1wc_1));
|
||||
}
|
||||
function F(t) {
|
||||
var n = b;
|
||||
return t.l1wd_1.e2b(
|
||||
return t.m1wd_1.e2b(
|
||||
t,
|
||||
q(
|
||||
"protocol",
|
||||
@@ -100,7 +100,7 @@
|
||||
);
|
||||
}
|
||||
function G() {
|
||||
((this.l1wd_1 = new y(o(m), null)), (this.n1wd_1 = new $(1791645716, 423004956)));
|
||||
((this.m1wd_1 = new y(o(m), null)), (this.o1wd_1 = new $(1791645716, 423004956)));
|
||||
}
|
||||
function H() {
|
||||
return ((t = E(c(W))), W.call(t), t);
|
||||
@@ -112,14 +112,14 @@
|
||||
var t;
|
||||
}
|
||||
function K() {
|
||||
this.k1wc_1 = 0;
|
||||
this.l1wc_1 = 0;
|
||||
}
|
||||
function Y() {
|
||||
return ((t = E(c(X))), X.call(t), t);
|
||||
var t;
|
||||
}
|
||||
function X() {
|
||||
this.o1wc_1 = new $(0, 0);
|
||||
this.p1wc_1 = new $(0, 0);
|
||||
}
|
||||
(p(P, "", P),
|
||||
p(O, "", O),
|
||||
@@ -131,55 +131,55 @@
|
||||
p(K, "", V),
|
||||
p(X, "", Y),
|
||||
(c(P).q7g = function (t) {
|
||||
((this.d1wc_1 = t.n7f(new a(new _(o(X), !1), !1))),
|
||||
(this.e1wc_1 = t.n7f(new a(new _(o(h), !1), !1))));
|
||||
((this.e1wc_1 = t.n7f(new a(new _(o(X), !1), !1))),
|
||||
(this.f1wc_1 = t.n7f(new a(new _(o(h), !1), !1))));
|
||||
}),
|
||||
(c(P).p7g = function (t) {
|
||||
var n = H(),
|
||||
i = n,
|
||||
r = A(this).p7g(t);
|
||||
i.f1wc_1 = null != r && v(r, f) ? r : l();
|
||||
i.g1wc_1 = null != r && v(r, f) ? r : l();
|
||||
var e = n,
|
||||
u = R(this).p7g(t);
|
||||
return ((e.g1wc_1 = null != u && v(u, f) ? u : l()), n);
|
||||
return ((e.h1wc_1 = null != u && v(u, f) ? u : l()), n);
|
||||
}),
|
||||
(c(P).o7g = function (t, n) {
|
||||
if (null == n) throw w("Object is null. Use @ProtocolOptional annotation.");
|
||||
var i = n instanceof W ? n : l();
|
||||
(A(this).o7g(t, i.h1wc()), R(this).o7g(t, i.i1wc()));
|
||||
(A(this).o7g(t, i.i1wc()), R(this).o7g(t, i.j1wc()));
|
||||
}),
|
||||
(c(O).q7g = function (t) {
|
||||
this.j1wc_1 = t.n7f(new a(new _(o(d), !1), !1));
|
||||
this.k1wc_1 = t.n7f(new a(new _(o(d), !1), !1));
|
||||
}),
|
||||
(c(O).p7g = function (t) {
|
||||
var n = V();
|
||||
n.k1wc_1 = t.a7g_1.p2u();
|
||||
n.l1wc_1 = t.a7g_1.p2u();
|
||||
var i = n,
|
||||
r = N(this).p7g(t);
|
||||
return ((i.l1wc_1 = null != r && v(r, f) ? r : l()), n);
|
||||
return ((i.m1wc_1 = null != r && v(r, f) ? r : l()), n);
|
||||
}),
|
||||
(c(O).o7g = function (t, n) {
|
||||
if (null == n) throw w("Object is null. Use @ProtocolOptional annotation.");
|
||||
var i = n instanceof K ? n : l();
|
||||
(t.a7g_1.k2u(i.k1wc_1), N(this).o7g(t, i.rif()));
|
||||
(t.a7g_1.k2u(i.l1wc_1), N(this).o7g(t, i.rif()));
|
||||
}),
|
||||
(c(D).q7g = function (t) {
|
||||
this.m1wc_1 = t.n7f(new _(g().mb(), !1));
|
||||
this.n1wc_1 = t.n7f(new _(g().mb(), !1));
|
||||
}),
|
||||
(c(D).p7g = function (t) {
|
||||
var n = Y(),
|
||||
i = n,
|
||||
r = M(this).p7g(t);
|
||||
return ((i.n1wc_1 = null != r ? r : l()), (n.o1wc_1 = t.a7g_1.q2u()), n);
|
||||
return ((i.o1wc_1 = null != r ? r : l()), (n.p1wc_1 = t.a7g_1.q2u()), n);
|
||||
}),
|
||||
(c(D).o7g = function (t, n) {
|
||||
if (null == n) throw w("Object is null. Use @ProtocolOptional annotation.");
|
||||
var i = n instanceof X ? n : l();
|
||||
(M(this).o7g(t, i.b85()), t.a7g_1.p1s(i.o1wc_1));
|
||||
(M(this).o7g(t, i.b85()), t.a7g_1.p1s(i.p1wc_1));
|
||||
}),
|
||||
(c(L).s80 = function () {
|
||||
var t = b;
|
||||
return this.p1wc_1.e2b(
|
||||
return this.q1wc_1.e2b(
|
||||
this,
|
||||
q(
|
||||
"protocol",
|
||||
@@ -194,7 +194,7 @@
|
||||
}),
|
||||
(c(L).wav = function () {
|
||||
var t = b;
|
||||
return this.q1wc_1.e2b(
|
||||
return this.r1wc_1.e2b(
|
||||
this,
|
||||
q(
|
||||
"modelService",
|
||||
@@ -224,111 +224,111 @@
|
||||
this.s80().l7f(new _(o(X), !0), j(t)));
|
||||
}),
|
||||
(c(U).uaw = function () {
|
||||
var t = this.w1wc_1;
|
||||
var t = this.x1wc_1;
|
||||
if (null != t) return t;
|
||||
s("server");
|
||||
}),
|
||||
(c(U).taw = function () {
|
||||
var t, n;
|
||||
((this.w1wc_1 =
|
||||
((this.x1wc_1 =
|
||||
((t = this),
|
||||
(n = E(c(G))),
|
||||
G.call(n),
|
||||
(n.p1wd_1 = t),
|
||||
(n.m1wd_1 = C().e7j_1),
|
||||
(n.o1wd_1 = F(n).n7f(new _(g().sb(), !1))),
|
||||
(n.q1wd_1 = t),
|
||||
(n.n1wd_1 = C().e7j_1),
|
||||
(n.p1wd_1 = F(n).n7f(new _(g().sb(), !1))),
|
||||
n)),
|
||||
(this.z1wc_1 = B(this).n7f(new _(o(K), !1))),
|
||||
(this.b1wd_1 = B(this).n7f(new _(o(W), !1))),
|
||||
(this.d1wd_1 = B(this).n7f(new _(g().qb(), !1))),
|
||||
(this.f1wd_1 = B(this).n7f(new a(new _(o(h), !1), !1))));
|
||||
(this.a1wd_1 = B(this).n7f(new _(o(K), !1))),
|
||||
(this.c1wd_1 = B(this).n7f(new _(o(W), !1))),
|
||||
(this.e1wd_1 = B(this).n7f(new _(g().qb(), !1))),
|
||||
(this.g1wd_1 = B(this).n7f(new a(new _(o(h), !1), !1))));
|
||||
}),
|
||||
(c(U).q7i = function (t, n) {
|
||||
if (z(t, this.y1wc_1)) {
|
||||
if (z(t, this.z1wc_1)) {
|
||||
var i = (function (t) {
|
||||
var n = t.z1wc_1;
|
||||
var n = t.a1wd_1;
|
||||
if (null != n) return n;
|
||||
s("_loadDependencies_dependenciesCodec");
|
||||
})(this).p7g(n);
|
||||
this.h1wd(i instanceof K ? i : l());
|
||||
} else if (z(t, this.a1wd_1)) {
|
||||
this.i1wd(i instanceof K ? i : l());
|
||||
} else if (z(t, this.b1wd_1)) {
|
||||
var r = (function (t) {
|
||||
var n = t.b1wd_1;
|
||||
var n = t.c1wd_1;
|
||||
if (null != n) return n;
|
||||
s("_loadObjectsData_objectsDataCodec");
|
||||
})(this).p7g(n);
|
||||
this.i1wd(r instanceof W ? r : l());
|
||||
} else if (z(t, this.c1wd_1)) {
|
||||
this.j1wd(r instanceof W ? r : l());
|
||||
} else if (z(t, this.d1wd_1)) {
|
||||
var e = (function (t) {
|
||||
var n = t.d1wd_1;
|
||||
var n = t.e1wd_1;
|
||||
if (null != n) return n;
|
||||
s("_setModelCommandAlias_aliasCodec");
|
||||
})(this).p7g(n);
|
||||
this.j1wd(null != e && "number" == typeof e ? e : l(), n.a7g_1.q2u(), n.a7g_1.q2u());
|
||||
} else if (z(t, this.e1wd_1)) {
|
||||
this.k1wd(null != e && "number" == typeof e ? e : l(), n.a7g_1.q2u(), n.a7g_1.q2u());
|
||||
} else if (z(t, this.f1wd_1)) {
|
||||
var u = (function (t) {
|
||||
var n = t.f1wd_1;
|
||||
var n = t.g1wd_1;
|
||||
if (null != n) return n;
|
||||
s("_unloadObjects_objectsCodec");
|
||||
})(this).p7g(n);
|
||||
this.k1wd(null != u && v(u, f) ? u : l());
|
||||
this.l1wd(null != u && v(u, f) ? u : l());
|
||||
}
|
||||
}),
|
||||
(c(U).p57 = function () {
|
||||
return this.g1wd_1;
|
||||
return this.h1wd_1;
|
||||
}),
|
||||
(c(G).q1wd = function (t) {
|
||||
this.o1wd_1.o7g(this.m1wd_1, t);
|
||||
var n = new T(C().g7j().p57(), this.n1wd_1, this.m1wd_1),
|
||||
(c(G).r1wd = function (t) {
|
||||
this.p1wd_1.o7g(this.n1wd_1, t);
|
||||
var n = new T(C().g7j().p57(), this.o1wd_1, this.n1wd_1),
|
||||
i = C().g7j().q7o();
|
||||
(this.m1wd_1.z7f(), i.v7o().i7q(n), this.m1wd_1.d3());
|
||||
}),
|
||||
(c(W).h1wc = function () {
|
||||
var t = this.f1wc_1;
|
||||
if (null != t) return t;
|
||||
s("modelsData");
|
||||
(this.n1wd_1.z7f(), i.v7o().i7q(n), this.n1wd_1.d3());
|
||||
}),
|
||||
(c(W).i1wc = function () {
|
||||
var t = this.g1wc_1;
|
||||
if (null != t) return t;
|
||||
s("modelsData");
|
||||
}),
|
||||
(c(W).j1wc = function () {
|
||||
var t = this.h1wc_1;
|
||||
if (null != t) return t;
|
||||
s("objects");
|
||||
}),
|
||||
(c(W).toString = function () {
|
||||
var t = "ObjectsData [";
|
||||
return (
|
||||
(t = (t = t + "modelsData = " + I(this.h1wc()) + " ") + "objects = " + I(this.i1wc()) + " ") + "]"
|
||||
(t = (t = t + "modelsData = " + I(this.i1wc()) + " ") + "objects = " + I(this.j1wc()) + " ") + "]"
|
||||
);
|
||||
}),
|
||||
(c(K).rif = function () {
|
||||
var t = this.l1wc_1;
|
||||
var t = this.m1wc_1;
|
||||
if (null != t) return t;
|
||||
s("resources");
|
||||
}),
|
||||
(c(K).toString = function () {
|
||||
var t = "ObjectsDependencies [";
|
||||
return (
|
||||
(t = (t = t + "callbackId = " + this.k1wc_1 + " ") + "resources = " + I(this.rif()) + " ") + "]"
|
||||
(t = (t = t + "callbackId = " + this.l1wc_1 + " ") + "resources = " + I(this.rif()) + " ") + "]"
|
||||
);
|
||||
}),
|
||||
(c(X).b85 = function () {
|
||||
var t = this.n1wc_1;
|
||||
var t = this.o1wc_1;
|
||||
if (null != t) return t;
|
||||
s("data");
|
||||
}),
|
||||
(c(X).toString = function () {
|
||||
var t = "ModelData [";
|
||||
return (t = (t = t + "data = " + I(this.b85()) + " ") + "id = " + this.o1wc_1.toString() + " ") + "]";
|
||||
return (t = (t = t + "data = " + I(this.b85()) + " ") + "id = " + this.p1wc_1.toString() + " ") + "]";
|
||||
}),
|
||||
(t.$_$ = t.$_$ || {}),
|
||||
(t.$_$.a = H),
|
||||
(t.$_$.b = function (t, n) {
|
||||
return (function (t, n, i) {
|
||||
return (K.call(i), (i.k1wc_1 = t), (i.l1wc_1 = n), i);
|
||||
return (K.call(i), (i.l1wc_1 = t), (i.m1wc_1 = n), i);
|
||||
})(t, n, E(c(K)));
|
||||
}),
|
||||
(t.$_$.c = function (t, n) {
|
||||
return (function (t, n, i) {
|
||||
return (X.call(i), (i.n1wc_1 = t), (i.o1wc_1 = n), i);
|
||||
return (X.call(i), (i.o1wc_1 = t), (i.p1wc_1 = n), i);
|
||||
})(t, n, E(c(X)));
|
||||
}),
|
||||
(t.$_$.d = L),
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -33,6 +33,18 @@
|
||||
void 0 === t.prototype.fill &&
|
||||
Object.defineProperty(t.prototype, "fill", { value: Array.prototype.fill });
|
||||
}),
|
||||
void 0 === Math.hypot &&
|
||||
(Math.hypot = function () {
|
||||
for (var t = 0, n = arguments.length, i = 0; i < n; i++) {
|
||||
if (arguments[i] === 1 / 0 || arguments[i] === -1 / 0) return 1 / 0;
|
||||
t += arguments[i] * arguments[i];
|
||||
}
|
||||
return Math.sqrt(t);
|
||||
}),
|
||||
void 0 === Math.log2 &&
|
||||
(Math.log2 = function (t) {
|
||||
return Math.log(t) * Math.LOG2E;
|
||||
}),
|
||||
void 0 === Math.tanh)
|
||||
) {
|
||||
var n = Math.sqrt(2220446049250313e-31),
|
||||
@@ -60,18 +72,6 @@
|
||||
(Math.sign = function (t) {
|
||||
return 0 === (t = +t) || isNaN(t) ? Number(t) : t > 0 ? 1 : -1;
|
||||
}),
|
||||
void 0 === Math.log2 &&
|
||||
(Math.log2 = function (t) {
|
||||
return Math.log(t) * Math.LOG2E;
|
||||
}),
|
||||
void 0 === Math.hypot &&
|
||||
(Math.hypot = function () {
|
||||
for (var t = 0, n = arguments.length, i = 0; i < n; i++) {
|
||||
if (arguments[i] === 1 / 0 || arguments[i] === -1 / 0) return 1 / 0;
|
||||
t += arguments[i] * arguments[i];
|
||||
}
|
||||
return Math.sqrt(t);
|
||||
}),
|
||||
void 0 === String.prototype.startsWith &&
|
||||
Object.defineProperty(String.prototype, "startsWith", {
|
||||
value: function (t, n) {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
rt = n.$_$.ad;
|
||||
function et(t) {
|
||||
var n = h;
|
||||
return t.h1we_1.e2b(
|
||||
return t.i1we_1.e2b(
|
||||
t,
|
||||
c(
|
||||
"modelRegister",
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
function ut(t) {
|
||||
var n = h;
|
||||
return t.i1we_1.e2b(
|
||||
return t.j1we_1.e2b(
|
||||
t,
|
||||
c(
|
||||
"resourceLoaderService",
|
||||
@@ -92,16 +92,16 @@
|
||||
return f;
|
||||
}
|
||||
function _t() {
|
||||
(b.call(this), (this.h1we_1 = new $(m(q), null)), (this.i1we_1 = new $(m(j), null)));
|
||||
(b.call(this), (this.i1we_1 = new $(m(q), null)), (this.j1we_1 = new $(m(j), null)));
|
||||
}
|
||||
function at() {
|
||||
((o = this), (this.j1we_1 = new $(m(q), null)));
|
||||
((o = this), (this.k1we_1 = new $(m(q), null)));
|
||||
}
|
||||
function ht() {
|
||||
return (null == o && new at(), o);
|
||||
}
|
||||
function ct(t) {
|
||||
var n = t.l1we_1;
|
||||
var n = t.m1we_1;
|
||||
if (null != n) return n;
|
||||
C("idCodec");
|
||||
}
|
||||
@@ -113,23 +113,23 @@
|
||||
r = n.a7g_1.q2u(),
|
||||
e = wt().h7l().a7n();
|
||||
d(e.w7o().p57(), i) && e.z7o(i);
|
||||
var u = wt().o1we().f7n(r);
|
||||
var u = wt().p1we().f7n(r);
|
||||
if (null == u) throw A("Class not found exception class=" + r.toString() + ", object=" + i.toString());
|
||||
var s = u;
|
||||
return e.y7o(i, s, "");
|
||||
}
|
||||
function vt() {
|
||||
((_ = this), (this.m1we_1 = new $(m(P), null)), (this.n1we_1 = new $(m(N), null)));
|
||||
((_ = this), (this.n1we_1 = new $(m(P), null)), (this.o1we_1 = new $(m(N), null)));
|
||||
}
|
||||
function wt() {
|
||||
return (null == _ && new vt(), _);
|
||||
}
|
||||
function pt() {
|
||||
(wt(), (this.p1we_1 = new lt()));
|
||||
(wt(), (this.q1we_1 = new lt()));
|
||||
}
|
||||
function dt(t) {
|
||||
var n = h;
|
||||
return t.q1we_1.e2b(
|
||||
return t.r1we_1.e2b(
|
||||
t,
|
||||
c(
|
||||
"gameTypeRegistry",
|
||||
@@ -144,7 +144,7 @@
|
||||
}
|
||||
function gt(t) {
|
||||
var n = h;
|
||||
return t.r1we_1.e2b(
|
||||
return t.s1we_1.e2b(
|
||||
t,
|
||||
c(
|
||||
"resourceRegistry",
|
||||
@@ -159,7 +159,7 @@
|
||||
}
|
||||
function mt(t) {
|
||||
var n = h;
|
||||
return t.s1we_1.e2b(
|
||||
return t.t1we_1.e2b(
|
||||
t,
|
||||
c(
|
||||
"modelRegistry",
|
||||
@@ -174,7 +174,7 @@
|
||||
}
|
||||
function yt(t) {
|
||||
var n = h;
|
||||
return t.t1we_1.e2b(
|
||||
return t.u1we_1.e2b(
|
||||
t,
|
||||
c(
|
||||
"spaceRegistry",
|
||||
@@ -217,19 +217,19 @@
|
||||
u = n.a7g_1.o2u(),
|
||||
s = n.a7g_1.q2u(),
|
||||
o = (function (t) {
|
||||
var n = t.u1we_1;
|
||||
var n = t.v1we_1;
|
||||
if (null != n) return n;
|
||||
C("booleanCodec");
|
||||
})(t).p7g(n);
|
||||
return (
|
||||
(i = !!(null != o && "boolean" == typeof o ? o : w()) || xt().v1we_1.h1(r)),
|
||||
(i = !!(null != o && "boolean" == typeof o ? o : w()) || xt().w1we_1.h1(r)),
|
||||
new L(e, u, r, s, i)
|
||||
);
|
||||
}
|
||||
function jt() {
|
||||
((a = this),
|
||||
(this.v1we_1 = B()),
|
||||
this.v1we_1.f1(
|
||||
(this.w1we_1 = B()),
|
||||
this.w1we_1.f1(
|
||||
F([
|
||||
U(0, 500360050),
|
||||
U(0, 500381261),
|
||||
@@ -270,7 +270,7 @@
|
||||
U(356, -1308055559),
|
||||
]),
|
||||
),
|
||||
this.v1we_1.f1(
|
||||
this.w1we_1.f1(
|
||||
F([
|
||||
U(0, 500025807),
|
||||
U(0, 500378100),
|
||||
@@ -326,10 +326,10 @@
|
||||
}
|
||||
function zt() {
|
||||
(xt(),
|
||||
(this.q1we_1 = new $(m(P), null)),
|
||||
(this.r1we_1 = new $(m(G), null)),
|
||||
(this.s1we_1 = new $(m(q), null)),
|
||||
(this.t1we_1 = new $(m(N), null)));
|
||||
(this.r1we_1 = new $(m(P), null)),
|
||||
(this.s1we_1 = new $(m(G), null)),
|
||||
(this.t1we_1 = new $(m(q), null)),
|
||||
(this.u1we_1 = new $(m(N), null)));
|
||||
}
|
||||
function ModelNotFoundError(t, n, i, r) {
|
||||
(Y(
|
||||
@@ -359,8 +359,8 @@
|
||||
S(jt),
|
||||
z(zt, "", zt),
|
||||
z(ModelNotFoundError, "", J, K),
|
||||
(x(_t).h1wd = function (t) {
|
||||
if (t.rif().r()) t.k1wc_1 > 0 && this.uaw().q1wd(t.k1wc_1);
|
||||
(x(_t).i1wd = function (t) {
|
||||
if (t.rif().r()) t.l1wc_1 > 0 && this.uaw().r1wd(t.l1wc_1);
|
||||
else {
|
||||
var n = v().g7j().q7o();
|
||||
n.b7p(t.rif());
|
||||
@@ -371,7 +371,7 @@
|
||||
(p = n),
|
||||
function () {
|
||||
return (
|
||||
c.uaw().q1wd(w.k1wc_1),
|
||||
c.uaw().r1wd(w.l1wc_1),
|
||||
(function (t, n, i) {
|
||||
for (var r = ut(t), e = n.rif(), u = l(), s = e.t(); s.u();) {
|
||||
var o = s.v();
|
||||
@@ -417,18 +417,18 @@
|
||||
}
|
||||
var a, h, c, w, p;
|
||||
}),
|
||||
(x(_t).i1wd = function (t) {
|
||||
(x(_t).j1wd = function (t) {
|
||||
(!(function (t, n) {
|
||||
for (var i = n.h1wc(), r = v().g7j().q7o(), e = 0; e < i.e1();) {
|
||||
for (var i = n.i1wc(), r = v().g7j().q7o(), e = 0; e < i.e1();) {
|
||||
for (
|
||||
var u = i.g1(e).b85(), s = u instanceof p ? u : w(), o = r.x7o(s), _ = (e = (e + 1) | 0);
|
||||
_ < i.e1() && !d(i.g1(_).o1wc_1, new p(0, 0));
|
||||
_ < i.e1() && !d(i.g1(_).p1wc_1, new p(0, 0));
|
||||
)
|
||||
_ = (_ + 1) | 0;
|
||||
for (; e < _;) {
|
||||
var a = i.g1(e),
|
||||
h = et(t).m7n(a.o1wc_1);
|
||||
if (null == h) throw new ModelNotFoundError(r.p57(), s, a.o1wc_1, et(t).g7n().e1());
|
||||
h = et(t).m7n(a.p1wc_1);
|
||||
if (null == h) throw new ModelNotFoundError(r.p57(), s, a.p1wc_1, et(t).g7n().e1());
|
||||
(h.r7i(o, a.b85()), (e = (e + 1) | 0));
|
||||
}
|
||||
}
|
||||
@@ -448,12 +448,12 @@
|
||||
var o = u;
|
||||
((u = (u + 1) | 0), n.g1(o).t7o(m(g)).b7j());
|
||||
} while (u < s);
|
||||
})(0, t.i1wc()));
|
||||
})(0, t.j1wc()));
|
||||
}),
|
||||
(x(_t).j1wd = function (t, n, i) {
|
||||
(x(_t).k1wd = function (t, n, i) {
|
||||
v().g7j().q7o().e7p(t, n, i);
|
||||
}),
|
||||
(x(_t).k1wd = function (t) {
|
||||
(x(_t).l1wd = function (t) {
|
||||
var n = v().g7j().q7o(),
|
||||
i = 0,
|
||||
r = t.e1();
|
||||
@@ -465,43 +465,43 @@
|
||||
n.z7o(u.p57());
|
||||
} while (i < r);
|
||||
}),
|
||||
(x(at).k1we = function () {
|
||||
(x(at).l1we = function () {
|
||||
var t = h;
|
||||
return this.j1we_1.e2b(
|
||||
return this.k1we_1.e2b(
|
||||
this,
|
||||
c(
|
||||
"modelRegister",
|
||||
1,
|
||||
t,
|
||||
function (t) {
|
||||
return t.k1we();
|
||||
return t.l1we();
|
||||
},
|
||||
null,
|
||||
),
|
||||
);
|
||||
}),
|
||||
(x(lt).q7g = function (t) {
|
||||
this.l1we_1 = t.n7f(new E(m(p), !1));
|
||||
this.m1we_1 = t.n7f(new E(m(p), !1));
|
||||
}),
|
||||
(x(lt).o7g = function (t, n) {}),
|
||||
(x(lt).p7g = function (t) {
|
||||
var n = ct(this).p7g(t),
|
||||
i = n instanceof p ? n : w();
|
||||
if (d(i, new p(0, 0))) return I(T(ct(this).p7g(t)), i);
|
||||
var r = ht().k1we().k7n(i),
|
||||
var r = ht().l1we().k7n(i),
|
||||
e = T(r.p7g(t));
|
||||
return I(e, i);
|
||||
}),
|
||||
(x(vt).o1we = function () {
|
||||
(x(vt).p1we = function () {
|
||||
var t = h;
|
||||
return this.m1we_1.e2b(
|
||||
return this.n1we_1.e2b(
|
||||
this,
|
||||
c(
|
||||
"gameTypeRegistry",
|
||||
1,
|
||||
t,
|
||||
function (t) {
|
||||
return t.o1we();
|
||||
return t.p1we();
|
||||
},
|
||||
null,
|
||||
),
|
||||
@@ -509,7 +509,7 @@
|
||||
}),
|
||||
(x(vt).h7l = function () {
|
||||
var t = h;
|
||||
return this.n1we_1.e2b(
|
||||
return this.o1we_1.e2b(
|
||||
this,
|
||||
c(
|
||||
"spaceRegistry",
|
||||
@@ -523,7 +523,7 @@
|
||||
);
|
||||
}),
|
||||
(x(pt).q7g = function (t) {
|
||||
this.p1we_1.q7g(t);
|
||||
this.q1we_1.q7g(t);
|
||||
}),
|
||||
(x(pt).o7g = function (t, n) {
|
||||
throw A("unsupported");
|
||||
@@ -531,7 +531,7 @@
|
||||
(x(pt).p7g = function (t) {
|
||||
var n = O();
|
||||
return (
|
||||
(n.g1wc_1 = (function (t, n) {
|
||||
(n.h1wc_1 = (function (t, n) {
|
||||
var i = n.c7g_1.p2u(),
|
||||
r = l(),
|
||||
e = 0;
|
||||
@@ -541,13 +541,13 @@
|
||||
} while (e < i);
|
||||
return r;
|
||||
})(0, t)),
|
||||
(n.f1wc_1 = (function (t, n) {
|
||||
(n.g1wc_1 = (function (t, n) {
|
||||
var i = n.c7g_1.p2u(),
|
||||
r = R(i),
|
||||
e = 0;
|
||||
if (e < i)
|
||||
do {
|
||||
((e = (e + 1) | 0), r.y(t.p1we_1.p7g(n)));
|
||||
((e = (e + 1) | 0), r.y(t.q1we_1.p7g(n)));
|
||||
} while (e < i);
|
||||
return r;
|
||||
})(this, t)),
|
||||
@@ -555,7 +555,7 @@
|
||||
);
|
||||
}),
|
||||
(x(zt).q7g = function (t) {
|
||||
this.u1we_1 = t.o7f(H().pb(), !1);
|
||||
this.v1we_1 = t.o7f(H().pb(), !1);
|
||||
}),
|
||||
(x(zt).o7g = function (t, n) {
|
||||
throw W();
|
||||
|
||||
@@ -647,17 +647,17 @@
|
||||
if ($t) return mr;
|
||||
(($t = !0),
|
||||
(lt = new fo("EN", 0, "English", "en")),
|
||||
(ft = new fo("RU", 1, "РуÑÑкий", "ru")),
|
||||
(ft = new fo("RU", 1, "Русский", "ru")),
|
||||
(vt = new fo("DE", 2, "Deutsch", "de")),
|
||||
(wt = new fo("ES", 3, "Español", "es")),
|
||||
(wt = new fo("ES", 3, "Español", "es")),
|
||||
(pt = new fo("PL", 4, "Polski", "pl")),
|
||||
(dt = new fo("PT", 5, "Português", "pt_br", "pt-BR")),
|
||||
(gt = new fo("ZH", 6, "䏿–‡", "cn", "zh-CN")),
|
||||
(mt = new fo("FR", 7, "Français", "fr")),
|
||||
(dt = new fo("PT", 5, "Português", "pt_br", "pt-BR")),
|
||||
(gt = new fo("ZH", 6, "中文", "cn", "zh-CN")),
|
||||
(mt = new fo("FR", 7, "Français", "fr")),
|
||||
(yt = new fo("JA", 8, "Japanese", "ja")),
|
||||
(kt = new fo("TR", 9, "Türkçe", "tr")),
|
||||
(bt = new fo("CS", 10, "Český", "cs")),
|
||||
(qt = new fo("HI", 11, "हिनà¥à¤¦à¥€", "hi")));
|
||||
(kt = new fo("TR", 9, "Türkçe", "tr")),
|
||||
(bt = new fo("CS", 10, "Český", "cs")),
|
||||
(qt = new fo("HI", 11, "हिन्दी", "hi")));
|
||||
}
|
||||
function fo(t, n, i, r, e) {
|
||||
((e = e === kr ? r : e), Or.call(this, t, n), (this.p2e_1 = i), (this.q2e_1 = r), (this.r2e_1 = e));
|
||||
@@ -2787,33 +2787,33 @@
|
||||
return (
|
||||
(r =
|
||||
11 <= u && u <= 19
|
||||
? "дней"
|
||||
? "дней"
|
||||
: 1 === (u = (u % 10) | 0)
|
||||
? "день"
|
||||
? "день"
|
||||
: 2 <= u && u <= 4
|
||||
? "днÑ"
|
||||
: "дней"),
|
||||
? "дня"
|
||||
: "дней"),
|
||||
(e.j2c_1 = r),
|
||||
1 === n || 21 === n
|
||||
? (e.k2c_1 = "чаÑ")
|
||||
? (e.k2c_1 = "час")
|
||||
: (2 <= n && n <= 4) || (22 <= n && n <= 24)
|
||||
? (e.k2c_1 = "чаÑа")
|
||||
: 5 <= n && n <= 20 && (e.k2c_1 = "чаÑов"),
|
||||
? (e.k2c_1 = "часа")
|
||||
: 5 <= n && n <= 20 && (e.k2c_1 = "часов"),
|
||||
1 === t || 21 === t || 31 === t || 41 === t || 51 === t
|
||||
? (e.l2c_1 = "минуту")
|
||||
? (e.l2c_1 = "минуту")
|
||||
: (2 <= t && t <= 4) ||
|
||||
(22 <= t && t <= 24) ||
|
||||
(32 <= t && t <= 34) ||
|
||||
(42 <= t && t <= 44) ||
|
||||
(52 <= t && t <= 54)
|
||||
? (e.l2c_1 = "минуты")
|
||||
? (e.l2c_1 = "минуты")
|
||||
: (0 === t ||
|
||||
(5 <= t && t <= 20) ||
|
||||
(25 <= t && t <= 30) ||
|
||||
(35 <= t && t <= 40) ||
|
||||
(45 <= t && t <= 50) ||
|
||||
(55 <= t && t <= 60)) &&
|
||||
(e.l2c_1 = "минут"),
|
||||
(e.l2c_1 = "минут"),
|
||||
e
|
||||
);
|
||||
}),
|
||||
@@ -2831,7 +2831,7 @@
|
||||
}),
|
||||
(Cr(Os).z2c = function () {
|
||||
var t = new Ps();
|
||||
return ((t.j2c_1 = "天"), (t.k2c_1 = "å°æ—¶"), (t.l2c_1 = "分钟"), t);
|
||||
return ((t.j2c_1 = "天"), (t.k2c_1 = "小时"), (t.l2c_1 = "分钟"), t);
|
||||
}),
|
||||
(Cr(Os).v2c = function (t, n, i) {
|
||||
var r = new Ps();
|
||||
@@ -2859,7 +2859,7 @@
|
||||
}),
|
||||
(Cr(Os).y2c = function (t, n, i) {
|
||||
var r = new Ps();
|
||||
switch (((r.j2c_1 = 1 === i ? "dÃa" : "dÃas"), (r.k2c_1 = 1 === n ? "hora" : "horas"), t)) {
|
||||
switch (((r.j2c_1 = 1 === i ? "día" : "días"), (r.k2c_1 = 1 === n ? "hora" : "horas"), t)) {
|
||||
case 1:
|
||||
case 0:
|
||||
r.l2c_1 = "minuto";
|
||||
@@ -2872,7 +2872,7 @@
|
||||
(Cr(Os).x2c = function (t, n, i) {
|
||||
var r = new Ps();
|
||||
return (
|
||||
(r.j2c_1 = 1 === i ? "dzień" : "dni"),
|
||||
(r.j2c_1 = 1 === i ? "dzień" : "dni"),
|
||||
(r.k2c_1 = 1 === n ? "godzina" : "godzin"),
|
||||
(r.l2c_1 =
|
||||
0 === t
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
this.vui_1 = $t("#battle\\|([0-9a-f]{16})", t);
|
||||
var n = qt();
|
||||
this.wui_1 = $t(
|
||||
"(https?:\\/\\/|www\\.)((([\\w\\-\\.]+)\\.([a-z]{2,6}\\.?))|(([а-Ñ\\-\\.]+)\\.(рф\\.?)))(\\/[\\w\\.]*)*\\/?([^\\s`!\\(\\)\\[\\]\\{\\};:'\",<>«»“â€â€˜â€™]+)?",
|
||||
"(https?:\\/\\/|www\\.)((([\\w\\-\\.]+)\\.([a-z]{2,6}\\.?))|(([а-я\\-\\.]+)\\.(рф\\.?)))(\\/[\\w\\.]*)*\\/?([^\\s`!\\(\\)\\[\\]\\{\\};:'\",<>«»“”‘’]+)?",
|
||||
n,
|
||||
);
|
||||
var i = qt();
|
||||
|
||||
@@ -343,8 +343,6 @@
|
||||
);
|
||||
}
|
||||
function ur(t, n) {
|
||||
// [Hornet 调试] 暴露连接实例(o7m_1 里缓存 "spaceRegistry",p7m_1 是分发器),不影响逻辑
|
||||
window.__HornetConn__ = this;
|
||||
((this.l7m_1 = t),
|
||||
(this.m7m_1 = n),
|
||||
(this.n7m_1 = new H(G(F), null)),
|
||||
@@ -842,7 +840,7 @@
|
||||
i.g3("mobile_device", l);
|
||||
var f = ue(t).c2e().j2k().toString();
|
||||
i.g3("touchscreen_support", f);
|
||||
i.g3("client_version", "83fabafa6dc46cc3940ff1fd9aee94f3b8752bb1");
|
||||
i.g3("client_version", "903317d564e517a51ee888cb6bb2a74f3a9b5def");
|
||||
var v = ue(t).i2e();
|
||||
if (null == v);
|
||||
else {
|
||||
@@ -1567,8 +1565,6 @@
|
||||
this.q7m_1 = t;
|
||||
}),
|
||||
(J(or).q7g = function (t) {
|
||||
// [Hornet 调试] 暴露空间命令注册表(x7m_1 / y7m_1 = id→codec),不影响逻辑
|
||||
window.__HornetSpaceReg__ = this;
|
||||
((this.w7m_1 = t.p7f(bt().qb())), t.l7f(new qt(G(Oi), !1), new lr()));
|
||||
var n = new Vi();
|
||||
n.q7g(t);
|
||||
@@ -2612,28 +2608,6 @@
|
||||
n.z2u());
|
||||
var i = n.l2t(),
|
||||
r = new DataView(i.buffer, n.n2t(), n.u2u());
|
||||
// [Hornet 调试] 记录上行命令对象 + 实际发送字节(反查"上行方法号 → 命令类")
|
||||
try {
|
||||
var __log__ = window.__HornetSendLog__ || (window.__HornetSendLog__ = []);
|
||||
var __hex__ = '';
|
||||
for (var __k__ = 0; __k__ < r.byteLength && __k__ < 4096; __k__++) {
|
||||
__hex__ += ('0' + r.getUint8(__k__).toString(16)).slice(-2);
|
||||
}
|
||||
__log__.push({
|
||||
t: Date.now(),
|
||||
cls: t && t.constructor ? t.constructor.name : '?',
|
||||
text: (function () {
|
||||
try {
|
||||
return String(t);
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
})(),
|
||||
len: r.byteLength,
|
||||
hex: __hex__,
|
||||
});
|
||||
if (__log__.length > 4000) __log__.splice(0, __log__.length - 4000);
|
||||
} catch (__e__) {}
|
||||
(this.q7t_1.send(r), ni().k7f(n));
|
||||
}
|
||||
}),
|
||||
@@ -2751,9 +2725,6 @@
|
||||
var i = new kr();
|
||||
Y(G(pr), i, null);
|
||||
var r = new mr();
|
||||
// [Hornet 调试] 把 RPC 模型注册表暴露到 window:
|
||||
// v7n_1 = methodId→modelId,u7n_1 = modelId→模型,w7n_1 = modelId→codec(不影响逻辑)
|
||||
window.__HornetModelReg__ = r;
|
||||
Y(G(wr), r, null);
|
||||
}),
|
||||
(t.$_$.b1 = function () {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+46554
-46508
File diff suppressed because it is too large.
Load diff
@@ -29,7 +29,7 @@
|
||||
function x() {}
|
||||
function z() {}
|
||||
function S() {
|
||||
this.c1wf_1 = new d(p(w), null);
|
||||
this.d1wf_1 = new d(p(w), null);
|
||||
}
|
||||
function C() {
|
||||
if (a) return l;
|
||||
@@ -48,12 +48,12 @@
|
||||
var t;
|
||||
}
|
||||
function I() {
|
||||
((this.w1we_1 = 0),
|
||||
(this.x1we_1 = 0),
|
||||
((this.x1we_1 = 0),
|
||||
(this.y1we_1 = 0),
|
||||
(this.z1we_1 = 0),
|
||||
(this.a1wf_1 = 0),
|
||||
(this.b1wf_1 = 0));
|
||||
(this.b1wf_1 = 0),
|
||||
(this.c1wf_1 = 0));
|
||||
}
|
||||
(v(x, "", x),
|
||||
v(z, "", z),
|
||||
@@ -87,28 +87,28 @@
|
||||
(h(z).p7g = function (t) {
|
||||
var n = T();
|
||||
return (
|
||||
(n.w1we_1 = t.a7g_1.r2u()),
|
||||
(n.x1we_1 = t.a7g_1.p2u()),
|
||||
(n.x1we_1 = t.a7g_1.r2u()),
|
||||
(n.y1we_1 = t.a7g_1.p2u()),
|
||||
(n.z1we_1 = t.a7g_1.p2u()),
|
||||
(n.a1wf_1 = t.a7g_1.p2u()),
|
||||
(n.b1wf_1 = t.a7g_1.o2u()),
|
||||
(n.b1wf_1 = t.a7g_1.p2u()),
|
||||
(n.c1wf_1 = t.a7g_1.o2u()),
|
||||
n
|
||||
);
|
||||
}),
|
||||
(h(z).o7g = function (t, n) {
|
||||
if (null == n) throw c("Object is null. Use @ProtocolOptional annotation.");
|
||||
var i = n instanceof I ? n : f();
|
||||
(t.a7g_1.l2u(i.w1we_1),
|
||||
t.a7g_1.k2u(i.x1we_1),
|
||||
(t.a7g_1.l2u(i.x1we_1),
|
||||
t.a7g_1.k2u(i.y1we_1),
|
||||
t.a7g_1.k2u(i.z1we_1),
|
||||
t.a7g_1.k2u(i.a1wf_1),
|
||||
t.a7g_1.j2u(i.b1wf_1));
|
||||
t.a7g_1.k2u(i.b1wf_1),
|
||||
t.a7g_1.j2u(i.c1wf_1));
|
||||
}),
|
||||
(h(S).s80 = function () {
|
||||
var t = g;
|
||||
return this.c1wf_1.e2b(
|
||||
return this.d1wf_1.e2b(
|
||||
this,
|
||||
m(
|
||||
"protocol",
|
||||
@@ -137,18 +137,18 @@
|
||||
(t =
|
||||
(t =
|
||||
(t =
|
||||
(t = (t = t + "fps = " + this.w1we_1 + " ") + "frameHeight = " + this.x1we_1 + " ") +
|
||||
(t = (t = t + "fps = " + this.x1we_1 + " ") + "frameHeight = " + this.y1we_1 + " ") +
|
||||
"frameWidth = " +
|
||||
this.y1we_1 +
|
||||
this.z1we_1 +
|
||||
" ") +
|
||||
"imageHeight = " +
|
||||
this.z1we_1 +
|
||||
this.a1wf_1 +
|
||||
" ") +
|
||||
"imageWidth = " +
|
||||
this.a1wf_1 +
|
||||
this.b1wf_1 +
|
||||
" ") +
|
||||
"numFrames = " +
|
||||
this.b1wf_1 +
|
||||
this.c1wf_1 +
|
||||
" ") + "]"
|
||||
);
|
||||
}),
|
||||
|
||||
+34508
-34507
File diff suppressed because it is too large.
Load diff
@@ -11,7 +11,7 @@
|
||||
f = r.$_$.mf,
|
||||
v = e.$_$.y1,
|
||||
w = r.$_$.h5,
|
||||
p = i.$_$.h1g,
|
||||
p = i.$_$.j1g,
|
||||
d = r.$_$.uj,
|
||||
g = r.$_$.h2,
|
||||
m = r.$_$.nc,
|
||||
@@ -25,36 +25,36 @@
|
||||
z = r.$_$.k5,
|
||||
S = r.$_$.td,
|
||||
C = e.$_$.t,
|
||||
E = i.$_$.s1o,
|
||||
T = i.$_$.k1l,
|
||||
I = i.$_$.xm,
|
||||
A = i.$_$.f1l,
|
||||
R = i.$_$.r1o,
|
||||
P = i.$_$.l1m,
|
||||
E = i.$_$.u1o,
|
||||
T = i.$_$.m1l,
|
||||
I = i.$_$.ym,
|
||||
A = i.$_$.h1l,
|
||||
R = i.$_$.t1o,
|
||||
P = i.$_$.n1m,
|
||||
N = r.$_$.jb,
|
||||
O = r.$_$.vj,
|
||||
M = u.$_$.h,
|
||||
D = r.$_$.l6,
|
||||
L = r.$_$.k,
|
||||
B = r.$_$.jd,
|
||||
U = i.$_$.pm,
|
||||
F = i.$_$.nm,
|
||||
U = i.$_$.qm,
|
||||
F = i.$_$.om,
|
||||
G = s.$_$.f,
|
||||
H = e.$_$.s1,
|
||||
W = r.$_$.qj,
|
||||
V = r.$_$.m,
|
||||
K = r.$_$.x1,
|
||||
Y = r.$_$.xb,
|
||||
X = i.$_$.jm,
|
||||
X = i.$_$.km,
|
||||
J = i.$_$.oa,
|
||||
Z = i.$_$.ra,
|
||||
Q = i.$_$.ua,
|
||||
tt = r.$_$.je,
|
||||
nt = r.$_$.tk,
|
||||
it = i.$_$.k1m,
|
||||
it = i.$_$.m1m,
|
||||
rt = r.$_$.ga,
|
||||
et = i.$_$.sa,
|
||||
ut = i.$_$.r1l,
|
||||
ut = i.$_$.t1l,
|
||||
st = r.$_$.mk,
|
||||
ot = r.$_$.c5,
|
||||
_t = n.$_$.d,
|
||||
@@ -67,8 +67,8 @@
|
||||
wt = r.$_$.kg,
|
||||
pt = r.$_$.hd,
|
||||
dt = r.$_$.gi,
|
||||
gt = i.$_$.h1n,
|
||||
mt = i.$_$.km,
|
||||
gt = i.$_$.j1n,
|
||||
mt = i.$_$.lm,
|
||||
yt = e.$_$.y9,
|
||||
kt = r.$_$.z1,
|
||||
bt = r.$_$.yg,
|
||||
@@ -88,19 +88,19 @@
|
||||
Nt = r.$_$.sc,
|
||||
Ot = r.$_$.ai,
|
||||
Mt = r.$_$.a7,
|
||||
Dt = i.$_$.j1m,
|
||||
Dt = i.$_$.l1m,
|
||||
Lt = r.$_$.z2,
|
||||
Bt = r.$_$.vg,
|
||||
Ut = _.$_$.o,
|
||||
Ft = i.$_$.q1l,
|
||||
Ft = i.$_$.s1l,
|
||||
Gt = n.$_$.r,
|
||||
Ht = r.$_$.m7,
|
||||
Wt = n.$_$.h,
|
||||
Vt = i.$_$.a5,
|
||||
Kt = i.$_$.zk,
|
||||
Kt = i.$_$.al,
|
||||
Yt = r.$_$.n6,
|
||||
Xt = i.$_$.g1n,
|
||||
Jt = i.$_$.p1l;
|
||||
Xt = i.$_$.i1n,
|
||||
Jt = i.$_$.r1l;
|
||||
function Zt(t, n) {
|
||||
return t.getDigitalGoodsService(n);
|
||||
}
|
||||
|
||||
@@ -5146,9 +5146,9 @@
|
||||
function Sb() {
|
||||
(xb.call(this),
|
||||
(this.u5p_1 =
|
||||
"\n\t\t\t\n\t\t#define HALF_QUAD_SIZE 50.0 // размер единичного квада в нашем движке \n\t\t\n\t\tuniform vec3 cameraPosition;\n\t\tuniform float lengthScale;\n\t\n\t\t\t\t\n\t\tvec4 renderBillboard(vec3 vertexPos, vec3 centerPos, vec3 up, vec3 right) {\t\t\t\n\t\t\tvec3 forward = cross(right, up);\n\t\t\t\t\t\n\t\t\tmat3 billboardMatrix = mat3(right, forward, up);\n\t\t\tvec4 result = vec4(billboardMatrix * vertexPos + centerPos, 1.0);\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t\n\t\t"),
|
||||
"\n\t\t\t\n\t\t#define HALF_QUAD_SIZE 50.0 // размер единичного квада в нашем движке \n\t\t\n\t\tuniform vec3 cameraPosition;\n\t\tuniform float lengthScale;\n\t\n\t\t\t\t\n\t\tvec4 renderBillboard(vec3 vertexPos, vec3 centerPos, vec3 up, vec3 right) {\t\t\t\n\t\t\tvec3 forward = cross(right, up);\n\t\t\t\t\t\n\t\t\tmat3 billboardMatrix = mat3(right, forward, up);\n\t\t\tvec4 result = vec4(billboardMatrix * vertexPos + centerPos, 1.0);\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t\n\t\t"),
|
||||
(this.v5p_1 =
|
||||
"\n\t\t\tvec3 dirToCam = normalize(inputCenter - cameraPosition);\n\n\t\t\t// scale vertex position\n\t\t\tvec3 vertexPos;\n\t\t\tvertexPos.x = (inputPosition.x + sign(lengthScale) * HALF_QUAD_SIZE) * lengthScale * inputScale.z; // unity transfers pivot to the side of the quad in stretched billboard mode, so do we\n\t\t\tvertexPos.y = 0.0; // stretched Billboard in Unity ignores forward-axis pivot\n\t\t\tvertexPos.z = inputPosition.z * inputScale.x;\n\n\t\t\tvec3 right = normalize(-inputVelocity);//раÑÑ‚Ñгиваем партикл против Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑкороÑти \n\n\t\t\t// calculate orthogonal vector to velocity-camera direction plane;\n\t\t\t// it is not unit because velocity and camera direction are not orthogonal in most cases\n\t\t\tvec3 up = normalize(cross(dirToCam, right));\n\n\t\t\tvec4 localVertexPosition = renderBillboard(vertexPos, inputCenter, up, right);\n\t\t\tgl_Position = mvp * localVertexPosition;\n\t\t"),
|
||||
"\n\t\t\tvec3 dirToCam = normalize(inputCenter - cameraPosition);\n\n\t\t\t// scale vertex position\n\t\t\tvec3 vertexPos;\n\t\t\tvertexPos.x = (inputPosition.x + sign(lengthScale) * HALF_QUAD_SIZE) * lengthScale * inputScale.z; // unity transfers pivot to the side of the quad in stretched billboard mode, so do we\n\t\t\tvertexPos.y = 0.0; // stretched Billboard in Unity ignores forward-axis pivot\n\t\t\tvertexPos.z = inputPosition.z * inputScale.x;\n\n\t\t\tvec3 right = normalize(-inputVelocity);//растягиваем партикл против направления скорости \n\n\t\t\t// calculate orthogonal vector to velocity-camera direction plane;\n\t\t\t// it is not unit because velocity and camera direction are not orthogonal in most cases\n\t\t\tvec3 up = normalize(cross(dirToCam, right));\n\n\t\t\tvec4 localVertexPosition = renderBillboard(vertexPos, inputCenter, up, right);\n\t\t\tgl_Position = mvp * localVertexPosition;\n\t\t"),
|
||||
(this.w5p_1 = new Ss()),
|
||||
(this.x5p_1 = new Ss()));
|
||||
}
|
||||
@@ -10740,7 +10740,7 @@
|
||||
(this.k40_1.c41_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DYNAMIC_LIGHT\n\t\tuniform sampler2D dynamicLightTexture;\n\t\t#endif // USE_DYNAMIC_LIGHT\n\t\t\n\t\t#define USE_SHADOW_MAP " +
|
||||
(this.k40_1.b41_1 ? 1 : 0) +
|
||||
"\n\t\t#ifdef USE_SHADOW_MAP\n\t\tuniform mat4 worldToShadowClipSpaceMatrix;\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\
Line truncated
|
||||
"\n\t\t#ifdef USE_SHADOW_MAP\n\t\tuniform mat4 worldToShadowClipSpaceMatrix;\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWi
Line truncated
|
||||
);
|
||||
}),
|
||||
(cs(dv).i3u = function (t, n) {
|
||||
@@ -11842,7 +11842,7 @@
|
||||
return "\n\t\tuniform mat4 mvp;\n\t\t// width, length\n\t\tuniform vec2 size;\n\t\tuniform float amplitude;\n\t\tuniform float distanceFrequency;\n\t\tuniform float timeFrequency;\n\t\tuniform float time;\n\t\tuniform float speed;\n\t\tuniform float sideOffset;\n\t\tuniform float phaseOffset;\n\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\t\n\t\tout vec2 vUV;\n\t\tout float vV;\n\t\t\n\t\t#define PI 3.14159\n\t\t\n\t\tfloat shape(float x)\n\t\t{\n\t\t\tfloat t = 1.5 * x;\n\t\t\treturn t * t * (3.0 - 2.0 * t);\n\t\t}\n\n\t\tvoid main()\n\t\t{\n\t\t\tvV = uv.y;\n\t\t\tvUV = uv + vec2(0.0, speed * time);\n\t\t\tfloat v = uv.y;\n\t\t\tfloat s = 0.15;\n\t\t\tfloat w = sin(s * PI + (1.0 - 2.0 * s) * PI * v);\n\t\t\tvec2 pos = vec2(w, 1.0) * size * (uv - vec2(0.5, 0.0));\n\t\t\tfloat offset = amplitude * sin(distanceFrequency * v + time * timeFrequency + phaseOffset);\n\t\t\tpos.x += offset * shape(v);\n\t\t\tpos.x += sideOffset * sin(PI * v);\n\t\t\tgl_Position = mvp * vec4(pos, 0.0, 1.0);\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(Rp).n3h = function () {
|
||||
return "\n\t\tuniform sampler2D mainTexture;\n\t\t\n\t\tin vec2 vUV;\n\t\tin float vV;\n\t\t\n\t\tvoid main()\n\t\t{\n\t\t\tvec4 col = texture(mainTexture, vUV);\n\t\t\t// Увод прозрачноÑти в ноль на концах\n\t\t\tcol.a *= smoothstep(0.0, 0.02, vV) * (1.0 - smoothstep(0.98, 1.0, vV));\t\t\t\t\n\t\t\toutColor0 = col;\n\t\t}\n\t";
|
||||
return "\n\t\tuniform sampler2D mainTexture;\n\t\t\n\t\tin vec2 vUV;\n\t\tin float vV;\n\t\t\n\t\tvoid main()\n\t\t{\n\t\t\tvec4 col = texture(mainTexture, vUV);\n\t\t\t// Увод прозрачности в ноль на концах\n\t\t\tcol.a *= smoothstep(0.0, 0.02, vV) * (1.0 - smoothstep(0.98, 1.0, vV));\t\t\t\t\n\t\t\toutColor0 = col;\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(Pp).h3e = function () {
|
||||
return new Mp(this);
|
||||
@@ -11887,7 +11887,7 @@
|
||||
return (
|
||||
"\n\t\t#define ALPHA_TEST " +
|
||||
(this.x3u_1.q4h_1 ? 1 : 0) +
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\t// ТеÑÑ‚ проще, чем SingleTextureProgram, Ñ‚.к. нет таких требований к корректноÑти.\n\t\t\tfloat a = texture(mainTexture, v_uv).a;\n\t\t\tif (a < 0.5) discard;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\t// Тест проще, чем SingleTextureProgram, т.к. нет таких требований к корректности.\n\t\t\tfloat a = texture(mainTexture, v_uv).a;\n\t\t\tif (a < 0.5) discard;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Dp).h3e = function () {
|
||||
@@ -11921,14 +11921,14 @@
|
||||
return (
|
||||
"\n\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\n\t\tuniform mat4 boneMatrices[30];\n\t\tlayout(location=7)\n\t\tin uvec2 boneIndex;\n\t\tlayout(location=8)\n\t\tin vec2 boneWeight;\n\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\t\n\t\t#define ALPHA_TEST " +
|
||||
(this.t3v_1.s4h_1 ? 1 : 0) +
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tout vec2 v_uv;\n\t\t#endif\n\t\n\t\tvoid main() {\n\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t// ЕÑли Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ иÑпользуетÑÑ, то и индекÑ, и Ð²ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ равны нулю.\n\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t}\n\t\t\tmat4 mvp = viewProjectionMatrix * modelToWorldMatrix;\n\t\t\t// Пока проÑтой вариант, Ñ‚.к. у Ð½Ð°Ñ Ð½ÐµÑ‚ маÑштабированиÑ.\n\t\t\tmat3 normalToWorldMatrix = mat3(modelToWorldMatrix);\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t#if ALPHA_TEST\n\t\t\tv_uv = uv;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tout vec2 v_uv;\n\t\t#endif\n\t\n\t\tvoid main() {\n\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t// Если индекс не используется, то и индекс, и вес будут равны нулю.\n\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t}\n\t\t\tmat4 mvp = viewProjectionMatrix * modelToWorldMatrix;\n\t\t\t// Пока простой вариант, т.к. у нас нет масштабирования.\n\t\t\tmat3 normalToWorldMatrix = mat3(modelToWorldMatrix);\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t#if ALPHA_TEST\n\t\t\tv_uv = uv;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Up).n3h = function () {
|
||||
return (
|
||||
"\n\t\t#define ALPHA_TEST " +
|
||||
(this.t3v_1.s4h_1 ? 1 : 0) +
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\t// ТеÑÑ‚ проще, чем SingleTextureProgram, Ñ‚.к. нет таких требований к корректноÑти.\n\t\t\tfloat a = texture(mainTexture, v_uv).a;\n\t\t\tif (a < 0.5) discard;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\t// Тест проще, чем SingleTextureProgram, т.к. нет таких требований к корректности.\n\t\t\tfloat a = texture(mainTexture, v_uv).a;\n\t\t\tif (a < 0.5) discard;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Fp).h3e = function () {
|
||||
@@ -11959,14 +11959,14 @@
|
||||
return (
|
||||
"\n\t\tuniform mat4 worldToShadowProjectionMatrix;\n\t\tuniform mat4 boneMatrices[30];\n\t\tlayout(location=7)\n\t\tin uvec2 boneIndex;\n\t\tlayout(location=8)\n\t\tin vec2 boneWeight;\n\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\t\n\t\t#define ALPHA_TEST " +
|
||||
(this.j3v_1.u4h_1 ? 1 : 0) +
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tout vec2 v_uv;\n\t\t#endif\n\t\n\t\tvoid main() {\n\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t// ЕÑли Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ иÑпользуетÑÑ, то и индекÑ, и Ð²ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ равны нулю.\n\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t}\n\t\t\tmat4 mvp = worldToShadowProjectionMatrix * modelToWorldMatrix;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t#if ALPHA_TEST\n\t\t\tv_uv = uv;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tout vec2 v_uv;\n\t\t#endif\n\t\n\t\tvoid main() {\n\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t// Если индекс не используется, то и индекс, и вес будут равны нулю.\n\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t}\n\t\t\tmat4 mvp = worldToShadowProjectionMatrix * modelToWorldMatrix;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t#if ALPHA_TEST\n\t\t\tv_uv = uv;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Wp).n3h = function () {
|
||||
return (
|
||||
"\n\t\t#define ALPHA_TEST " +
|
||||
(this.j3v_1.u4h_1 ? 1 : 0) +
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\t// ТеÑÑ‚ проще, чем SingleTextureProgram, Ñ‚.к. нет таких требований к корректноÑти.\n\t\t\tfloat a = texture(mainTexture, v_uv).a;\n\t\t\tif (a < 0.5) discard;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\t// Тест проще, чем SingleTextureProgram, т.к. нет таких требований к корректности.\n\t\t\tfloat a = texture(mainTexture, v_uv).a;\n\t\t\tif (a < 0.5) discard;\n\t\t\t#endif\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Vp).c3q = function (t) {
|
||||
@@ -12001,7 +12001,7 @@
|
||||
(this.q4i_1 = this.w3h("alpha")));
|
||||
}),
|
||||
(cs(Zp).m3h = function () {
|
||||
return "\n\t\t// u' = u * t.x + t.y\n\t\t// v' = v * t.z + t.w\n\t\tuniform vec4 uvTransform;\n\t\t// xy -- windowWidth, windowHeight\n\t\t// zw -- rectWidth, rectHeight\n\t\tuniform vec4 windowAndRectSize;\n\t\t// xy -- левый верхний угол в оконных координатах.\n\t\t// z -- глубина в интервале [-1, 1].\n\t\tuniform vec3 position;\n\t\n\t\tlayout(location=0)\n\t\tin vec2 vertexPosition;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\t\n\t\tout vec2 vUV;\n\t\t\n\t\t\n\t\t#ifndef SCREEN_TO_NDC\n\t\t#define SCREEN_TO_NDC\n\t\t\n\t\tvec2 screenToNdc(vec2 screenSize, vec2 screenCoordinates) {\n\t\t\tvec2 normalized = screenCoordinates / screenSize;\n\t\t\treturn vec2(2.0, -2.0) * normalized - vec2(1.0, -1.0);\n\t\t}\n\t\t\n\t\t#endif //SCREEN_TO_NDC\n\t\n\t\n\t\tvoid main(void) {\n\t\t\tvUV = uv * uvTransform.xz + uvTransform.yw;\n\t\n\t\t\tvec2 windowSize = windowAndRectSize.xy;\n\t\t\tvec2 rectSize = windowAndRectSize.zw;\n\t\t\tvec2 xy = position.xy + vertexPosition * rectSize;\n\t\t\tvec2 ndc = screenToNdc(windowSize, xy);\n\t\t\tgl_Position = vec4(ndc, position.z, 1.0);\n\t\t}\n\t";
|
||||
return "\n\t\t// u' = u * t.x + t.y\n\t\t// v' = v * t.z + t.w\n\t\tuniform vec4 uvTransform;\n\t\t// xy -- windowWidth, windowHeight\n\t\t// zw -- rectWidth, rectHeight\n\t\tuniform vec4 windowAndRectSize;\n\t\t// xy -- левый верхний угол в оконных координатах.\n\t\t// z -- глубина в интервале [-1, 1].\n\t\tuniform vec3 position;\n\t\n\t\tlayout(location=0)\n\t\tin vec2 vertexPosition;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\t\n\t\tout vec2 vUV;\n\t\t\n\t\t\n\t\t#ifndef SCREEN_TO_NDC\n\t\t#define SCREEN_TO_NDC\n\t\t\n\t\tvec2 screenToNdc(vec2 screenSize, vec2 screenCoordinates) {\n\t\t\tvec2 normalized = screenCoordinates / screenSize;\n\t\t\treturn vec2(2.0, -2.0) * normalized - vec2(1.0, -1.0);\n\t\t}\n\t\t\n\t\t#endif //SCREEN_TO_NDC\n\t\n\t\n\t\tvoid main(void) {\n\t\t\tvUV = uv * uvTransform.xz + uvTransform.yw;\n\t\n\t\t\tvec2 windowSize = windowAndRectSize.xy;\n\t\t\tvec2 rectSize = windowAndRectSize.zw;\n\t\t\tvec2 xy = position.xy + vertexPosition * rectSize;\n\t\t\tvec2 ndc = screenToNdc(windowSize, xy);\n\t\t\tgl_Position = vec4(ndc, position.z, 1.0);\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(Zp).n3h = function () {
|
||||
return "\n\t\tuniform sampler2D mainTexture;\n\t\tuniform float alpha;\n\t\n\t\tin vec2 vUV;\n\t\n\t\tvoid main(void) {\n\t\t\tvec4 color = texture(mainTexture, vUV);\n\t\t\tcolor.w *= alpha;\n\t\t\toutColor0 = color;\n\t\t}\n\t";
|
||||
@@ -12050,7 +12050,7 @@
|
||||
}),
|
||||
(cs(od).m3h = function () {
|
||||
return (
|
||||
"\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=5)\n\t\tin vec3 lightPosition;\n\t\tlayout(location=3)\n\t\t// Ðльфа Ñодержит мощноÑть Ñвета.\n\t\tin vec4 lightColorAndPower;\n\t\t\n\t\tflat out vec3 vLightPosition;\n\t\tflat out vec4 vLightColorAndPower;\n\t\t\n\t\t#define POINT_LIGHT " +
|
||||
"\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=5)\n\t\tin vec3 lightPosition;\n\t\tlayout(location=3)\n\t\t// Альфа содержит мощность света.\n\t\tin vec4 lightColorAndPower;\n\t\t\n\t\tflat out vec3 vLightPosition;\n\t\tflat out vec4 vLightColorAndPower;\n\t\t\n\t\t#define POINT_LIGHT " +
|
||||
(this.r42_1.equals(ed()) ? 1 : 0) +
|
||||
"\n\t\t#if POINT_LIGHT\n\t\tlayout(location=4)\n\t\t// x -- inner radius, y -- outer radius\n\t\tin vec2 lightAttenuation;\n\t\tflat out vec2 vLightAttenuation;\n\t\t#endif // POINT_LIGHT\n\t\t\n\t\t#define SPOT_LIGHT " +
|
||||
(this.r42_1.equals(ud()) ? 1 : 0) +
|
||||
@@ -12067,7 +12067,7 @@
|
||||
(this.r42_1.equals(ud()) ? 1 : 0) +
|
||||
"\n\t\t#if SPOT_LIGHT\n\t\tflat in vec4 vLightAttenuation;\n\t\tflat in vec3 vLightDirection;\n\t\t#endif\n\t\t\n\t\t#define LINE_LIGHT " +
|
||||
(this.r42_1.equals(sd()) ? 1 : 0) +
|
||||
"\n\t\t#if LINE_LIGHT\n\t\tflat in vec2 vLightAttenuation;\n\t\tflat in vec3 vLightVector;\n\t\tflat in float vLightSquaredLengthReciprocal;\n\t\t#endif //LINE_LIGHT\n\t\t\n\t\tfloat unpack(vec2 v, float n) {\n\t\t\treturn v.x * n + v.y * n * n;\n\t\t}\n\t\t\n\t\tvec3 unpack(vec2 enc)\n\t\t{\n\t\t\tvec2 f = enc - vec2(0.5);\n\t\t\tfloat c = min(dot(f, f), 0.25);\n\t\t\tfloat p = sqrt(8. - 16. * c);\n\t\t\tvec3 n;\n\t\t\tn.xy = p * f;\n\t\t\tn.z = 1. - 4. * c;\n\t\t\treturn n;\n\t\t}\n\t\t\n\t\tvec3 getViewSpacePosition(vec2 normalizedScreenCoordinate, float depth) {\n\t\t // Множитель 2 включён в fovScale, поÑтому здеÑÑŒ только половина.\n\t\t\tvec2 halfNdc = normalizedScreenCoordinate - vec2(0.5);\n\t\t\treturn vec3(halfNdc * fovScale * depth, -depth);\n\t\t}\n\t\t\n\t\tfloat windowFunc(float distance, float outerRadius) {\n\t\t\tfloat t = distance / outerRadius;\n\t\t\tfloat k = max(1.0 - t*t*t*t, 0.0);\n\t\t\treturn k * k;\n\t\t}\n\t\t\n\t\tfloat getDistanceAttenuation(float distance, float innerRadius, float outerRadius) {\n\t\t\tfloat window = windowFunc(distance, outerRadius);\n\t\t\tfloat k = innerRadius / max(distance, innerRadius);\n\t\t\treturn k * k * window;\n\t\t}\n\t\t\n\t\tfloat getConeAttenuation(vec3 r, vec3 lightDirection, vec2 attenuationParams) {\n\t\t\tfloat s = max(dot(r, lightDirection), 0.0);\n\t\t\tfloat t = (s - attenuationParams.x) / attenuationParams.y;\n\t\t\tt = smoothstep(0.0, 1.0, t);\n\t\t\treturn t;\n\t\t}\n\t\t\t\t\t\n\t\tvoid main() {\n\t\t\tvec2 normalizedScreenCoordinate = gl_FragCoord.xy/screenSize.xy; \n\t\t\tvec4 viewDepthAndNormal = texture(viewDepthAndNormalTexture, normalizedScreenCoordinate);\n\t\t\tfloat depth = viewDepthAndNormal.r;\n\t\t\tvec3 normal = viewDepthAndNormal.gba;\n\t\t\t//float depth = unpack(positionAndNormal_packed.rg, 5.);\n\t\t\t//vec3 normal = normalize(unpack(positionAndNormal_packed.ba));\n\t\t\n\t\t\tvec3 position = getViewSpacePosition(normalizedScreenCoordinate, depth);\n\t\t\t\n\t\t\t#if LINE_LIGHT\n\t\t\tfloat t = clamp(dot(vLightVector, position - vLightPosition) * vLightSquaredLengthReciprocal, 0., 1.);\n\t\t\tvec3 p = vLightPosition + t * vLightVector;\n\t\t\tvec3 directionToLight = p - position;\n\t\t\tfloat distanceToLight = length(directionToLight);\n\t\t\tdirectionToLight = normalize(directionToLight);\n\t\t\t\n\t\t\t#else // LINE_LIGHT\n\t\t\t\n\t\t\tvec3 directionToLight = normalize(vLightPosition - position);\n\t\t\tfloat distanceToLight = distance(vLightPosition, position);\n\t\t\t\n\t\t\t#endif // LINE_LIGHT\n\t\t\t\n\t\t\tfloat illumination = max(0.0, dot(normal, directionToLight));\n\t\t\tfloat attenuation = getDistanceAttenuation(distanceToLight, vLightAttenuation.x, vLightAttenuation.y);\n\t\t\t\n\t\t\t#if SPOT_LIGHT\n\t\t\tattenuation *= getConeAttenuation(-directionToLight, vLightDirection, vLightAttenuation.zw);\n\t\t\t#endif\n\t\t\t\n\t\t\tvec3 color = vLightColorAndPower.a * illumination * attenuation * vLightColorAndPower.rgb; \n\t\t\t\n\t\t\toutColor0 = vec4(color, 1.0);\n\t\t}\n\t"
|
||||
"\n\t\t#if LINE_LIGHT\n\t\tflat in vec2 vLightAttenuation;\n\t\tflat in vec3 vLightVector;\n\t\tflat in float vLightSquaredLengthReciprocal;\n\t\t#endif //LINE_LIGHT\n\t\t\n\t\tfloat unpack(vec2 v, float n) {\n\t\t\treturn v.x * n + v.y * n * n;\n\t\t}\n\t\t\n\t\tvec3 unpack(vec2 enc)\n\t\t{\n\t\t\tvec2 f = enc - vec2(0.5);\n\t\t\tfloat c = min(dot(f, f), 0.25);\n\t\t\tfloat p = sqrt(8. - 16. * c);\n\t\t\tvec3 n;\n\t\t\tn.xy = p * f;\n\t\t\tn.z = 1. - 4. * c;\n\t\t\treturn n;\n\t\t}\n\t\t\n\t\tvec3 getViewSpacePosition(vec2 normalizedScreenCoordinate, float depth) {\n\t\t // Множитель 2 включён в fovScale, поэтому здесь только половина.\n\t\t\tvec2 halfNdc = normalizedScreenCoordinate - vec2(0.5);\n\t\t\treturn vec3(halfNdc * fovScale * depth, -depth);\n\t\t}\n\t\t\n\t\tfloat windowFunc(float distance, float outerRadius) {\n\t\t\tfloat t = distance / outerRadius;\n\t\t\tfloat k = max(1.0 - t*t*t*t, 0.0);\n\t\t\treturn k * k;\n\t\t}\n\t\t\n\t\tfloat getDistanceAttenuation(float distance, float innerRadius, float outerRadius) {\n\t\t\tfloat window = windowFunc(distance, outerRadius);\n\t\t\tfloat k = innerRadius / max(distance, innerRadius);\n\t\t\treturn k * k * window;\n\t\t}\n\t\t\n\t\tfloat getConeAttenuation(vec3 r, vec3 lightDirection, vec2 attenuationParams) {\n\t\t\tfloat s = max(dot(r, lightDirection), 0.0);\n\t\t\tfloat t = (s - attenuationParams.x) / attenuationParams.y;\n\t\t\tt = smoothstep(0.0, 1.0, t);\n\t\t\treturn t;\n\t\t}\n\t\t\t\t\t\n\t\tvoid main() {\n\t\t\tvec2 normalizedScreenCoordinate = gl_FragCoord.xy/screenSize.xy; \n\t\t\tvec4 viewDepthAndNormal = texture(viewDepthAndNormalTexture, normalizedScreenCoordinate);\n\t\t\tfloat depth = viewDepthAndNormal.r;\n\t\t\tvec3 normal = viewDepthAndNormal.gba;\n\t\t\t//float depth = unpack(positionAndNormal_packed.rg, 5.);\n\t\t\t//vec3 normal = normalize(unpack(positionAndNormal_packed.ba));\n\t\t\n\t\t\tvec3 position = getViewSpacePosition(normalizedScreenCoordinate, depth);\n\t\t\t\n\t\t\t#if LINE_LIGHT\n\t\t\tfloat t = clamp(dot(vLightVector, position - vLightPosition) * vLightSquaredLengthReciprocal, 0., 1.);\n\t\t\tvec3 p = vLightPosition + t * vLightVector;\n\t\t\tvec3 directionToLight = p - position;\n\t\t\tfloat distanceToLight = length(directionToLight);\n\t\t\tdirectionToLight = normalize(directionToLight);\n\t\t\t\n\t\t\t#else // LINE_LIGHT\n\t\t\t\n\t\t\tvec3 directionToLight = normalize(vLightPosition - position);\n\t\t\tfloat distanceToLight = distance(vLightPosition, position);\n\t\t\t\n\t\t\t#endif // LINE_LIGHT\n\t\t\t\n\t\t\tfloat illumination = max(0.0, dot(normal, directionToLight));\n\t\t\tfloat attenuation = getDistanceAttenuation(distanceToLight, vLightAttenuation.x, vLightAttenuation.y);\n\t\t\t\n\t\t\t#if SPOT_LIGHT\n\t\t\tattenuation *= getConeAttenuation(-directionToLight, vLightDirection, vLightAttenuation.zw);\n\t\t\t#endif\n\t\t\t\n\t\t\tvec3 color = vLightColorAndPower.a * illumination * attenuation * vLightColorAndPower.rgb; \n\t\t\t\n\t\t\toutColor0 = vec4(color, 1.0);\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(_d).c3q = function (t) {
|
||||
@@ -12110,7 +12110,7 @@
|
||||
(this.e3p_1.t4i_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SKINNING\n\t\t\tuniform mat4 boneMatrices[30];\n\t\t\tlayout(location=7)\n\t\t\tin uvec2 boneIndex;\n\t\t\tlayout(location=8)\n\t\t\tin vec2 boneWeight;\n\t\t#else\n\t\t\tuniform mat4 mvp;\n\t\t\tuniform mat4 modelToViewMatrix;\n\t\t\tuniform mat3 normalToViewMatrix;\n\t\t#endif\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\t\n\t\t#define ALPHA_TEST " +
|
||||
(this.e3p_1.u4i_1 ? 1 : 0) +
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tout vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tout float v_viewZ;\n\t\tout vec3 v_viewNormal;\n\t\t\t\t\t\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\tv_uv = uv;\n\t\t\t#endif\n\t\t\t#if USE_SKINNING\n\t\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\t// ЕÑли Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ иÑпользуетÑÑ, то и индекÑ, и Ð²ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ равны нулю.\n\t\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t\t}\n\t\t\t\tmat4 mvp = vertexProjectionMatrix * modelToWorldMatrix;\n\t\t\t\tmat4 modelToViewMatrix = viewMatrix * modelToWorldMatrix;\n\t\t\t\t// Пока проÑтой вариант, Ñ‚.к. у Ð½Ð°Ñ Ð½ÐµÑ‚ маÑштабированиÑ.\n\t\t\t\tmat3 normalToViewMatrix = mat3(modelToViewMatrix);\n\t\t\t#else\n\t\t\t\tmat4 mvp = vertexProjectionMatrix;\n\t\t\t#endif\n\t\t\tv_viewZ = (modelToViewMatrix * vec4(position, 1.0)).z;\n\t\t\tv_viewNormal = normalToViewMatrix * normal;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t}\n\t"
|
||||
"\n\t\t#if ALPHA_TEST\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tout vec2 v_uv;\n\t\t#endif\n\t\t\n\t\tout float v_viewZ;\n\t\tout vec3 v_viewNormal;\n\t\t\t\t\t\t\t\n\t\tvoid main() {\n\t\t\t#if ALPHA_TEST\n\t\t\tv_uv = uv;\n\t\t\t#endif\n\t\t\t#if USE_SKINNING\n\t\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\t// Если индекс не используется, то и индекс, и вес будут равны нулю.\n\t\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t\t}\n\t\t\t\tmat4 mvp = vertexProjectionMatrix * modelToWorldMatrix;\n\t\t\t\tmat4 modelToViewMatrix = viewMatrix * modelToWorldMatrix;\n\t\t\t\t// Пока простой вариант, т.к. у нас нет масштабирования.\n\t\t\t\tmat3 normalToViewMatrix = mat3(modelToViewMatrix);\n\t\t\t#else\n\t\t\t\tmat4 mvp = vertexProjectionMatrix;\n\t\t\t#endif\n\t\t\tv_viewZ = (modelToViewMatrix * vec4(position, 1.0)).z;\n\t\t\tv_viewNormal = normalToViewMatrix * normal;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(hd).n3h = function () {
|
||||
@@ -13354,7 +13354,7 @@
|
||||
return (
|
||||
"\n\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t#define USE_SKINNING " +
|
||||
(this.o4y_1.h4y_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SKINNING\n\t\t\tuniform mat4 boneMatrices[30];\n\t\t\tlayout(location=7)\n\t\t\tin uvec2 boneIndex;\n\t\t\tlayout(location=8)\n\t\t\tin vec2 boneWeight;\n\t\t#else\n\t\t\tuniform mat4 modelMatrix;\n\t\t#endif // USE_SKINNING\n\t\t//fixme(fma): use uniform block?\n\t\tuniform float vertexOffset;\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=6)\n\t\tin vec3 normal;\n\t\n\t\tvoid main(void) {\n\t\t\t#if USE_SKINNING\n\t\t\tmat4 modelMatrix = mat4(0);\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t// ЕÑли Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ иÑпользуетÑÑ, то и индекÑ, и Ð²ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ равны нулю.\n\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\tmodelMatrix += boneWeight[i] * boneMatrix;\n\t\t\t}\n\t\t\t#endif\n\t\t\t// ИÑпользуем упрощённый раÑÑчёт мировых нормалей, Ñ‚.к. пока у наÑ\n\t\t\t// нет неравномерного маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð² Ñ Ð¾Ð±Ð²Ð¾Ð´ÐºÐ¾Ð¹.\n\t\t\tmat3 normalToWorldMatrix = mat3(modelMatrix);\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tvec4 worldPosition = modelMatrix * vec4(position, 1.0);\n\t\t\tworldPosition.xyz += vertexOffset * worldNormal;\n\t\t\tgl_Position = viewProjectionMatrix * worldPosition;\n\t\t}\n\t"
|
||||
"\n\t\t#if USE_SKINNING\n\t\t\tuniform mat4 boneMatrices[30];\n\t\t\tlayout(location=7)\n\t\t\tin uvec2 boneIndex;\n\t\t\tlayout(location=8)\n\t\t\tin vec2 boneWeight;\n\t\t#else\n\t\t\tuniform mat4 modelMatrix;\n\t\t#endif // USE_SKINNING\n\t\t//fixme(fma): use uniform block?\n\t\tuniform float vertexOffset;\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=6)\n\t\tin vec3 normal;\n\t\n\t\tvoid main(void) {\n\t\t\t#if USE_SKINNING\n\t\t\tmat4 modelMatrix = mat4(0);\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t// Если индекс не используется, то и индекс, и вес будут равны нулю.\n\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\tmodelMatrix += boneWeight[i] * boneMatrix;\n\t\t\t}\n\t\t\t#endif\n\t\t\t// Используем упрощённый рассчёт мировых нормалей, т.к. пока у нас\n\t\t\t// нет неравномерного масштабирования объектов с обводкой.\n\t\t\tmat3 normalToWorldMatrix = mat3(modelMatrix);\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tvec4 worldPosition = modelMatrix * vec4(position, 1.0);\n\t\t\tworldPosition.xyz += vertexOffset * worldNormal;\n\t\t\tgl_Position = viewProjectionMatrix * worldPosition;\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Yg).n3h = function () {
|
||||
@@ -16197,7 +16197,7 @@
|
||||
(this.e5z_1 = this.w3h("u_backgroundColor")));
|
||||
}),
|
||||
(cs(hq).m3h = function () {
|
||||
return "\n\t\tlayout(location=0)\n\t\tin vec2 i_coordinate;\n\t\tlayout(location=1)\n\t\tin float i_progress;\n\t\tlayout(location=2)\n\t\tin float i_alpha;\n\n\t\t// Точка, отноÑительно которой риÑуетÑÑ Ñлемент\n\t\tuniform vec3 u_normalizedPosition;\n\t\tuniform vec2 u_scaleAndNormalize;\n\t\t\n\t\tout float v_progress;\n\t\tout float v_alpha;\n\t\t\n\t\tvoid main() {\n\t\t\tv_progress = i_progress;\n\t\t\tv_alpha = i_alpha;\n\t\t\tvec2 xy = u_normalizedPosition.xy + i_coordinate * u_scaleAndNormalize;\n\t\t\tgl_Position = vec4(xy, u_normalizedPosition.z, 1.0);\n\t\t}\n\t";
|
||||
return "\n\t\tlayout(location=0)\n\t\tin vec2 i_coordinate;\n\t\tlayout(location=1)\n\t\tin float i_progress;\n\t\tlayout(location=2)\n\t\tin float i_alpha;\n\n\t\t// Точка, относительно которой рисуется элемент\n\t\tuniform vec3 u_normalizedPosition;\n\t\tuniform vec2 u_scaleAndNormalize;\n\t\t\n\t\tout float v_progress;\n\t\tout float v_alpha;\n\t\t\n\t\tvoid main() {\n\t\t\tv_progress = i_progress;\n\t\t\tv_alpha = i_alpha;\n\t\t\tvec2 xy = u_normalizedPosition.xy + i_coordinate * u_scaleAndNormalize;\n\t\t\tgl_Position = vec4(xy, u_normalizedPosition.z, 1.0);\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(hq).n3h = function () {
|
||||
return "\n\t\tin float v_progress;\n\t\tin float v_alpha;\n\t\t\n\t\tuniform float u_progress;\n\t\tuniform vec4 u_color;\n\t\tuniform vec4 u_backgroundColor;\n\t\t\n\t\tvoid main() {\n\t\t\tfloat mixCoeff = step(u_progress, v_progress);\n\t\t\toutColor0 = mix(u_color, u_backgroundColor, mixCoeff);\n\t\t\toutColor0.a *= v_alpha;\n\t\t}\n\t";
|
||||
@@ -16379,7 +16379,7 @@
|
||||
this.q61_1 && (this.t61_1 = this.w3h("uFogColor")));
|
||||
}),
|
||||
(cs(Uq).m3h = function () {
|
||||
return "\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\n\t\t// Матрица учитывает только ориентацию камеры и не учитывает транÑформацию объекта.\n\t\t// Таким образом ÑÐºÐ°Ð¹Ð±Ð¾ÐºÑ Ð²Ñегда находитÑÑ Ð² координатах камеры.\n\t\tuniform mat4 mvp;\n\n\t\tout vec3 texCoord;\n\n\t\tvoid main() {\n\t\t\t// Т.к. ÑÐºÐ°Ð¹Ð±Ð¾ÐºÑ Ð¿Ñ€ÐµÐ´Ñтавлен единичным кубом, то текÑÑ‚ÑƒÑ€Ð½Ð°Ñ ÐºÐ¾Ð¾Ñ€Ð´Ð¸Ð½Ð°Ñ‚Ð° в кубичеÑкой\n\t\t\t// текÑтуре равна локальным координатам вершины. Ðужно только поменÑть меÑтами оÑи\n\t\t\t// Y и Z из-за разных ÑиÑтем координат объекта и камеры.\n\t\t\ttexCoord.xyz = position.xzy;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t}\n\t";
|
||||
return "\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\n\t\t// Матрица учитывает только ориентацию камеры и не учитывает трансформацию объекта.\n\t\t// Таким образом скайбокс всегда находится в координатах камеры.\n\t\tuniform mat4 mvp;\n\n\t\tout vec3 texCoord;\n\n\t\tvoid main() {\n\t\t\t// Т.к. скайбокс представлен единичным кубом, то текстурная координата в кубической\n\t\t\t// текстуре равна локальным координатам вершины. Нужно только поменять местами оси\n\t\t\t// Y и Z из-за разных систем координат объекта и камеры.\n\t\t\ttexCoord.xyz = position.xzy;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(Uq).n3h = function () {
|
||||
return (
|
||||
@@ -16897,7 +16897,7 @@
|
||||
return "\n\t\tuniform mat4 viewProjectionMatrix;\n\t\tuniform vec2 timeAndWindStrength;\n\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tlayout(location=3)\n\t\tin vec3 instancePosition;\n\t\t// x = scale, y = cos(alpha), z = sin(alpha)\n\t\tlayout(location=4)\n\t\tin vec3 instanceScaleRotation;\n\t\t\n\t\tout vec2 vUV;\n\t\t\n\t\t\n\t\t\tmat4 makeModelMatrix(in float scale, in float cosRotationZ, in float sinRotationZ, in vec3 position) {\n\t\t\t\tfloat c = scale * cosRotationZ;\n\t\t\t\tfloat s = scale * sinRotationZ;\n\t\t\t\treturn mat4(\n\t\t\t\t\tvec4(c, s, 0., 0.),\n\t\t\t\t\tvec4(-s, c, 0., 0.),\n\t\t\t\t\tvec4(0., 0., scale, 0.),\n\t\t\t\t\tvec4(position, 1.0)\n\t\t\t\t);\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\tvec2 unity_gradientNoise_dir(vec2 p)\n\t\t{\n\t\t\tp = mod(p,289.0);\n\t\t\tfloat x = (34.0 * p.x + 1.0) * mod(p.x, 289.0) + p.y;\n\t\t\tx = (34.0 * x + 1.0) * mod(x, 289.0);\n\t\t\tx = fract(x / 41.0) * 2.0 - 1.0;\n\t\t\treturn normalize(vec2(x - floor(x + 0.5), abs(x) - 0.5));\n\t\t}\n\t\t\n\t\tfloat unity_gradientNoise(vec2 p)\n\t\t{\n\t\t\tvec2 ip = floor(p);\n\t\t\tvec2 fp = fract(p);\n\t\t\tfloat d00 = dot(unity_gradientNoise_dir(ip), fp);\n\t\t\tfloat d01 = dot(unity_gradientNoise_dir(ip + vec2(0, 1)), fp - vec2(0, 1));\n\t\t\tfloat d10 = dot(unity_gradientNoise_dir(ip + vec2(1, 0)), fp - vec2(1, 0));\n\t\t\tfloat d11 = dot(unity_gradientNoise_dir(ip + vec2(1, 1)), fp - vec2(1, 1));\n\t\t\tfp = fp * fp * fp * (fp * (fp * 6.0 - 15.0) + 10.0);\n\t\t\treturn mix(mix(d00, d01, fp.y), mix(d10, d11, fp.y), fp.x);\n\t\t}\n\t\t\n\t\tfloat gradientNoise(vec2 UV, float Scale)\n\t\t{\n\t\t\treturn unity_gradientNoise(UV * Scale) + 0.5;\n\t\t}\n\t\n\t\t\t#define WIND_SPEED 0.3\n\t\t\t\n\t\t\tvec4 getPositionModifiedByWind(vec4 position, float time, float windStrength) {\n\t\t\t\tfloat noise = gradientNoise(position.xy + time, WIND_SPEED);\n\t\t\t\tfloat offset = (2. * noise - 1.) * windStrength;\n\t\t\t\treturn position + vec4(offset, offset, 0., 0.);\n\t\t\t}\n\t\t\n\t\n\t\tvoid main() {\n\t\t\tvUV = uv;\n\t\t\tmat4 modelMatrix = makeModelMatrix(\n\t\t\t\tinstanceScaleRotation.x,\n\t\t\t\tinstanceScaleRotation.y,\n\t\t\t\tinstanceScaleRotation.z,\n\t\t\t\tinstancePosition\n\t\t\t);\n\t\t\tvec4 vertexWorldPosition = modelMatrix * vec4(position, 1.0);\n\t\t\tfloat time = timeAndWindStrength.x;\n\t\t\tfloat windStrength = timeAndWindStrength.y;\n\t\t\tvertexWorldPosition = getPositionModifiedByWind(vertexWorldPosition, time, windStrength);\n\t\t\n\t\t\tgl_Position = viewProjectionMatrix * vertexWorldPosition;\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(S$).n3h = function () {
|
||||
return "\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 vUV;\n\t\t\n\t\tvoid main() {\n\t\t\tfloat a = texture(mainTexture, vUV).a;\n\t\t\t// ПроÑтой теÑÑ‚, Ñ‚.к. нет выÑоких требований к корректноÑти как в SingleTextureProgram.\n\t\t\tif (a < 0.5) discard;\n\t\t}\n\t";
|
||||
return "\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 vUV;\n\t\t\n\t\tvoid main() {\n\t\t\tfloat a = texture(mainTexture, vUV).a;\n\t\t\t// Простой тест, т.к. нет высоких требований к корректности как в SingleTextureProgram.\n\t\t\tif (a < 0.5) discard;\n\t\t}\n\t";
|
||||
}),
|
||||
(cs(C$).c3q = function (t) {
|
||||
return this;
|
||||
@@ -16980,7 +16980,7 @@
|
||||
return (
|
||||
"\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tuniform vec2 timeAndWindStrength;\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tlayout(location=3)\n\t\tin vec3 instancePosition;\n\t\t// x = scale, y = cos(alpha), z = sin(alpha)\n\t\tlayout(location=4)\n\t\tin vec3 instanceScaleRotation;\n\t\t\n\t\tout vec2 v_uv;\n\t\tout float v_illumination;\n\t\t\n\t\t#define USE_SHADOW_MAP " +
|
||||
(this.b69_1.m69_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW_MAP\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowViewProjectionMatrix;\n\t\t#endif\n\t\t\n\t\t#define USE_ALPHA_DITHERING " +
|
||||
"\n\t\t#if USE_SHADOW_MAP\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowViewProjectionMatrix;\n\t\t#endif\n\t\t\n\t\t#define USE_ALPHA_DITHERING " +
|
||||
(this.b69_1.l69_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_ALPHA_DITHERING\n\t\tlayout(location=6) in float instanceAlpha;\n\t\tout float v_alpha;\n\t\t#endif\n\t\t\n\t\t#define USE_FOG " +
|
||||
(this.b69_1.n69_1 ? 1 : 0) +
|
||||
@@ -16993,11 +16993,11 @@
|
||||
(this.b69_1.k69_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DYNAMIC_LIGHT\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\tuniform sampler2D dynamicLightTexture;\n\t\t#endif\n\t\t\t\n\t\t#define USE_SHADOW_MAP " +
|
||||
(this.b69_1.m69_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW_MAP\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat
Line truncated
|
||||
"\n\t\t#if USE_SHADOW_MAP\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t#endif\n\t\t\n\t\t#define USE_ALPHA_DITHERING " +
|
||||
(this.b69_1.l69_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_ALPHA_DITHERING\n\t\tuniform sampler2D ditheringTexture;\n\t\tin float v_alpha;\n\t\t#endif\n\t\t\n\t\t" +
|
||||
Me.w5q(this.b69_1.n69_1) +
|
||||
"\n\t\t\n\t\t// Does not take into account GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD/GL_TEXTURE_LOD_BIAS,\n\t\t// nor implementation-specific flexibility allowed by OpenGL spec\n\t\tfloat mip_map_level(vec2 texture_coordinate) // in texel units\n\t\t{\n\t\t\tvec2 dx_vtc = dFdx(texture_coordinate);\n\t\t\tvec2 dy_vtc = dFdy(texture_coordinate);\n\t\t\tfloat delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));\n\t\t\tfloat mml = 0.5 * log2(delta_max_sqr);\n\t\t\treturn max(0.0, mml); \n\t\t}\n\t\t\n\t\tvoid main(void) {\n\t\t\t#if USE_ALPHA_DITHERING\n\t\t\tvec2 ditheringTextureSize = vec2(textureSize(ditheringTexture, 0));\n\t\t\tvec2 ditheringTextureUV = mod(gl_FragCoord.xy, ditheringTextureSize) / ditheringTextureSize;\n\t\t\tfloat ditheringTextureValue = texture(ditheringTexture, ditheringTextureUV).a;\n\t\t\tif (ditheringTextureValue >= v_alpha) discard;\n\t\t\t#endif // USE_ALPHA_DITHERIING\n\n\t\t\tvec4 color = texture(mainTexture, v_uv);\n\t\t\t\n\t\t\tivec2 mainTextureSize = textureSize(mainTexture, 0);\n\t\t\tfloat mipLevel = mip_map_level(v_uv * vec2(mainTextureSize));\n\t\t\t// МенÑем alpha в ÑоответÑтвии Ñ mip уровнем текÑтуры, что бы избежать Ñффекта иÑÑ‡ÐµÐ·Ð½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð½Ð° раÑÑтоÑнии.\n\t\t\t// NOTE(fominykh): РазобратьÑÑ Ñ‡Ñ‚Ð¾ Ñто такое на Ñамом деле и допиÑать поÑÑнение.\n\t\t\tfloat a = color.a * (1.0 + mipLevel * 0.25); \n\t\t\tif (a < 0.8) {\n\t\t\t\tdiscard;\t\t\t\n\t\t\t}\n\n\t\t\tfloat illumination = v_illumination;\n\t\t\n\t\t\t#if USE_SHADOW_MAP\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tillumination *= shadowAttenuation;\n\t\t\t#endif\n\t\n\t\t\tvec3 light = ambientLightColor + mainLightColor * illumination;\n\t\t\t\n\t\t\t#if USE_DYNAMIC_LIGHT\n\t\t\tvec2 lightmapUV = gl_FragCoord.xy / screenSize; \n\t\t\tvec3 dynamicLight = texture(dynamicLightTexture, lightmapUV).rgb;\n\t\t\tlight += dynamicLight;\n\t\t\t#endif\n\t\t\t\n\t\t\tcolor.rgb *= light;\n\t\t\tcolor.rgb *= lodColor;\n\t\t\t\n\t\t\t" +
|
||||
"\n\t\t\n\t\t// Does not take into account GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD/GL_TEXTURE_LOD_BIAS,\n\t\t// nor implementation-specific flexibility allowed by OpenGL spec\n\t\tfloat mip_map_level(vec2 texture_coordinate) // in texel units\n\t\t{\n\t\t\tvec2 dx_vtc = dFdx(texture_coordinate);\n\t\t\tvec2 dy_vtc = dFdy(texture_coordinate);\n\t\t\tfloat delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));\n\t\t\tfloat mml = 0.5 * log2(delta_max_sqr);\n\t\t\treturn max(0.0, mml); \n\t\t}\n\t\t\n\t\tvoid main(void) {\n\t\t\t#if USE_ALPHA_DITHERING\n\t\t\tvec2 ditheringTextureSize = vec2(textureSize(ditheringTexture, 0));\n\t\t\tvec2 ditheringTextureUV = mod(gl_FragCoord.xy, ditheringTextureSize) / ditheringTextureSize;\n\t\t\tfloat ditheringTextureValue = texture(ditheringTexture, ditheringTextureUV).a;\n\t\t\tif (ditheringTextureValue >= v_alpha) discard;\n\t\t\t#endif // USE_ALPHA_DITHERIING\n\n\t\t\tvec4 color = texture(mainTexture, v_uv);\n\t\t\t\n\t\t\tivec2 mainTextureSize = textureSize(mainTexture, 0);\n\t\t\tfloat mipLevel = mip_map_level(v_uv * vec2(mainTextureSize));\n\t\t\t// Меняем alpha в соответствии с mip уровнем текстуры, что бы избежать эффекта исчезновения на расстоянии.\n\t\t\t// NOTE(fominykh): Разобраться что это такое на самом деле и дописать пояснение.\n\t\t\tfloat a = color.a * (1.0 + mipLevel * 0.25); \n\t\t\tif (a < 0.8) {\n\t\t\t\tdiscard;\t\t\t\n\t\t\t}\n\n\t\t\tfloat illumination = v_illumination;\n\t\t\n\t\t\t#if USE_SHADOW_MAP\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tillumination *= shadowAttenuation;\n\t\t\t#endif\n\t\n\t\t\tvec3 light = ambientLightColor + mainLightColor * illumination;\n\t\t\t\n\t\t\t#if USE_DYNAMIC_LIGHT\n\t\t\tvec2 lightmapUV = gl_FragCoord.xy / screenSize; \n\t\t\tvec3 dynamicLight = texture(dynamicLightTexture, lightmapUV).rgb;\n\t\t\tlight += dynamicLight;\n\t\t\t#endif\n\t\t\t\n\t\t\tcolor.rgb *= light;\n\t\t\tcolor.rgb *= lodColor;\n\t\t\t\n\t\t\t" +
|
||||
Me.x5q("color.rgb") +
|
||||
"\n\t\t\t\n\t\t\toutColor0 = color;\n\t\t}\n\t"
|
||||
);
|
||||
@@ -17100,7 +17100,7 @@
|
||||
return (
|
||||
"\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tuniform mat4 mvp;\n\t\tuniform mat3 normalToWorldMatrix;\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\t\n\t\tout vec2 v_uv;\n\t\tout float v_illuminationFront;\n\t\tout float v_illuminationBack;\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.m6b_1.c6b_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowMVP;\n\t\t#endif\n\t\t\n\t\t#define USE_WIND " +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowMVP;\n\t\t#endif\n\t\t\n\t\t#define USE_WIND " +
|
||||
(this.m6b_1.e6b_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_WIND\n uniform float time;\n uniform highp sampler2D noiseTexture;\n\t\t#endif\n\t\t\t\t\n\t\t" +
|
||||
De.u5q(!0) +
|
||||
@@ -17119,7 +17119,7 @@
|
||||
(this.m6b_1.b6b_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DYNAMIC_LIGHT\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\tuniform sampler2D dynamicLightTexture;\n\t\t#endif // USE_DYNAMIC_LIGHT\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.m6b_1.c6b_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat Get
Line truncated
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t#endif\n\t\t\n\t\t\n\t\tuniform float alphaTestThreshold;\n\t\n\t\t// texture_coordinate in texel units\n\t\tfloat GetMipMapLevel(vec2 texture_coordinate) {\n\t\t\tvec2 dx_vtc = dFdx(texture_coordinate);\n\t\t\tvec2 dy_vtc = dFdy(texture_coordinate);\n\t\t\tfloat delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));\n\t\t\tfloat mml = 0.5 * log2(delta_max_sqr);\n\t\t\treturn max(0.0, mml); \n\t\t}\n\t\t\n\t\tbool IsAlphaBelowThreshold(float alpha, float threshold, vec2 uv, vec2 textureSize) {\n\t\t\tfloat mipLevel = GetMip
Line truncated
|
||||
De.w5q(!0) +
|
||||
"\n\t\t" +
|
||||
Me.w5q(this.m6b_1.d6b_1) +
|
||||
@@ -19061,14 +19061,14 @@
|
||||
return (
|
||||
"\n\t\tuniform mat4 mvp;\n\t\tuniform float uOffset;\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\t\n\t\tout vec2 v_uv;\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.i6s_1.q6s_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat3 normalToWorldMatrix;\n\t\tuniform mat4 shadowMVP;\n\t\t#endif\n\t\t\n\t\tvoid main(void) {\n\t\t\tv_uv = uv + vec2(uOffset, 0.);\n\t\t\tgl_Position = mvp * vec4(position, 1.);\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\tposition,\n\t\t\t\tnormal,\n\t\t\t\tworldNormal,\n\t\t\t\tmainLightDirection,\n\t\t\t\tshadowMVP\n\t\t\t);\n\t\t\t#endif\n\t\t}\n\t"
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat3 normalToWorldMatrix;\n\t\tuniform mat4 shadowMVP;\n\t\t#endif\n\t\t\n\t\tvoid main(void) {\n\t\t\tv_uv = uv + vec2(uOffset, 0.);\n\t\t\tgl_Position = mvp * vec4(position, 1.);\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\tposition,\n\t\t\t\tnormal,\n\t\t\t\tworldNormal,\n\t\t\t\tmainLightDirection,\n\t\t\t\tshadowMVP\n\t\t\t);\n\t\t\t#endif\n\t\t}\n\t"
|
||||
);
|
||||
}),
|
||||
(cs(Lz).n3h = function () {
|
||||
return (
|
||||
"\n\t\tuniform sampler2D mainTexture;\n\t\tin vec2 v_uv;\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.i6s_1.q6s_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance,
Line truncated
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t#endif\n\t\t\n\t\t#define USE_ALPHA_TEST " +
|
||||
(this.i6s_1.p6s_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_ALPHA_TEST\n\t\t\n\t\tuniform float alphaTestThreshold;\n\t\n\t\t// texture_coordinate in texel units\n\t\tfloat GetMipMapLevel(vec2 texture_coordinate) {\n\t\t\tvec2 dx_vtc = dFdx(texture_coordinate);\n\t\t\tvec2 dy_vtc = dFdy(texture_coordinate);\n\t\t\tfloat delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));\n\t\t\tfloat mml = 0.5 * log2(delta_max_sqr);\n\t\t\treturn max(0.0, mml); \n\t\t}\n\t\t\n\t\tbool IsAlphaBelowThreshold(float alpha, float threshold, vec2 uv, vec2 textureSize) {\n\t\t\tfloat mipLevel = GetMipMapLevel(uv * textureSize);\n\t\t\tfloat a = alpha * (1.0 + mipLevel * 0.25);\n\t\t\treturn a < threshold;\n\t\t}\n\t\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\tvec4 color = texture(mainTexture, v_uv);\n\t\t\t#if USE_ALPHA_TEST\n\t\t\tif (color.a < alphaTestThreshold) discard;\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tvec3 light = mix(ambientLightColor, vec3(1.), shadowAttenuation);\n\t\t\tcolor.rgb *= light;\n\t\t\t#endif\n\t\t\t\n\t\t\toutColor0 = color;\n\t\t}\n\t"
|
||||
);
|
||||
@@ -19226,7 +19226,7 @@
|
||||
(i.n6p_1 ? 1 : 0) +
|
||||
"\n\t\t\t#if USE_DIRECTIONAL_LIGHT\n\t\t\tin float v_illumination;\n\t\t\t\n\t\t\t#define USE_SHADOW " +
|
||||
(i.o6p_1 ? 1 : 0) +
|
||||
"\n\t\t\t#if USE_SHADOW\n\t\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat
Line truncated
|
||||
"\n\t\t\t#if USE_SHADOW\n\t\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t\t#endif // USE_SHADOW\n\t\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\t\n\t\t\t#define USE_LIGHTING (USE_AMBIENT_LIGHT || USE_DYNAMIC_LIGHT || USE_DIRECTIONAL_LIGHT)\n\t\t\t\n\t\t\t#if USE_AMBIENT_LIGHT || USE_DIRECTIONAL_LIGHT\n\t\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\t\t#endif\n\t\t\t\n\t\t\t#define USE_ALPHA_TEST " +
|
||||
(e ? 1 : 0) +
|
||||
"\n\t\t\t#if USE_ALPHA_TEST\n\t\t\t\n\t\tuniform float alphaTestThreshold;\n\t\n\t\t// texture_coordinate in texel units\n\t\tfloat GetMipMapLevel(vec2 texture_coordinate) {\n\t\t\tvec2 dx_vtc = dFdx(texture_coordinate);\n\t\t\tvec2 dy_vtc = dFdy(texture_coordinate);\n\t\t\tfloat delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));\n\t\t\tfloat mml = 0.5 * log2(delta_max_sqr);\n\t\t\treturn max(0.0, mml); \n\t\t}\n\t\t\n\t\tbool IsAlphaBelowThreshold(float alpha, float threshold, vec2 uv, vec2 textureSize) {\n\t\t\tfloat mipLevel = GetMipMapLevel(uv * textureSize);\n\t\t\tfloat a = alpha * (1.0 + mipLevel * 0.25);\n\t\t\treturn a < threshold;\n\t\t}\n\t\n\t\t\t#endif\n\t\t\t\n\t\t\t#define USE_COLOR_TRANSFORM " +
|
||||
(r ? 1 : 0) +
|
||||
@@ -19275,7 +19275,7 @@
|
||||
(this.j6t_1.y6t_1.n6p_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DIRECTIONAL_LIGHT\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\tuniform mat3 normalToWorldMatrix;\n\t\tout float v_illumination;\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.j6t_1.y6t_1.o6p_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowMVP;\n\t\t#endif // USE_SHADOW\n\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\n\t\t" +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowMVP;\n\t\t#endif // USE_SHADOW\n\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\n\t\t" +
|
||||
Me.u5q(this.j6t_1.b6u_1) +
|
||||
"\n\t\t\t\n\t\tvoid main(void) {\n\t\t\tv_uv = uv;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t\n\t\t\t#if USE_DIRECTIONAL_LIGHT\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tv_illumination = max(dot(worldNormal, -mainLightDirection), 0.);\n\t\t\n\t\t\t#if USE_SHADOW\n\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\tposition,\n\t\t\t\tnormal,\n\t\t\t\tworldNormal,\n\t\t\t\tmainLightDirection,\n\t\t\t\tshadowMVP\n\t\t\t);\n\t\t\t#endif // USE_SHADOW\n\t\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\t\n\t\t\t" +
|
||||
Me.v5q("position") +
|
||||
@@ -19674,11 +19674,11 @@
|
||||
(this.q6x_1.o6y_1 ? 1 : 0) +
|
||||
"\n\t\t\n\t\t#if USE_SKINNING\n\t\t\tuniform mat4 boneMatrices[30];\n\t\t\tlayout(location=7)\n\t\t\tin uvec2 boneIndex;\n\t\t\tlayout(location=8)\n\t\t\tin vec2 boneWeight;\n\t\t#else\n\t\tuniform mat4 mvp;\n\t\t#if USE_DIRECTIONAL_LIGHT\n\t\tuniform mat3 normalToWorldMatrix;\n\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t#endif // USE_SKINNING\n\t\t\n\t\tuniform vec2 uvOffset;\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\t\n\t\tout vec2 vUV;\n\t\t\n\t\t#if USE_DIRECTIONAL_LIGHT\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tout float v_illumination;\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.q6x_1.h6y_1.o6p_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowProjectionMatrix;\n\t\t#endif // USE_SHADOW\n\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\n\t\t" +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowProjectionMatrix;\n\t\t#endif // USE_SHADOW\n\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\n\t\t" +
|
||||
Me.u5q(this.q6x_1.n6y_1) +
|
||||
"\n\t\t\n\t\t#define MIX_BETWEEN_TWO_SAMPLES " +
|
||||
(this.q6x_1.m6y_1 ? 1 : 0) +
|
||||
"\n\t\t#if MIX_BETWEEN_TWO_SAMPLES\n\t\tuniform vec2 uv2Offset;\n\t\tout vec2 vUV2;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\tvUV = uv + uvOffset;\n\t\t\t#if MIX_BETWEEN_TWO_SAMPLES\n\t\t\tvUV2 = uv + uv2Offset;\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SKINNING\n\t\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\t// ЕÑли Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ иÑпользуетÑÑ, то и индекÑ, и Ð²ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ равны нулю.\n\t\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t\t}\n\t\t\t\tmat4 mvp = viewProjectionMatrix * modelToWorldMatrix;\n\t\t\t\t// Пока проÑтой вариант, Ñ‚.к. у Ð½Ð°Ñ Ð½ÐµÑ‚ маÑштабированиÑ.\n\t\t\t\tmat3 normalToWorldMatrix = mat3(modelToWorldMatrix);\n\t\t\t#endif\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t\n\t\t\t#if USE_DIRECTIONAL_LIGHT\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tv_illumination = max(dot(worldNormal, -mainLightDirection), 0.);\n\t\t\n\t\t\t#if USE_SHADOW\n\t\t\t\t#if USE_SKINNING\n\t\t\t\tvec3 worldPosition = (modelToWorldMatrix * vec4(position, 1.)).xyz;\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tworldPosition,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#else\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tposition,\n\t\t\t\t\tnormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#endif\n\t\t\t#endif\n\t\t\t#endif // USE_DIRECTIONAL_LIGHT\n\n\t\t\t" +
|
||||
"\n\t\t#if MIX_BETWEEN_TWO_SAMPLES\n\t\tuniform vec2 uv2Offset;\n\t\tout vec2 vUV2;\n\t\t#endif\n\t\t\n\t\tvoid main() {\n\t\t\tvUV = uv + uvOffset;\n\t\t\t#if MIX_BETWEEN_TWO_SAMPLES\n\t\t\tvUV2 = uv + uv2Offset;\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SKINNING\n\t\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\t// Если индекс не используется, то и индекс, и вес будут равны нулю.\n\t\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t\t}\n\t\t\t\tmat4 mvp = viewProjectionMatrix * modelToWorldMatrix;\n\t\t\t\t// Пока простой вариант, т.к. у нас нет масштабирования.\n\t\t\t\tmat3 normalToWorldMatrix = mat3(modelToWorldMatrix);\n\t\t\t#endif\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\t\n\t\t\t#if USE_DIRECTIONAL_LIGHT\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tv_illumination = max(dot(worldNormal, -mainLightDirection), 0.);\n\t\t\n\t\t\t#if USE_SHADOW\n\t\t\t\t#if USE_SKINNING\n\t\t\t\tvec3 worldPosition = (modelToWorldMatrix * vec4(position, 1.)).xyz;\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tworldPosition,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#else\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tposition,\n\t\t\t\t\tnormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#endif\n\t\t\t#endif\n\t\t\t#endif // USE_DIRECTIONAL_LIGHT\n\n\t\t\t" +
|
||||
Me.v5q("position") +
|
||||
"\n\t\t}\n\t"
|
||||
);
|
||||
@@ -19691,7 +19691,7 @@
|
||||
(this.q6x_1.h6y_1.n6p_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DIRECTIONAL_LIGHT\n\t\tin float v_illumination;\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.q6x_1.h6y_1.o6p_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat Get
Line truncated
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t#endif // USE_SHADOW\n\t\t#endif // USE_DIRECTIONAL_LIGHT\n\t\t\n\t\t#define MIX_BETWEEN_TWO_SAMPLES " +
|
||||
(this.q6x_1.m6y_1 ? 1 : 0) +
|
||||
"\n\t\t#if MIX_BETWEEN_TWO_SAMPLES\n\t\tuniform float mixCoeff;\n\t\tin vec2 vUV2;\n\t\t#endif\n\n\t\t#define USE_COLOR_TRANSFORM " +
|
||||
(this.q6x_1.j6y_1 ? 1 : 0) +
|
||||
@@ -19932,9 +19932,9 @@
|
||||
(this.c70_1.f71_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_ADDITIONAL_MAIN_LIGHTS\n\t\tuniform vec3 additionalMainLightDirection[2];\n\t\t#endif\n\t\t\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\t\t\n\t\tout vec2 v_uv;\n\t\tout vec2 v_uv_paint;\n\t\tout float v_illumination;\n\t\t\n\t\t#if USE_SPECULAR\n\t\t#if !USE_SKINNING\n\t\tuniform mat4 modelToWorldMatrix;\n\t\t#endif\n\t\tout vec3 v_normal;\n\t\tout vec3 v_fragmentWorldPosition;\n\t\t#endif\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.c70_1.z70_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowProjectionMatrix;\n\t\t#endif\n\n\t\t" +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowProjectionMatrix;\n\t\t#endif\n\n\t\t" +
|
||||
Me.u5q(this.c70_1.c71_1) +
|
||||
"\t\n\n\t\tuniform vec2 paintUVScale;\n\t\t\n\t\tvoid main(void) {\n\t\t\t#if USE_SKINNING\n\t\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\t// ЕÑли Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ иÑпользуетÑÑ, то и индекÑ, и Ð²ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ равны нулю.\n\t\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t\t}\n\t\t\t\tmat4 mvp = viewProjectionMatrix * modelToWorldMatrix;\n\t\t\t\t// Пока проÑтой вариант, Ñ‚.к. у Ð½Ð°Ñ Ð½ÐµÑ‚ маÑштабированиÑ.\n\t\t\t\tmat3 normalToWorldMatrix = mat3(modelToWorldMatrix);\n\t\t\t#endif\n\t\t\t\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\tv_uv = uv;\n\t\t\t\n\t\t\tv_uv_paint = fract(uv) * paintUVScale;\n\t\t\t\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tv_illumination = max(0., dot(worldNormal, -mainLightDirection));\n\t\t\t#if USE_ADDITIONAL_MAIN_LIGHTS\n\t\t\tv_illumination += max(0., dot(worldNormal, -additionalMainLightDirection[0]));\n\t\t\tv_illumination += max(0., dot(worldNormal, -additionalMainLightDirection[1]));\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SPECULAR\n\t\t\tv_normal = worldNormal;\n\t\t\tv_fragmentWorldPosition = vec3(modelToWorldMatrix * vec4(position, 1.0));\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\t\t#if USE_SKINNING\n\t\t\t\tvec3 worldPosition = (modelToWorldMatrix * vec4(position, 1.)).xyz;\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tworldPosition,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#else\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tposition,\n\t\t\t\t\tnormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#endif\n\t\t\t#endif\n\t\t\t\n\t\t\t" +
|
||||
"\t\n\n\t\tuniform vec2 paintUVScale;\n\t\t\n\t\tvoid main(void) {\n\t\t\t#if USE_SKINNING\n\t\t\t\tmat4 modelToWorldMatrix = mat4(0);\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\t// Если индекс не используется, то и индекс, и вес будут равны нулю.\n\t\t\t\t\tmat4 boneMatrix = boneMatrices[boneIndex[i]];\n\t\t\t\t\tmodelToWorldMatrix += boneWeight[i] * boneMatrix;\n\t\t\t\t}\n\t\t\t\tmat4 mvp = viewProjectionMatrix * modelToWorldMatrix;\n\t\t\t\t// Пока простой вариант, т.к. у нас нет масштабирования.\n\t\t\t\tmat3 normalToWorldMatrix = mat3(modelToWorldMatrix);\n\t\t\t#endif\n\t\t\t\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\t\t\tv_uv = uv;\n\t\t\t\n\t\t\tv_uv_paint = fract(uv) * paintUVScale;\n\t\t\t\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tv_illumination = max(0., dot(worldNormal, -mainLightDirection));\n\t\t\t#if USE_ADDITIONAL_MAIN_LIGHTS\n\t\t\tv_illumination += max(0., dot(worldNormal, -additionalMainLightDirection[0]));\n\t\t\tv_illumination += max(0., dot(worldNormal, -additionalMainLightDirection[1]));\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SPECULAR\n\t\t\tv_normal = worldNormal;\n\t\t\tv_fragmentWorldPosition = vec3(modelToWorldMatrix * vec4(position, 1.0));\n\t\t\t#endif\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\t\t#if USE_SKINNING\n\t\t\t\tvec3 worldPosition = (modelToWorldMatrix * vec4(position, 1.)).xyz;\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tworldPosition,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#else\n\t\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\t\tposition,\n\t\t\t\t\tnormal,\n\t\t\t\t\tworldNormal,\n\t\t\t\t\tmainLightDirection,\n\t\t\t\t\tshadowProjectionMatrix\n\t\t\t\t);\n\t\t\t\t#endif\n\t\t\t#endif\n\t\t\t\n\t\t\t" +
|
||||
Me.v5q("position") +
|
||||
"\n\t\t}\n\t"
|
||||
);
|
||||
@@ -19947,15 +19947,15 @@
|
||||
(this.c70_1.x70_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DYNAMIC_LIGHTS\n\t\tuniform sampler2D dynamicLightTexture;\n\t\t#endif\n\n\t\t#define ANIMATED " +
|
||||
(this.c70_1.a71_1 ? 1 : 0) +
|
||||
"\n\t\t#if ANIMATED\n\t\t// xy -- размер кадра анимации в uv-проÑтранÑтве\n\t\t// zw -- начало текущего кадра в uv-проÑтранÑтве\n\t\tuniform vec4 animatedPaintUVTransform;\n\t\t#endif\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
"\n\t\t#if ANIMATED\n\t\t// xy -- размер кадра анимации в uv-пространстве\n\t\t// zw -- начало текущего кадра в uv-пространстве\n\t\tuniform vec4 animatedPaintUVTransform;\n\t\t#endif\n\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.c70_1.z70_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat Get
Line truncated
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t#endif\n\t\n\t\tvec3 black = vec3(0);\n\t\tfloat deadDetailsAlpha = 0.2;\n\t\t\n\t\t#define USE_COLOR_TRANSFORM " +
|
||||
(this.c70_1.b71_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_COLOR_TRANSFORM\n\t\tuniform vec4 colorOffset;\n\t\tuniform vec4 colorMultiplier;\n\t\t#endif\n\t\t\n\t\t#define DEAD " +
|
||||
(this.c70_1.d71_1 ? 1 : 0) +
|
||||
"\n\n\t\t" +
|
||||
Me.w5q(this.c70_1.c71_1) +
|
||||
"\n\t\t\n\t\t\n\t\t\t#ifndef LAMBERT_LIGHT_INCLUDE\n\t\t\t#define LAMBERT_LIGHT_INCLUDE\n\t\t\t\n\t\t\tfloat CalculateLambertLight(vec3 normal, vec3 lightDir) {\n \t\t\treturn max(0.0, dot(normal, -lightDir)); \t\t\t\n\t\t\t}\t\n\t\t\t\n\t\t\tfloat CalculateSpecularLight(vec3 normal, vec3 h) {\n\t\t\t\tfloat spec = max( dot(normal, h) , 0.0);\n\t\t\t\treturn pow(spec, 5.0);\n\t\t\t}\n\t\t\t\n\t\t\tfloat CalculateSpecularLight(vec3 normal, vec3 cameraPos, vec3 lightDir, vec3 fragWorldPos, float specularPower) {\n\t\t\t\tvec3 viewDir = normalize(cameraPos - fragWorldPos);\n\t\t\t\tvec3 reflectDir = reflect(lightDir, normal);\n\t\t\t\tfloat spec = max(dot(viewDir, reflectDir), 0.0);\n\t\t\t\treturn pow(spec, specularPower);\n\t\t\t}\n\t\t\t\n\t\t\tfloat CalculateMetalShading(vec3 normal, vec3 cameraPos, vec3 fragWorldPos) {\n\t\t\t\tnormal = normalize(normal);\n\t\t\t\tvec3 viewDir = normalize(cameraPos - fragWorldPos);\n\t\t\t\treturn 1.0 - clamp(2.5 * dot(normal, viewDir), 0.0, 1.0);\n\t\t\t}\n\t\t\t\n\t\t\t#endif //LAMBERT_LIGHT_INCLUDE\n\t\t\n\t\t\n\t\tvec3 blend_hardlight(vec3 a, vec3 b) {\n\t\t\tvec3 k = step(vec3(0.5), b);\n\t\t\tvec3 col1 = 2.0 * a * b;\n\t\t\tvec3 col2 = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);\n\t\t\treturn mix(col1, col2, k);\n\t\t}\n\t\n\t\tvoid main(void) {\n\t\t\t#if ANIMATED\n\t\t\tvec2 paintUV = fract(v_uv_paint / animatedPaintUVTransform.xy) * animatedPaintUVTransform.xy + animatedPaintUVTransform.zw;\n\t\t\t#else\n\t\t\tvec2 paintUV = v_uv_paint;\n\t\t\t#endif\n\t\t\tvec4 paintColor = texture(paintTexture, paintUV);\n\t\t\tvec4 mainColor = texture(mainTexture, v_uv);\n\t\t\t\n\t\t\tvec4 color = vec4(blend_hardlight(paintColor.rgb, mainColor.rgb), alpha);\n\n\t\t\t#if DEAD\n\t\t\tfloat detailsAlpha = mainColor.a * deadDetailsAlpha;\n\t\t\t#else\n\t\t\tfloat detailsAlpha = mainColor.a;\n\t\t\t#endif\n\t\t\t\n\t\t\tcolor.rgb = mix(color.rgb, mainColor.rgb, detailsAlpha);\n\t\t\t\t\t\n\t\t\t#if USE_COLOR_TRANSFORM\n\t\t\tcolor = color * colorMultiplier + colorOffset;\n\t\t\t#endif\n\t\t\t\n\t\t\tvec3 light = ambientLightColor;\n\t\t\t\n\t\t\tvec3 mainLight = mainLightColor * v_illumination;\n\t\t\tvec3 directionalLight = mainLight;\n\t\t\t\n\t\t\t#if USE_SPECULAR\n\t\t\tvec3 cameraPosition = vec3(viewToWorldMatrix[3]);\n\t\t\tfloat specularIllumination = CalculateSpecularLight(\n\t\t\t\tnormalize(v_normal),\n\t\t\t\tcameraPosition,\n\t\t\t\tmainLightDirection,\n\t\t\t\tv_fragmentWorldPosition,\n\t\t\t\tspecularPower\n\t\t\t);\n\t\t\tfloat specularScale = texture(specularTexture, v_uv * 5.0).r;\n\t\t\t// МаÑка Ð·Ð°ÐºÑ€Ð°ÑˆÐ¸Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÐ¶Ðµ определÑÑ‚ наличие specular отражений.\n\t\t\t// Закрашенные облаÑти (detailsAlpha = 0) не отражают ÑовÑем, незакрашенные (detailsAlpha = 1)\n\t\t\t// отражают полноÑтью.\n\t\t\tvec3 specularLight = vec3(1.0) * specularIllumination * specularScale * detailsAlpha;\n\t\t\tdirectionalLight += specularLight;\n\t\t\t#endif // USE_SPECULAR\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tdirectionalLight *= shadowAttenuation;\n\t\t\t#endif\n\t\t\tlight += directionalLight;\n\t\t\t\n\t\t\t#if USE_DYNAMIC_LIGHTS\n\t\t\tvec2 lightmapUV = gl_FragCoord.xy / screenSize; \n\t\t\tvec3 dynamicLight = texture(dynamicLightTexture, lightmapUV).rgb;\n\t\t\tlight += dynamicLight;\n\t\t\t#endif\n\t\t\t\n\t\t\t#if DEAD\n\t\t\tvec3 emissionSource = color.rgb;\n\t\t\t#else \n\t\t\tvec3 emissionSource = mix(black, mainColor.rgb, mainColor.a);\t\t\t\t\n\t\t\t#endif\n\t\t\t\n\t\t\tvec3 emissionColorFactor = getEmissionColorFactor(emissionSource, light);\n\t\t\tcolor.rgb *= emissionColorFactor;\n\t\t\t\n\t\t\t" +
|
||||
"\n\t\t\n\t\t\n\t\t\t#ifndef LAMBERT_LIGHT_INCLUDE\n\t\t\t#define LAMBERT_LIGHT_INCLUDE\n\t\t\t\n\t\t\tfloat CalculateLambertLight(vec3 normal, vec3 lightDir) {\n \t\t\treturn max(0.0, dot(normal, -lightDir)); \t\t\t\n\t\t\t}\t\n\t\t\t\n\t\t\tfloat CalculateSpecularLight(vec3 normal, vec3 h) {\n\t\t\t\tfloat spec = max( dot(normal, h) , 0.0);\n\t\t\t\treturn pow(spec, 5.0);\n\t\t\t}\n\t\t\t\n\t\t\tfloat CalculateSpecularLight(vec3 normal, vec3 cameraPos, vec3 lightDir, vec3 fragWorldPos, float specularPower) {\n\t\t\t\tvec3 viewDir = normalize(cameraPos - fragWorldPos);\n\t\t\t\tvec3 reflectDir = reflect(lightDir, normal);\n\t\t\t\tfloat spec = max(dot(viewDir, reflectDir), 0.0);\n\t\t\t\treturn pow(spec, specularPower);\n\t\t\t}\n\t\t\t\n\t\t\tfloat CalculateMetalShading(vec3 normal, vec3 cameraPos, vec3 fragWorldPos) {\n\t\t\t\tnormal = normalize(normal);\n\t\t\t\tvec3 viewDir = normalize(cameraPos - fragWorldPos);\n\t\t\t\treturn 1.0 - clamp(2.5 * dot(normal, viewDir), 0.0, 1.0);\n\t\t\t}\n\t\t\t\n\t\t\t#endif //LAMBERT_LIGHT_INCLUDE\n\t\t\n\t\t\n\t\tvec3 blend_hardlight(vec3 a, vec3 b) {\n\t\t\tvec3 k = step(vec3(0.5), b);\n\t\t\tvec3 col1 = 2.0 * a * b;\n\t\t\tvec3 col2 = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);\n\t\t\treturn mix(col1, col2, k);\n\t\t}\n\t\n\t\tvoid main(void) {\n\t\t\t#if ANIMATED\n\t\t\tvec2 paintUV = fract(v_uv_paint / animatedPaintUVTransform.xy) * animatedPaintUVTransform.xy + animatedPaintUVTransform.zw;\n\t\t\t#else\n\t\t\tvec2 paintUV = v_uv_paint;\n\t\t\t#endif\n\t\t\tvec4 paintColor = texture(paintTexture, paintUV);\n\t\t\tvec4 mainColor = texture(mainTexture, v_uv);\n\t\t\t\n\t\t\tvec4 color = vec4(blend_hardlight(paintColor.rgb, mainColor.rgb), alpha);\n\n\t\t\t#if DEAD\n\t\t\tfloat detailsAlpha = mainColor.a * deadDetailsAlpha;\n\t\t\t#else\n\t\t\tfloat detailsAlpha = mainColor.a;\n\t\t\t#endif\n\t\t\t\n\t\t\tcolor.rgb = mix(color.rgb, mainColor.rgb, detailsAlpha);\n\t\t\t\t\t\n\t\t\t#if USE_COLOR_TRANSFORM\n\t\t\tcolor = color * colorMultiplier + colorOffset;\n\t\t\t#endif\n\t\t\t\n\t\t\tvec3 light = ambientLightColor;\n\t\t\t\n\t\t\tvec3 mainLight = mainLightColor * v_illumination;\n\t\t\tvec3 directionalLight = mainLight;\n\t\t\t\n\t\t\t#if USE_SPECULAR\n\t\t\tvec3 cameraPosition = vec3(viewToWorldMatrix[3]);\n\t\t\tfloat specularIllumination = CalculateSpecularLight(\n\t\t\t\tnormalize(v_normal),\n\t\t\t\tcameraPosition,\n\t\t\t\tmainLightDirection,\n\t\t\t\tv_fragmentWorldPosition,\n\t\t\t\tspecularPower\n\t\t\t);\n\t\t\tfloat specularScale = texture(specularTexture, v_uv * 5.0).r;\n\t\t\t// Маска закрашивания также определят наличие specular отражений.\n\t\t\t// Закрашенные области (detailsAlpha = 0) не отражают совсем, незакрашенные (detailsAlpha = 1)\n\t\t\t// отражают полностью.\n\t\t\tvec3 specularLight = vec3(1.0) * specularIllumination * specularScale * detailsAlpha;\n\t\t\tdirectionalLight += specularLight;\n\t\t\t#endif // USE_SPECULAR\n\t\t\t\n\t\t\t#if USE_SHADOW\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tdirectionalLight *= shadowAttenuation;\n\t\t\t#endif\n\t\t\tlight += directionalLight;\n\t\t\t\n\t\t\t#if USE_DYNAMIC_LIGHTS\n\t\t\tvec2 lightmapUV = gl_FragCoord.xy / screenSize; \n\t\t\tvec3 dynamicLight = texture(dynamicLightTexture, lightmapUV).rgb;\n\t\t\tlight += dynamicLight;\n\t\t\t#endif\n\t\t\t\n\t\t\t#if DEAD\n\t\t\tvec3 emissionSource = color.rgb;\n\t\t\t#else \n\t\t\tvec3 emissionSource = mix(black, mainColor.rgb, mainColor.a);\t\t\t\t\n\t\t\t#endif\n\t\t\t\n\t\t\tvec3 emissionColorFactor = getEmissionColorFactor(emissionSource, light);\n\t\t\tcolor.rgb *= emissionColorFactor;\n\t\t\t\n\t\t\t" +
|
||||
Me.x5q("color.rgb") +
|
||||
"\n\t\t\toutColor0 = color;\n\t\t}\n\t"
|
||||
);
|
||||
@@ -20053,7 +20053,7 @@
|
||||
return (
|
||||
"\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tuniform mat4 mvp;\n\t\tuniform mat3 normalToWorldMatrix;\n\n\t\tlayout(location=0)\n\t\tin vec3 position;\n\t\tlayout(location=1)\n\t\tin vec2 uv;\n\t\tlayout(location=3)\n\t\tin vec2 uv2;\n\t\tlayout(location=2)\n\t\tin vec3 normal;\n\n\t\tout vec2 v_uv;\n\t\tcentroid out vec2 v_uv2;\n\t\tout float v_illumination;\n\n\t\t#define USE_SHADOW " +
|
||||
(this.j72_1.c73_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобратьÑÑ, наÑколько Ñто адекватный код. КажетÑÑ Ñтранным, что мы менÑем координаты в\n\t\t\t// нормализованном проÑтранÑтве. Возможно, Ñто правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowMVP;\n\t\t#endif // USE_SHADOW\n\n\t\t" +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\tout vec3 v_shadowCoordinate;\n\t\n\t\t\n\t\tvec3 GetShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tfloat cosAlpha = max(dot(worldNormal, -lightDirection), 0.0);\n\t\t\tfloat normalBiasScale = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L·N))\n\t\t\tfloat slopeBiasScale = min(normalBiasScale / cosAlpha, 2.0); // tan(acos(L·N))\n\t\t\t\n\t\t\tfloat normalBias = ShadowMapNormalBias() * normalBiasScale;\n\t\t\tvec3 positionWithOffset = position + normal * normalBias;\n\t\t\tvec3 result = (vertexSpaceToShadowMatrix * vec4(positionWithOffset, 1.0)).xyz;\n\t\t\t// remap [-1, 1] => [0, 1].\n\t\t\tresult = (result + vec3(1.0)) * 0.5;\n\t\t\t// todo(fominykh): разобраться, насколько это адекватный код. Кажется странным, что мы меняем координаты в\n\t\t\t// нормализованном пространстве. Возможно, это правильно, но неочевидно пока.\n\t\t\tresult.z += ShadowMapSlopeBias() * slopeBiasScale;\n\t\t\tresult.z += ShadowMapViewBias();\n\t\t\treturn result;\n\t\t}\n\t\n\t\t\n\t\tvoid SetOutputShadowMapCoordinate(\n\t\t\tin vec3 position,\n\t\t\tin vec3 normal,\n\t\t\tin vec3 worldNormal,\n\t\t\tin vec3 lightDirection,\n\t\t\tin mat4 vertexSpaceToShadowMatrix\n\t\t) {\n\t\t\tv_shadowCoordinate = GetShadowMapCoordinate(position, normal, worldNormal, lightDirection, vertexSpaceToShadowMatrix);\n\t\t}\n\t\n\t\tuniform mat4 shadowMVP;\n\t\t#endif // USE_SHADOW\n\n\t\t" +
|
||||
Me.u5q(this.j72_1.e73_1) +
|
||||
"\n\n\t\tvoid main(void) {\n\t\t\tv_uv = uv;\n\t\t\tv_uv2 = uv2;\n\t\t\tgl_Position = mvp * vec4(position, 1.0);\n\n\t\t\tvec3 worldNormal = normalize(normalToWorldMatrix * normal);\n\t\t\tv_illumination = max(dot(worldNormal, -mainLightDirection), 0.);\n\n\t\t\t#if USE_SHADOW\n\t\t\tSetOutputShadowMapCoordinate(\n\t\t\t\tposition,\n\t\t\t\tnormal,\n\t\t\t\tworldNormal,\n\t\t\t\tmainLightDirection,\n\t\t\t\tshadowMVP\n\t\t\t);\n\t\t\t#endif // USE_SHADOW\n\n\t\t\t" +
|
||||
Me.v5q("position") +
|
||||
@@ -20064,11 +20064,11 @@
|
||||
return (
|
||||
"\n\t\t\n\t\t#ifndef LIGHTING_UNIFORM_BLOCK\n\t\t#define LIGHTING_UNIFORM_BLOCK\n\t\tlayout(std140) uniform LightingBlock {\n\t\t\tvec3 ambientLightColor;\n\t\t\tvec3 mainLightColor;\n\t\t\tvec3 mainLightDirection;\n\t\t};\n\t\t#endif\n\t\n\t\tuniform sampler2D controlTexture;\n\t\tuniform sampler2D splatTexture[4];\n\t\tuniform vec4 splatUVTransform[4];\n\t\tuniform float heightBlending;\n\t\tuniform sampler2D lightmapTexture;\n\t\t\n\t\tin vec2 v_uv;\n\t\tcentroid in vec2 v_uv2;\n\t\tin float v_illumination;\n\t\t\t\n\t\t#define USE_SHADOW " +
|
||||
(this.j72_1.c73_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // ТекÑтура квадратнаÑ.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// ИÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ€Ñ‚Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой карты теней.\n\t\t// Возвращает 0, еÑли фрагмент в тени и 1, еÑли нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// ИÑпользуютÑÑ ÑˆÐµÑть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коÑффициент ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑвещённоÑти из-за тени в диапазоне [0, 1] Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ по дальноÑти.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на раÑÑтоÑнии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat Get
Line truncated
|
||||
"\n\t\t#if USE_SHADOW\n\t\t\n\t\t\n\t\t\n\t\tlayout(std140) uniform ShadowParams {\n\t\t\t// x -- depth bias, y -- normal bias, z -- slope bias, w -- view bias\n\t\t\tvec4 shadowMapBias;\n\t\t\t// x -- strength, y -- full distance, z -- fade distance, w -- blur size\n\t\t\tvec4 shadowParams;\n\t\t};\n\t\t\n\t\tfloat ShadowMapDepthBias() {\n\t\t\treturn shadowMapBias.x;\n\t\t}\n\t\t\n\t\tfloat ShadowMapNormalBias() {\n\t\t\treturn max(shadowMapBias.y, 0.0001);\n\t\t}\n\t\t\n\t\tfloat ShadowMapSlopeBias() {\n\t\t\treturn shadowMapBias.z;\n\t\t}\n\t\t\n\t\tfloat ShadowMapViewBias() {\n\t\t\treturn shadowMapBias.w;\n\t\t}\n\t\t\n\t\tfloat GetShadowStrength() {\n\t\t\treturn shadowParams.x;\n\t\t}\n\t\t\n\t\tfloat GetShadowFullDistance() {\n\t\t\treturn shadowParams.y;\n\t\t}\n\t\t\n\t\tfloat GetShadowFadeDistance() {\n\t\t\treturn shadowParams.z;\n\t\t}\n\t\t\n\t\tfloat GetBlurSize() {\n\t\t\treturn shadowParams.w;\n\t\t}\n\t\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\t\n\t\tuniform highp sampler2D shadowTexture;\n\t\tuniform sampler2D shadowBlurTexture;\n\t\t\n\t\tfloat GetBlurPixelSize() {\n\t\t // Текстура квадратная.\n\t\t\tfloat shadowTextureSize = float(textureSize(shadowTexture, 0).x);\n\t\t\treturn 1.0 / shadowTextureSize;\n\t\t}\n\t\n\t\t// Используется для ортографической карты теней.\n\t\t// Возвращает 0, если фрагмент в тени и 1, если нет.\n\t\tfloat SampleShadowMap(in vec3 fragShadowCoord) {\n\t\t\tfloat biasedFragmentDepth = fragShadowCoord.z - ShadowMapDepthBias();\n\t\t\tfloat shadowMapDepth = texture(shadowTexture, fragShadowCoord.xy).r;\n\t\t\treturn step(biasedFragmentDepth, shadowMapDepth);\n\t\t}\n\t\t\n\t\tfloat SampleShadowByBlurTexture(vec3 fragShadowCoord) {\n\t\t\t// Используются шесть точек\n\t\t\t#define COS60 0.5\n\t\t\t#define SIN60 0.866025\n\t\t\tmat2 rot = mat2(COS60, -SIN60, SIN60, COS60);\n\t\t\tvec2 blurTextureSize = vec2(textureSize(shadowBlurTexture, 0));\n\t\t\tvec2 blurUV = mod(gl_FragCoord.xy, blurTextureSize) / blurTextureSize;\n\t\t\tvec3 blurParams = texture(shadowBlurTexture, blurUV).xyz;\n\t\t\tfloat r = GetBlurSize() * GetBlurPixelSize() * blurParams.r;\n\t\t\tfloat c = (blurParams.g - 0.5) * 2.0;\n\t\t\tfloat s = (blurParams.b - 0.5) * 2.0;\n\t\t\tvec2 p = vec2(c, s) * r;\n\t\t\tfloat sum = 0.0;\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tsum += SampleShadowMap(fragShadowCoord + vec3(p, 0.0));\n\t\t\t\tp = rot * p;\n\t\t\t}\n\t\t\tfloat result = sum / 6.0;\n\t\t\treturn clamp(result, 0.0, 1.0);\n\t\t}\n\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1].\n\t\tfloat GetShadow(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = SampleShadowByBlurTexture(shadowCoordinate.xyz);\n\t\t\treturn mix(1.0, shadowAttenuation, GetShadowStrength());\n\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t// Возвращает коэффициент снижения освещённости из-за тени в диапазоне [0, 1] с ограничением по дальности.\n\t\tfloat GetShadowAttenuation(in vec3 shadowCoordinate) {\n\t\t\tfloat shadowAttenuation = GetShadow(shadowCoordinate);\n\t\t\t// Линейное затухание на расстоянии\n\t\t\tfloat fragmentDistance = GetSceneDepth(gl_FragCoord.z);\n\t\t\tfloat shadowFullDistance = GetShadowFullDistance();\n\t\t\tfloat shadowFadeDistance = GetShadowFadeDistance();\n\t\t\tfloat maxDistance = shadowFullDistance + shadowFadeDistance;\n\t\t\tfloat clampedFragmentDistance = clamp(fragmentDistance, shadowFullDistance, maxDistance);\n\t\t\tfloat t = (clampedFragmentDistance - shadowFullDistance) / shadowFadeDistance;\n\t\t\treturn mix(shadowAttenuation, 1.0, t);\n\t\t}\n\t\n\t\t\n\t\tin vec3 v_shadowCoordinate;\n\t\t\n\t\tfloat GetShadowAttenuation() {\n\t\t\treturn GetShadowAttenuation(v_shadowCoordinate);\n\t\t}\n\t\n\t\t#endif // USE_SHADOW\n\t\n\t\t#define USE_DYNAMIC_LIGHT " +
|
||||
(this.j72_1.d73_1 ? 1 : 0) +
|
||||
"\n\t\t#if USE_DYNAMIC_LIGHT\n\t\t\n\t\t\t#ifndef CAMERA_PARAMS_BLOCK\n\t\t\t#define CAMERA_PARAMS_BLOCK\n\t\t\t\n\t\tlayout(std140) uniform CameraParams {\n\t\t\tmat4 viewMatrix;\n\t\t\tmat4 projectionMatrix;\n\t\t\tmat4 viewProjectionMatrix;\n\t\t\tmat4 viewToWorldMatrix;\n\t\t\tvec4 sceneDepthParams;\n\t\t\tvec2 screenSize;\n\t\t};\n\t\n\t\t\t\n\t\t\tfloat GetSceneDepth(float zBufferDepth) {\t\t\n\t\t\t\treturn 1.0 / (sceneDepthParams.z * zBufferDepth + sceneDepthParams.w);\n\t\t\t}\n\t\t\t#endif\n\t\t\n\t\tuniform sampler2D dynamicLightTexture;\n\t\t#endif\n\n\t\t" +
|
||||
Me.w5q(this.j72_1.e73_1) +
|
||||
"\t\n\t\t\n\t\tvec3 blend_by_height(vec3 input1, vec3 input2, vec3 input3, vec3 input4, vec4 height) {\n float height_start = max(max(height.x, height.y), max(height.z, height.w)) - heightBlending;\n height_start = clamp(height_start, 0.0, 1.0);\n vec4 b = max(height - vec4(height_start), vec4(0.0));\n return ((input1 * b.x) + (input2 * b.y) + (input3 * b.z) + (input4 * b.w)) / (dot(b, vec4(1.0)));\n }\n\t\t\n\t\tvec2 transform_uv(vec2 uv, vec4 t) {\n\t\t\treturn uv * t.xy + t.zw;\n\t\t}\n\t\t\n\t\tvoid main() {\n\t\t\tvec2 uv[4];\n\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\tuv[i] = transform_uv(v_uv, splatUVTransform[i]);\n\t\t\t}\n\t\t\t// Ð’ WebGL маÑÑив ÑÑмплеров индекÑируетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ конÑтантами, поÑтому здеÑÑŒ без цикла.\n\t\t\tvec4 splat0 = texture(splatTexture[0], uv[0]);\n\t\t\tvec4 splat1 = texture(splatTexture[1], uv[1]);\n\t\t\tvec4 splat2 = texture(splatTexture[2], uv[2]);\n\t\t\tvec4 splat3 = texture(splatTexture[3], uv[3]);\n\t\t\tvec4 control = texture(controlTexture, v_uv);\n\t\t\t\n\t\t\tvec4 height = vec4(splat0.a, splat1.a, splat2.a, splat3.a);\n\t\t\theight = max(vec4(0.01), height) * control; \n\t\t\t\n\t\t\tvec4 color = vec4(0, 0, 0, 1);\n\t\t\tcolor.rgb = blend_by_height(splat0.rgb, splat1.rgb, splat2.rgb, splat3.rgb, height);\n\t\t\t\n\t\t\tvec3 light = ambientLightColor;\n\t\t\t\n\t\t\tvec3 mainLight = mainLightColor * v_illumination;\n\t\t\t#if USE_SHADOW\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tmainLight *= shadowAttenuation;\n\t\t\t#endif\n\t\t\t\n\t\t\tlight += mainLight;\n\t\t\t\n\t\t\t// Множитель 2 из-за алгоритма ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð»Ð°Ð¹Ñ‚Ð¼Ð°Ð¿Ñ‹, который позволÑет затенение и выÑветление.\n\t\t\tvec3 staticLight = 2.0 * texture(lightmapTexture, v_uv2).rgb;\n\t\t\t// Множитель 2 перед light из-за текущей Ñхемы оÑÐ²ÐµÑ‰ÐµÐ½Ð¸Ñ Ñ Ð»Ð°Ð¹Ñ‚Ð¼Ð°Ð¿Ð¾Ð¹.\n\t\t\tlight = min(2.0 * light, staticLight);\n\t\t\t\n\t\t\t#if USE_DYNAMIC_LIGHT\n\t\t\tvec2 lightmapUV = gl_FragCoord.xy / screenSize; \n\t\t\tvec3 dynamicLight = texture(dynamicLightTexture, lightmapUV).rgb;\n\t\t\tlight += dynamicLight;\n\t\t\t#endif\n\t\t\t\n\t\t\tcolor.rgb *= light;\n\t\t\t" +
|
||||
"\t\n\t\t\n\t\tvec3 blend_by_height(vec3 input1, vec3 input2, vec3 input3, vec3 input4, vec4 height) {\n float height_start = max(max(height.x, height.y), max(height.z, height.w)) - heightBlending;\n height_start = clamp(height_start, 0.0, 1.0);\n vec4 b = max(height - vec4(height_start), vec4(0.0));\n return ((input1 * b.x) + (input2 * b.y) + (input3 * b.z) + (input4 * b.w)) / (dot(b, vec4(1.0)));\n }\n\t\t\n\t\tvec2 transform_uv(vec2 uv, vec4 t) {\n\t\t\treturn uv * t.xy + t.zw;\n\t\t}\n\t\t\n\t\tvoid main() {\n\t\t\tvec2 uv[4];\n\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\tuv[i] = transform_uv(v_uv, splatUVTransform[i]);\n\t\t\t}\n\t\t\t// В WebGL массив сэмплеров индексируется только константами, поэтому здесь без цикла.\n\t\t\tvec4 splat0 = texture(splatTexture[0], uv[0]);\n\t\t\tvec4 splat1 = texture(splatTexture[1], uv[1]);\n\t\t\tvec4 splat2 = texture(splatTexture[2], uv[2]);\n\t\t\tvec4 splat3 = texture(splatTexture[3], uv[3]);\n\t\t\tvec4 control = texture(controlTexture, v_uv);\n\t\t\t\n\t\t\tvec4 height = vec4(splat0.a, splat1.a, splat2.a, splat3.a);\n\t\t\theight = max(vec4(0.01), height) * control; \n\t\t\t\n\t\t\tvec4 color = vec4(0, 0, 0, 1);\n\t\t\tcolor.rgb = blend_by_height(splat0.rgb, splat1.rgb, splat2.rgb, splat3.rgb, height);\n\t\t\t\n\t\t\tvec3 light = ambientLightColor;\n\t\t\t\n\t\t\tvec3 mainLight = mainLightColor * v_illumination;\n\t\t\t#if USE_SHADOW\n\t\t\tfloat shadowAttenuation = GetShadowAttenuation();\n\t\t\tmainLight *= shadowAttenuation;\n\t\t\t#endif\n\t\t\t\n\t\t\tlight += mainLight;\n\t\t\t\n\t\t\t// Множитель 2 из-за алгоритма создания лайтмапы, который позволяет затенение и высветление.\n\t\t\tvec3 staticLight = 2.0 * texture(lightmapTexture, v_uv2).rgb;\n\t\t\t// Множитель 2 перед light из-за текущей схемы освещения с лайтмапой.\n\t\t\tlight = min(2.0 * light, staticLight);\n\t\t\t\n\t\t\t#if USE_DYNAMIC_LIGHT\n\t\t\tvec2 lightmapUV = gl_FragCoord.xy / screenSize; \n\t\t\tvec3 dynamicLight = texture(dynamicLightTexture, lightmapUV).rgb;\n\t\t\tlight += dynamicLight;\n\t\t\t#endif\n\t\t\t\n\t\t\tcolor.rgb *= light;\n\t\t\t" +
|
||||
Me.x5q("color.rgb") +
|
||||
"\n\t\t\t\n\t\t\toutColor0 = color;\n\t\t}\n\t"
|
||||
);
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"type":"webpack-resource-map","generatedAt":"2026-09-16T03:01:34.814Z","totalResources":1218,"resourceMap":{"17":"static/images/31.2d481c05.webp","146":"static/images/neutral-g.38b68a23.svg","164":"static/images/gold.e0b82d44.svg","214":"static/images/btnBarrelUp.300e56c4.svg","349":"static/images/armor.d6fc6ef4.svg","405":"static/images/08.6a9e421e.webp","410":"static/images/speedIcon.3aaad0d9.svg","430":"static/images/18.0fcfcee7.webp","465":"static/images/stabilized_lightning.5b5469d1.svg","894":"static/images/05.4baa68b2.webp","899":"static/images/13.0ad436cb.webp","906":"static/images/Gauss.da869a90.svg","909":"static/images/contract.90d7cd8f.svg","911":"static/images/neutral-b.678833d3.svg","964":"static/images/unavailable.5c3ecd75.svg","1039":"static/images/armor.960e021b.svg","1042":"static/images/freeze_resistance.33bdf642.svg","1067":"static/images/battle_main_pick_match.f9aabe76.webp","1076":"static/images/bgSecondaryButton.d770f6f8.svg","1127":"static/images/overdrive.c8de54da.svg","1153":"static/images/overheat.89c0e772.svg","1196":"static/images/ctf_blue_base_no_flag.94a2bf33.svg","1254":"static/images/Smoky.a2623c59.svg","1257":"static/images/rgb_blue_delivering.6c8a284b.svg","1311":"static/images/lock.301e2c47.svg","1461":"static/images/claimAllButton.b9e9611f.webp","1498":"static/images/revolver.3f7f2a0e.svg","1502":"static/images/25.60b5ac7d.webp","1507":"static/images/22.39ef9ff5.webp","1552":"static/images/bgActionButton.b5ff3b72.svg","1580":"static/images/09.bc6e748e.webp","1647":"static/images/high_caliber_ammo.7d27e891.svg","1832":"static/images/vivern_shells.d1dda9d2.svg","1900":"static/images/RU.09428d33.webp","1911":"static/images/Add-friend.137d3601.svg","1988":"static/images/iconLobbyMenuGarage.0b623165.svg","2044":"static/images/booster_damage.c3e7e6b3.svg","2144":"static/images/tsunami_resistance.6200aad9.svg","2209":"static/images/self-destruction-stripe.cacb47e5.webp","2261":"static/images/tank-above.ac5b8ccc.svg","2277":"static/images/iconActiveProgressBar.ef307714.svg","2298":"static/images/emp.65915d57.svg","2328":"static/images/Scorpion.17f0ca64.svg","2387":"static/images/31.d51e86c9.webp","2417":"static/images/twitch.d986fa35.webp","2462":"static/images/red-c.0da087f5.svg","2538":"static/images/03.46e2680b.webp","2621":"static/images/battle_main_pick_pro_battles.015a9f72.webp","2826":"static/images/dejavu-sans-mono-16px-basis33-15px.bb61e2ba.png","2858":"static/images/experience.402435da.svg","3289":"static/images/blue-indicator.1208edf8.svg","3358":"static/images/btnSettings.abd80236.svg","3360":"static/images/09.390d5c71.webp","3370":"static/images/09.2e8435ba.webp","3439":"static/images/indicator-blue.23ed1adc.svg","3447":"static/images/firebird_magnetic.422b1b1c.svg","3581":"static/images/manual_mode.246743df.svg","3596":"static/images/alert.d58f4b55.svg","3611":"static/images/iconEpicFiolet.d91b1151.svg","3642":"static/images/logoTankiOnlineChina.0b6ba850.svg","3682":"static/images/jgr_red.8e25466e.svg","3905":"static/images/26.f1020f51.webp","3933":"static/images/shopIcon.c02c69df.svg","3953":"static/images/transitionToWindowScreenShotTanks.f3eeaa44.svg","4011":"static/images/externalLink.e7a8bb5a.svg","4081":"static/images/02.faa1f4fb.webp","4112":"static/images/policy_link.692055b6.svg","4238":"static/images/TwinsPlasmaInjector.53f9cfc2.svg","4348":"static/images/Viking.45549e00.svg","4432":"static/images/reset.b088bab6.svg","4549":"static/images/pierce.b182be03.svg","4958":"static/images/14.038e31ee.webp","4959":"static/images/magnum_lafet.ffcd092b.svg","5012":"static/images/Ultimate.94f7d547.svg","5067":"static/images/chatDirectArrow.d2462f04.svg","5072":"static/images/closedEye.81774df3.svg","5159":"static/images/24.d891a26c.webp","5370":"static/videos/rare.b7ef6294.webm","5640":"static/images/Hopper.17d5fd98.svg","5680":"static/images/overheat.c5da6580.svg","5912":"static/images/booster_armor.3dfb0e1e.svg","6153":"static/images/arrowRightMenuIconActive.f061716d.svg","6230":"static/images/hulls.b316ae80.svg","6458":"static/images/petalUp.688b620f.svg","6497":"static/images/hull_freezing_protection.1e959682.svg","6501":"static/images/15.981b89e8.webp","6506":"static/images/03.67da784b.webp","6511":"static/images/Reset.d3c792f7.svg","6693":"static/images/protectionSlotEquip.5f03fffe.svg","6715":"static/images/ic_unmount.01e4da15.svg","6784":"static/images/google.9550d60e.svg","6830":"static/images/ic_standard.9d75638b.svg","6898":"static/images/Clan_image.545f6980.webp","6937":"static/images/jgr_blue.c3fe3a20.svg","6942":"static/translations/cs.2078c440.json","6979":"static/images/nitro_hd.c9ef057e.webp","7070":"static/images/plasma_torch.b06f598e.svg","7110":"static/images/PT_BR.12471229.webp","7112":"static/images/arrow-gray.75f5f8a5.svg","7156":"static/images/battleChatToggleTeamSpectators.2cb18c57.svg","7161":"static/images/supplyRepair.2bd316e0.svg","7438":"static/images/Freeze.51cbde00.svg","7446":"static/images/hull_freezing_immunity.d1dda9d2.svg","7522Line truncated
|
||||
{"type":"webpack-resource-map","generatedAt":"2026-10-09T05:59:46.467Z","totalResources":1219,"resourceMap":{"17":"static/images/31.2d481c05.webp","146":"static/images/neutral-g.38b68a23.svg","164":"static/images/gold.e0b82d44.svg","214":"static/images/btnBarrelUp.300e56c4.svg","349":"static/images/armor.d6fc6ef4.svg","405":"static/images/08.6a9e421e.webp","410":"static/images/speedIcon.3aaad0d9.svg","430":"static/images/18.0fcfcee7.webp","465":"static/images/stabilized_lightning.5b5469d1.svg","894":"static/images/05.4baa68b2.webp","899":"static/images/13.0ad436cb.webp","906":"static/images/Gauss.da869a90.svg","909":"static/images/contract.90d7cd8f.svg","911":"static/images/neutral-b.678833d3.svg","964":"static/images/unavailable.5c3ecd75.svg","1039":"static/images/armor.960e021b.svg","1042":"static/images/freeze_resistance.33bdf642.svg","1067":"static/images/battle_main_pick_match.f9aabe76.webp","1076":"static/images/bgSecondaryButton.d770f6f8.svg","1127":"static/images/overdrive.c8de54da.svg","1153":"static/images/overheat.89c0e772.svg","1196":"static/images/ctf_blue_base_no_flag.94a2bf33.svg","1254":"static/images/Smoky.a2623c59.svg","1257":"static/images/rgb_blue_delivering.6c8a284b.svg","1311":"static/images/lock.301e2c47.svg","1461":"static/images/claimAllButton.b9e9611f.webp","1498":"static/images/revolver.3f7f2a0e.svg","1502":"static/images/25.60b5ac7d.webp","1507":"static/images/22.39ef9ff5.webp","1552":"static/images/bgActionButton.b5ff3b72.svg","1580":"static/images/09.bc6e748e.webp","1647":"static/images/high_caliber_ammo.7d27e891.svg","1832":"static/images/vivern_shells.d1dda9d2.svg","1900":"static/images/RU.09428d33.webp","1911":"static/images/Add-friend.137d3601.svg","1988":"static/images/iconLobbyMenuGarage.0b623165.svg","2044":"static/images/booster_damage.c3e7e6b3.svg","2144":"static/images/tsunami_resistance.6200aad9.svg","2209":"static/images/self-destruction-stripe.cacb47e5.webp","2261":"static/images/tank-above.ac5b8ccc.svg","2277":"static/images/iconActiveProgressBar.ef307714.svg","2298":"static/images/emp.65915d57.svg","2328":"static/images/Scorpion.17f0ca64.svg","2387":"static/images/31.d51e86c9.webp","2417":"static/images/twitch.d986fa35.webp","2462":"static/images/red-c.0da087f5.svg","2538":"static/images/03.46e2680b.webp","2621":"static/images/battle_main_pick_pro_battles.015a9f72.webp","2826":"static/images/dejavu-sans-mono-16px-basis33-15px.bb61e2ba.png","2858":"static/images/experience.402435da.svg","3289":"static/images/blue-indicator.1208edf8.svg","3358":"static/images/btnSettings.abd80236.svg","3360":"static/images/09.390d5c71.webp","3370":"static/images/09.2e8435ba.webp","3439":"static/images/indicator-blue.23ed1adc.svg","3447":"static/images/firebird_magnetic.422b1b1c.svg","3581":"static/images/manual_mode.246743df.svg","3596":"static/images/alert.d58f4b55.svg","3611":"static/images/iconEpicFiolet.d91b1151.svg","3642":"static/images/logoTankiOnlineChina.0b6ba850.svg","3682":"static/images/jgr_red.8e25466e.svg","3905":"static/images/26.f1020f51.webp","3933":"static/images/shopIcon.c02c69df.svg","3953":"static/images/transitionToWindowScreenShotTanks.f3eeaa44.svg","4011":"static/images/externalLink.e7a8bb5a.svg","4081":"static/images/02.faa1f4fb.webp","4112":"static/images/policy_link.692055b6.svg","4238":"static/images/TwinsPlasmaInjector.53f9cfc2.svg","4348":"static/images/Viking.45549e00.svg","4432":"static/images/reset.b088bab6.svg","4549":"static/images/pierce.b182be03.svg","4958":"static/images/14.038e31ee.webp","4959":"static/images/magnum_lafet.ffcd092b.svg","5012":"static/images/Ultimate.94f7d547.svg","5067":"static/images/chatDirectArrow.d2462f04.svg","5072":"static/images/closedEye.81774df3.svg","5159":"static/images/24.d891a26c.webp","5370":"static/videos/rare.b7ef6294.webm","5640":"static/images/Hopper.17d5fd98.svg","5680":"static/images/overheat.c5da6580.svg","5912":"static/images/booster_armor.3dfb0e1e.svg","6153":"static/images/arrowRightMenuIconActive.f061716d.svg","6230":"static/images/hulls.b316ae80.svg","6458":"static/images/petalUp.688b620f.svg","6497":"static/images/hull_freezing_protection.1e959682.svg","6501":"static/images/15.981b89e8.webp","6506":"static/images/03.67da784b.webp","6511":"static/images/Reset.d3c792f7.svg","6693":"static/images/protectionSlotEquip.5f03fffe.svg","6715":"static/images/ic_unmount.01e4da15.svg","6784":"static/images/google.9550d60e.svg","6830":"static/images/ic_standard.9d75638b.svg","6898":"static/images/Clan_image.545f6980.webp","6937":"static/images/jgr_blue.c3fe3a20.svg","6942":"static/translations/cs.0041f7b7.json","6979":"static/images/nitro_hd.c9ef057e.webp","7070":"static/images/plasma_torch.b06f598e.svg","7110":"static/images/PT_BR.12471229.webp","7112":"static/images/arrow-gray.75f5f8a5.svg","7156":"static/images/battleChatToggleTeamSpectators.2cb18c57.svg","7161":"static/images/supplyRepair.2bd316e0.svg","7438":"static/images/Freeze.51cbde00.svg","7446":"static/images/hull_freezing_immunity.d1dda9d2.svg","7522Line truncated
|
||||
+1051
-303
File diff suppressed because it is too large.
Load diff
+2
-1
@@ -23,7 +23,8 @@ FILES = [
|
||||
"hornet_aim_warning.js", # 6. 瞄准警告模块 -> __hornetTools__.AimWarning
|
||||
"hornet_freelook.js", # 7. 自由视角模块 -> __hornetTools__.FreeLook
|
||||
"hornet_warsandbox.js", # 8. 战争沙盘模块 -> __hornetTools__.WarSandbox
|
||||
"hornet_panel.js", # 9. 控制面板(Alt+T + HUD)
|
||||
"hornet_mouse.js", # 9. 鼠标输入稳定器 -> __hornetTools__.Mouse
|
||||
"hornet_panel.js", # 10. 控制面板(Alt+T + HUD)
|
||||
]
|
||||
|
||||
HEADER = """// ============================================================
|
||||
|
||||
+447
-261
@@ -10,12 +10,7 @@
|
||||
function _start() {
|
||||
console.log('===== 3DTank3D透视启动 =====');
|
||||
|
||||
if (!window.__gameMode__) {
|
||||
console.error('请先运行 hook_gamemode.js');
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== 清理旧透视 =====
|
||||
// 允许在未进入战局 / ght 尚未捕获时启动:先出叠加层与状态行,模型等进入战局再出
|
||||
if (window.__hornet3DWireframe__) {
|
||||
window.__hornet3DWireframe__.stop();
|
||||
console.log('已停止旧透视');
|
||||
@@ -25,7 +20,7 @@
|
||||
console.log('已停止旧描边透视');
|
||||
}
|
||||
|
||||
var gm = window.__gameMode__;
|
||||
var gm = window.__gameMode__ || null;
|
||||
|
||||
// ===== 当前模式 =====
|
||||
var Mode = 'outline'; // 'wireframe' | 'outline'
|
||||
@@ -97,27 +92,95 @@
|
||||
var GetTankState = lib.GetTankState;
|
||||
var IsTankAlive = lib.IsTankAlive;
|
||||
var GetTankName = lib.GetTankName;
|
||||
var GetTankHealth = lib.GetTankHealth;
|
||||
function GetPlayerTank() { return lib.GetPlayerTank(gm); }
|
||||
function IsFriendly(tank, playerTank) { return lib.IsFriendly(tank, playerTank, gm); }
|
||||
function GetCameraInfo() {
|
||||
// 自由视角激活时,用虚拟相机参数(位置/方向跟随鼠标)
|
||||
var fl = window.__hornetFreeLook__;
|
||||
if (fl && typeof fl.IsActive === 'function' && fl.IsActive()) {
|
||||
var pos = fl.GetPosition();
|
||||
var dir = fl.GetDirection();
|
||||
if (pos && dir) {
|
||||
return { pos: pos, yaw: dir.yaw, pitch: dir.pitch, fov: 1.0471976 };
|
||||
}
|
||||
}
|
||||
return lib.GetCameraInfo(gm);
|
||||
function GetCameraInfo() {
|
||||
// 自由视角激活时,用虚拟相机参数(位置/方向跟随鼠标)
|
||||
var fl = window.__hornetFreeLook__;
|
||||
if (fl && typeof fl.IsActive === 'function' && fl.IsActive()) {
|
||||
var pos = fl.GetPosition();
|
||||
var dir = fl.GetDirection();
|
||||
if (pos && dir) {
|
||||
return { pos: pos, yaw: dir.yaw, pitch: dir.pitch, fov: 1.0471976 };
|
||||
}
|
||||
}
|
||||
return lib.GetCameraInfo(gm);
|
||||
}
|
||||
var Project3D = lib.Project3D;
|
||||
var TransformVertex = lib.TransformVertex;
|
||||
|
||||
// ===== 热点优化:相机基每帧只算一次(避免逐顶点重复三角函数 + 对象分配)=====
|
||||
var Cam = {
|
||||
fx: 0, fy: 0, fz: 0, rx: 0, ry: 0, rz: 0, ux: 0, uy: 0, uz: 0,
|
||||
focal: 1, halfW: 0, halfH: 0, px: 0, py: 0, pz: 0
|
||||
};
|
||||
function UpdateCam(camInfo, screenW, screenH) {
|
||||
var cp = Math.cos(camInfo.pitch), sp = Math.sin(camInfo.pitch);
|
||||
var cy = Math.cos(camInfo.yaw), sy = Math.sin(camInfo.yaw);
|
||||
Cam.fx = cp * (-sy); Cam.fy = cp * cy; Cam.fz = sp; // forward
|
||||
Cam.rx = cy; Cam.ry = sy; Cam.rz = 0; // right
|
||||
Cam.ux = Cam.ry * Cam.fz - Cam.rz * Cam.fy; // up = right × forward
|
||||
Cam.uy = Cam.rz * Cam.fx - Cam.rx * Cam.fz;
|
||||
Cam.uz = Cam.rx * Cam.fy - Cam.ry * Cam.fx;
|
||||
Cam.focal = screenH / (2 * Math.tan(camInfo.fov / 2));
|
||||
Cam.halfW = screenW / 2; Cam.halfH = screenH / 2;
|
||||
Cam.px = camInfo.pos.x; Cam.py = camInfo.pos.y; Cam.pz = camInfo.pos.z;
|
||||
}
|
||||
|
||||
// 顶点缓冲(全局复用,杜绝每帧每顶点对象分配)
|
||||
var VB_Wx = null, VB_Wy = null, VB_Wz = null; // 世界坐标(法线用)
|
||||
var VB_Sx = null, VB_Sy = null, VB_Ok = null; // 屏幕坐标 + 可投影标志
|
||||
function EnsureVerts(n) {
|
||||
if (!VB_Wx || VB_Wx.length < n) {
|
||||
var cap = Math.max(n, 2048);
|
||||
VB_Wx = new Float32Array(cap); VB_Wy = new Float32Array(cap); VB_Wz = new Float32Array(cap);
|
||||
VB_Sx = new Float32Array(cap); VB_Sy = new Float32Array(cap);
|
||||
VB_Ok = new Uint8Array(cap);
|
||||
}
|
||||
}
|
||||
|
||||
// 变换 + 投影一个 mesh 节点的全部顶点到复用缓冲,返回顶点数
|
||||
function PrepareNodeVerts(meshData, worldMatrix, pos) {
|
||||
var positions = meshData.positions;
|
||||
var stride = meshData.stride || 3;
|
||||
var vc = Math.floor(positions.length / stride);
|
||||
EnsureVerts(vc);
|
||||
var m0 = worldMatrix[0], m1 = worldMatrix[1], m2 = worldMatrix[2],
|
||||
m4 = worldMatrix[4], m5 = worldMatrix[5], m6 = worldMatrix[6],
|
||||
m8 = worldMatrix[8], m9 = worldMatrix[9], m10 = worldMatrix[10],
|
||||
m12 = worldMatrix[12], m13 = worldMatrix[13], m14 = worldMatrix[14];
|
||||
var px = pos.x, py = pos.y, pz = pos.z;
|
||||
var cfx = Cam.fx, cfy = Cam.fy, cfz = Cam.fz;
|
||||
var crx = Cam.rx, cry = Cam.ry, crz = Cam.rz;
|
||||
var cux = Cam.ux, cuy = Cam.uy, cuz = Cam.uz;
|
||||
var focal = Cam.focal, halfW = Cam.halfW, halfH = Cam.halfH;
|
||||
var cpx = Cam.px, cpy = Cam.py, cpz = Cam.pz;
|
||||
for (var v = 0; v < vc; v++) {
|
||||
var bx = positions[v * stride], by = positions[v * stride + 1], bz = positions[v * stride + 2];
|
||||
var wx = m0 * bx + m4 * by + m8 * bz + m12;
|
||||
var wy = m1 * bx + m5 * by + m9 * bz + m13;
|
||||
var wz = m2 * bx + m6 * by + m10 * bz + m14;
|
||||
VB_Wx[v] = wx; VB_Wy[v] = wy; VB_Wz[v] = wz;
|
||||
var ddx = wx - px, ddy = wy - py, ddz = wz - pz;
|
||||
if (ddx * ddx + ddy * ddy + ddz * ddz > 6250000) { VB_Ok[v] = 0; continue; }
|
||||
var relX = wx - cpx, relY = wy - cpy, relZ = wz - cpz;
|
||||
var camZ = relX * cfx + relY * cfy + relZ * cfz;
|
||||
if (camZ <= 0.1) { VB_Ok[v] = 0; continue; }
|
||||
var camX = relX * crx + relY * cry + relZ * crz;
|
||||
var camY = relX * cux + relY * cuy + relZ * cuz;
|
||||
VB_Sx[v] = halfW + (camX / camZ) * focal;
|
||||
VB_Sy[v] = halfH - (camY / camZ) * focal;
|
||||
VB_Ok[v] = 1;
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
|
||||
// ===== 获取 KMt / TDt 渲染组件 =====
|
||||
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.v16b 里赋值)
|
||||
// 旧 build:u14l_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
|
||||
function GetKMtComponent(entity) {
|
||||
var comp = FindComponentByField(entity, 'u14l_1');
|
||||
var comp = FindComponentByField(entity, 'w14w_1');
|
||||
if (comp) return comp;
|
||||
comp = FindComponentByField(entity, 'u14l_1');
|
||||
if (comp) return comp;
|
||||
comp = FindComponentByField(entity, 't14l_1');
|
||||
if (comp) return comp;
|
||||
@@ -125,6 +188,17 @@
|
||||
return comp;
|
||||
}
|
||||
|
||||
// 取车身皮肤对象(含 s17b_1 部件表),跨版本兼容;stats 用于诊断来源
|
||||
function GetHullSkin(tank, stats) {
|
||||
var comp = GetKMtComponent(tank);
|
||||
if (!comp) { if (stats) stats.hullSource = '无组件'; return null; }
|
||||
if (comp.w14w_1 && comp.w14w_1.s17b_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
|
||||
if (comp.t14l_1 && comp.t14l_1.s17b_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
|
||||
if (comp.p14l_1 && comp.p14l_1.s17b_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
|
||||
if (stats) stats.hullSource = '有组件但无皮肤';
|
||||
return null;
|
||||
}
|
||||
|
||||
function GetTDtComponent(entity) {
|
||||
var comp = FindComponentByField(entity, 'n11c_1');
|
||||
if (comp) return comp;
|
||||
@@ -179,7 +253,7 @@
|
||||
// ===== GPU 数据缓存(按 Tp 资源引用,避免重复 GPU 读取) =====
|
||||
var GpuDataCache = new Map();
|
||||
var GpuCacheFrameCount = 0;
|
||||
var GpuCacheClearInterval = 600;
|
||||
var GpuCacheClearInterval = 1800; // 定期清 GPU 数据缓存(getBufferSubData 会停顿 GPU,太频繁会周期性卡顿)
|
||||
|
||||
var StrideDiagPrinted = new WeakSet();
|
||||
function GetGpuData(tp) {
|
||||
@@ -217,55 +291,21 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
// ===== 幽灵节点检测(三重检测:z34_1 + 世界矩阵 + 位置) =====
|
||||
var NodeMatrixHistory = new WeakMap();
|
||||
var TankPrevPos = new Map();
|
||||
var GhostThreshold = 30;
|
||||
var GhostCooldown = 120;
|
||||
|
||||
function IsNodeGhost(bpNode, tankIsMoving) {
|
||||
if (!bpNode || !bpNode.n35_1) return false;
|
||||
// 方案1:z34_1 字段检测(主方案)
|
||||
var z34Val = bpNode.g35_1;
|
||||
if (z34Val !== undefined && z34Val < 0.9) return true;
|
||||
// 方案2:世界矩阵更新检测(后备方案)
|
||||
var curMatrix = bpNode.n35_1;
|
||||
var hist = NodeMatrixHistory.get(bpNode);
|
||||
if (!hist) {
|
||||
hist = { m: new Array(16), unchanged: 0, cooldown: 0 };
|
||||
for (var i = 0; i < 16; i++) hist.m[i] = curMatrix[i];
|
||||
NodeMatrixHistory.set(bpNode, hist);
|
||||
return false;
|
||||
}
|
||||
var same = true;
|
||||
for (var i = 0; i < 16; i++) {
|
||||
if (Math.abs(hist.m[i] - curMatrix[i]) > 0.01) { same = false; break; }
|
||||
}
|
||||
if (same) hist.unchanged++;
|
||||
else {
|
||||
hist.unchanged = 0;
|
||||
for (var i = 0; i < 16; i++) hist.m[i] = curMatrix[i];
|
||||
}
|
||||
if (hist.cooldown > 0) { hist.cooldown--; return true; }
|
||||
if (tankIsMoving && hist.unchanged > GhostThreshold) {
|
||||
hist.cooldown = GhostCooldown;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===== 递归收集mesh节点(每帧重新获取 Bp 节点引用) =====
|
||||
function CollectMeshNodes(bpNode, nodes, depth, group) {
|
||||
function CollectMeshNodes(bpNode, nodes, depth, group, stats) {
|
||||
if (!bpNode || depth > 5) return;
|
||||
if (stats) stats.seen++;
|
||||
var name = bpNode.e35_1 || '';
|
||||
if (bpNode.t3m_1) {
|
||||
if (stats) stats.hasMesh++;
|
||||
var gpuData = GetGpuData(bpNode.t3m_1);
|
||||
if (gpuData) {
|
||||
if (stats) stats.gpuOk++;
|
||||
nodes.push({
|
||||
name: name, node: bpNode, tp: bpNode.t3m_1,
|
||||
positions: gpuData.positions, indices: gpuData.indices, stride: gpuData.stride, group: group
|
||||
});
|
||||
}
|
||||
} else if (stats) stats.gpuFail++;
|
||||
}
|
||||
if (bpNode.q4x_1 && typeof bpNode.q4x_1.e1 === 'function') {
|
||||
try {
|
||||
@@ -277,6 +317,7 @@
|
||||
if (!lodTp) continue;
|
||||
var lodGpuData = GetGpuData(lodTp);
|
||||
if (lodGpuData) {
|
||||
if (stats) stats.gpuOk++;
|
||||
nodes.push({
|
||||
name: name + '_lod' + lod, node: bpNode, tp: lodTp,
|
||||
positions: lodGpuData.positions, indices: lodGpuData.indices, stride: lodGpuData.stride, group: group
|
||||
@@ -290,20 +331,20 @@
|
||||
for (var c = 0; c < childCount; c++) {
|
||||
try {
|
||||
var child = bpNode.p35_1.g1(c);
|
||||
if (child) CollectMeshNodes(child, nodes, depth + 1, group);
|
||||
if (child) CollectMeshNodes(child, nodes, depth + 1, group, stats);
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 提取坦克的mesh数据 =====
|
||||
function GetTankMeshData(tank) {
|
||||
function GetTankMeshData(tank, stats) {
|
||||
var nodes = [];
|
||||
var kmt = GetKMtComponent(tank);
|
||||
if (kmt && kmt.t14l_1 && kmt.t14l_1.s17b_1) {
|
||||
var skin = kmt.t14l_1;
|
||||
var skin = GetHullSkin(tank, stats);
|
||||
if (skin) {
|
||||
try {
|
||||
var partCount = skin.s17b_1.e1();
|
||||
if (stats) stats.hullParts = partCount;
|
||||
for (var p = 0; p < partCount; p++) {
|
||||
var part = skin.s17b_1.g1(p);
|
||||
if (!part || !part.v17b_1) continue;
|
||||
@@ -311,93 +352,114 @@
|
||||
for (var n = 0; n < nodeCount; n++) {
|
||||
var bpNode = part.v17b_1.g1(n);
|
||||
if (!bpNode) continue;
|
||||
CollectMeshNodes(bpNode, nodes, 0, 'hull');
|
||||
CollectMeshNodes(bpNode, nodes, 0, 'hull', stats ? stats.hull : null);
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
var tdt = GetTDtComponent(tank);
|
||||
if (stats) stats.turretComp = !!tdt;
|
||||
if (tdt && tdt.n11c_1 && tdt.n11c_1.m17a_1) {
|
||||
try { CollectMeshNodes(tdt.n11c_1.m17a_1, nodes, 0, 'turret'); } catch(e) {}
|
||||
if (stats) stats.turretRoot = true;
|
||||
try { CollectMeshNodes(tdt.n11c_1.m17a_1, nodes, 0, 'turret', stats ? stats.turret : null); } catch(e) {}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// ===== 检查节点是否有效(幽灵检测 + 位置检查) =====
|
||||
function IsNodeValid(bpNode, pos, tankIsMoving, diagStats) {
|
||||
var worldMatrix = bpNode.n35_1;
|
||||
if (!worldMatrix) return null;
|
||||
// ===== 残留节点检测(世界矩阵"冻结")→ 拖拽跟随 =====
|
||||
// 现象:实体已移动,但原处仍留着线框。
|
||||
// 原因:引擎只为"本帧实际参与渲染"的节点更新世界矩阵,被裁剪/脱离的节点矩阵停在最后位置。
|
||||
// 处理:检测到「节点矩阵平移长时间不动、而坦克在动」时**不再丢弃**(丢弃会让整辆模型只剩一个点),
|
||||
// 而是用「冻结时刻的相对偏移 + 坦克当前位置」平移这份冻结矩阵,让它跟着坦克走:
|
||||
// 既不在旧位置留残留,也不会因为引擎不更新矩阵而丢掉模型。
|
||||
// 权衡:拖拽期间朝向沿用最后一次更新(位置正确、朝向可能滞后),对透视足够用。
|
||||
var NodeMatrixHistory = new WeakMap(); // WeakMap:不持有节点强引用(引擎会重建节点树)
|
||||
var TankPrevPos = new Map(); // tankId → 上一帧位置(含位移滑动平均)
|
||||
var FrozenFrames = 20; // 连续不动帧数阈值(仅在坦克本身移动时才累计)
|
||||
var NodeMatrixScratch = new Float32Array(16);
|
||||
|
||||
function IsNodeValid(bpNode, pos, tankIsMoving, diagStats) {
|
||||
var M = bpNode.n35_1;
|
||||
if (!M) return null;
|
||||
if (diagStats) diagStats.totalNodes++;
|
||||
|
||||
// 幽灵检测1:z34_1 字段
|
||||
var z34Val = bpNode.g35_1;
|
||||
if (z34Val !== undefined && z34Val < 0.9) {
|
||||
if (diagStats) diagStats.ghostNodes++;
|
||||
return null;
|
||||
var Hist = NodeMatrixHistory.get(bpNode);
|
||||
if (!Hist) {
|
||||
NodeMatrixHistory.set(bpNode, { x: M[12], y: M[13], z: M[14], still: 0, off: null });
|
||||
} else {
|
||||
var dx = M[12] - Hist.x, dy = M[13] - Hist.y, dz = M[14] - Hist.z;
|
||||
if (dx * dx + dy * dy + dz * dz > 0.01) {
|
||||
Hist.x = M[12]; Hist.y = M[13]; Hist.z = M[14];
|
||||
Hist.still = 0;
|
||||
Hist.off = null; // 矩阵恢复更新 → 恢复正常绘制
|
||||
} else if (tankIsMoving) {
|
||||
Hist.still++;
|
||||
if (Hist.still >= FrozenFrames) {
|
||||
if (!Hist.off) Hist.off = { x: M[12] - pos.x, y: M[13] - pos.y, z: M[14] - pos.z };
|
||||
for (var k = 0; k < 16; k++) NodeMatrixScratch[k] = M[k];
|
||||
NodeMatrixScratch[12] = pos.x + Hist.off.x;
|
||||
NodeMatrixScratch[13] = pos.y + Hist.off.y;
|
||||
NodeMatrixScratch[14] = pos.z + Hist.off.z;
|
||||
if (diagStats) diagStats.draggedNodes++;
|
||||
return NodeMatrixScratch; // 冻结但跟随坦克
|
||||
}
|
||||
} else {
|
||||
Hist.still = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 幽灵检测2:世界矩阵更新
|
||||
if (IsNodeGhost(bpNode, tankIsMoving)) {
|
||||
if (diagStats) diagStats.ghostNodes++;
|
||||
return null;
|
||||
}
|
||||
|
||||
// 位置检查
|
||||
var nodeDx = worldMatrix[12] - pos.x;
|
||||
var nodeDy = worldMatrix[13] - pos.y;
|
||||
var nodeDz = worldMatrix[14] - pos.z;
|
||||
if (nodeDx*nodeDx + nodeDy*nodeDy + nodeDz*nodeDz > 4000000) {
|
||||
// 位置检查(节点世界矩阵平移与坦克位置相差过大则丢弃)—— 只对"未冻结"的节点做
|
||||
var nodeDx = M[12] - pos.x, nodeDy = M[13] - pos.y, nodeDz = M[14] - pos.z;
|
||||
if (nodeDx * nodeDx + nodeDy * nodeDy + nodeDz * nodeDz > 4000000) {
|
||||
if (diagStats) diagStats.filteredNodes++;
|
||||
return null;
|
||||
}
|
||||
|
||||
return worldMatrix;
|
||||
return M;
|
||||
}
|
||||
|
||||
// ===== 线框模式:绘制单个节点的所有边 =====
|
||||
function DrawWireframeNode(ctx, meshData, worldMatrix, pos, camInfo, screenW, screenH) {
|
||||
var positions = meshData.positions;
|
||||
// 顶点数据来自 PrepareNodeVerts 的复用缓冲;边去重用数值键 Set(避免字符串分配)
|
||||
var _WfEdgeSet = new Set();
|
||||
|
||||
function WfAddEdge(ctx, a, b) {
|
||||
var lo = a < b ? a : b, hi = a < b ? b : a;
|
||||
var key = lo * 65536 + hi;
|
||||
if (_WfEdgeSet.has(key)) return;
|
||||
_WfEdgeSet.add(key);
|
||||
ctx.moveTo(VB_Sx[lo], VB_Sy[lo]);
|
||||
ctx.lineTo(VB_Sx[hi], VB_Sy[hi]);
|
||||
}
|
||||
|
||||
function DrawWireframeNode(ctx, meshData, worldMatrix, pos) {
|
||||
var indicesArr = meshData.indices;
|
||||
var stride = meshData.stride || 3;
|
||||
var vertexCount = PrepareNodeVerts(meshData, worldMatrix, pos);
|
||||
|
||||
var vertexCount = Math.floor(positions.length / stride);
|
||||
var projected = new Array(vertexCount);
|
||||
for (var v = 0; v < vertexCount; v++) {
|
||||
var wp = TransformVertex(worldMatrix, positions[v*stride], positions[v*stride+1], positions[v*stride+2]);
|
||||
// 顶点级合理性检查
|
||||
var ddx = wp.x - pos.x, ddy = wp.y - pos.y, ddz = wp.z - pos.z;
|
||||
if (ddx*ddx + ddy*ddy + ddz*ddz > 6250000) {
|
||||
projected[v] = null;
|
||||
continue;
|
||||
}
|
||||
projected[v] = Project3D(wp, camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
|
||||
}
|
||||
|
||||
var drawnEdges = new Set();
|
||||
_WfEdgeSet.clear();
|
||||
ctx.beginPath();
|
||||
for (var mi = 0; mi < indicesArr.length; mi++) {
|
||||
var indices = indicesArr[mi];
|
||||
for (var idx = 0; idx < indices.length; idx += 3) {
|
||||
var i0 = indices[idx], i1 = indices[idx+1], i2 = indices[idx+2];
|
||||
if (!projected[i0] || !projected[i1] || !projected[i2]) continue;
|
||||
var edges = [
|
||||
[Math.min(i0, i1), Math.max(i0, i1)],
|
||||
[Math.min(i1, i2), Math.max(i1, i2)],
|
||||
[Math.min(i2, i0), Math.max(i2, i0)]
|
||||
];
|
||||
for (var e = 0; e < 3; e++) {
|
||||
var key = edges[e][0] + '_' + edges[e][1];
|
||||
if (drawnEdges.has(key)) continue;
|
||||
drawnEdges.add(key);
|
||||
ctx.moveTo(projected[edges[e][0]].x, projected[edges[e][0]].y);
|
||||
ctx.lineTo(projected[edges[e][1]].x, projected[edges[e][1]].y);
|
||||
}
|
||||
if (!VB_Ok[i0] || !VB_Ok[i1] || !VB_Ok[i2]) continue;
|
||||
WfAddEdge(ctx, i0, i1);
|
||||
WfAddEdge(ctx, i1, i2);
|
||||
WfAddEdge(ctx, i2, i0);
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// ===== 兜底标记点:模型采集不到/被过滤时,至少画一个点,避免坦克完全不可见 =====
|
||||
function DrawTankMarker(ctx, pos, camInfo, screenW, screenH, color) {
|
||||
var p = Project3D(pos, camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
|
||||
if (!p) return;
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x, p.y, 3, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// ===== 描边模式:屏幕空间光栅化轮廓提取 =====
|
||||
// 算法(真正的"屏幕几何"方法):
|
||||
// 1. 把所有面向相机的三角形光栅化(扫描线填充)到像素掩码
|
||||
@@ -407,20 +469,20 @@
|
||||
var PixelMask = null;
|
||||
var PixelMaskW = 0;
|
||||
var PixelMaskH = 0;
|
||||
var MaskGen = 0; // 掩码用"代数"标记:本辆坦克填充的像素 = gen,无需在坦克之间清空整块缓冲
|
||||
|
||||
function GetPixelMask(w, h) {
|
||||
if (!PixelMask || PixelMaskW !== w || PixelMaskH !== h) {
|
||||
PixelMask = new Uint8Array(w * h);
|
||||
PixelMask = new Uint32Array(w * h);
|
||||
PixelMaskW = w;
|
||||
PixelMaskH = h;
|
||||
} else {
|
||||
PixelMask.fill(0);
|
||||
MaskGen = 0;
|
||||
}
|
||||
return PixelMask;
|
||||
}
|
||||
|
||||
// 扫描线光栅化三角形
|
||||
function RasterizeTriangle(pixels, w, h, x0, y0, x1, y1, x2, y2) {
|
||||
// 扫描线光栅化三角形(pixels 中写入 gen 表示"本辆坦克已填充")
|
||||
function RasterizeTriangle(pixels, w, h, gen, x0, y0, x1, y1, x2, y2) {
|
||||
// 按 y 排序三个顶点
|
||||
if (y0 > y1) { var t = y0; y0 = y1; y1 = t; t = x0; x0 = x1; x1 = t; }
|
||||
if (y1 > y2) { var t = y1; y1 = y2; y2 = t; t = x1; x1 = x2; x2 = t; }
|
||||
@@ -446,13 +508,15 @@
|
||||
var maxXA = Math.min(w - 1, Math.floor(xb + 0.5));
|
||||
var rowOffset = y * w;
|
||||
for (var x = minXA; x <= maxXA; x++) {
|
||||
pixels[rowOffset + x] = 1;
|
||||
pixels[rowOffset + x] = gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DrawTankOutline(ctx, meshNodes, pos, tankIsMoving, camInfo, screenW, screenH, diagStats, color) {
|
||||
function DrawTankOutline(ctx, meshNodes, pos, tankIsMoving, screenW, screenH, diagStats, color) {
|
||||
var pixels = GetPixelMask(screenW, screenH);
|
||||
var gen = ++MaskGen;
|
||||
if (gen === 0) { pixels.fill(0); gen = ++MaskGen; } // 代数回绕(理论值):整体清一次
|
||||
|
||||
// 记录坦克的屏幕边界框(用于后续边界检测优化)
|
||||
var minX = screenW, minY = screenH, maxX = 0, maxY = 0;
|
||||
@@ -463,23 +527,17 @@
|
||||
var worldMatrix = IsNodeValid(bpNode, pos, tankIsMoving, diagStats);
|
||||
if (!worldMatrix) continue;
|
||||
|
||||
var positions = meshData.positions;
|
||||
var indicesArr = meshData.indices;
|
||||
var stride = meshData.stride || 3;
|
||||
// 顶点变换+投影到复用缓冲(无对象分配)
|
||||
var vertexCount = PrepareNodeVerts(meshData, worldMatrix, pos);
|
||||
|
||||
// 变换顶点到世界空间并投影到屏幕
|
||||
var vertexCount = Math.floor(positions.length / stride);
|
||||
var worldVerts = new Array(vertexCount);
|
||||
var screenVerts = new Array(vertexCount);
|
||||
for (var v = 0; v < vertexCount; v++) {
|
||||
worldVerts[v] = TransformVertex(worldMatrix, positions[v*stride], positions[v*stride+1], positions[v*stride+2]);
|
||||
screenVerts[v] = Project3D(worldVerts[v], camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
|
||||
if (screenVerts[v]) {
|
||||
if (screenVerts[v].x < minX) minX = screenVerts[v].x;
|
||||
if (screenVerts[v].y < minY) minY = screenVerts[v].y;
|
||||
if (screenVerts[v].x > maxX) maxX = screenVerts[v].x;
|
||||
if (screenVerts[v].y > maxY) maxY = screenVerts[v].y;
|
||||
}
|
||||
if (!VB_Ok[v]) continue;
|
||||
var sx = VB_Sx[v], sy = VB_Sy[v];
|
||||
if (sx < minX) minX = sx;
|
||||
if (sy < minY) minY = sy;
|
||||
if (sx > maxX) maxX = sx;
|
||||
if (sy > maxY) maxY = sy;
|
||||
}
|
||||
|
||||
// 遍历三角形,光栅化面向相机的
|
||||
@@ -487,63 +545,60 @@
|
||||
var indices = indicesArr[mi];
|
||||
for (var i = 0; i < indices.length; i += 3) {
|
||||
var a = indices[i], b = indices[i+1], c = indices[i+2];
|
||||
var va = worldVerts[a], vb = worldVerts[b], vc = worldVerts[c];
|
||||
var sa = screenVerts[a], sb = screenVerts[b], sc = screenVerts[c];
|
||||
if (!sa || !sb || !sc) continue;
|
||||
if (!VB_Ok[a] || !VB_Ok[b] || !VB_Ok[c]) continue;
|
||||
|
||||
// 计算法线判断是否面向相机
|
||||
var e1x = vb.x - va.x, e1y = vb.y - va.y, e1z = vb.z - va.z;
|
||||
var e2x = vc.x - va.x, e2y = vc.y - va.y, e2z = vc.z - va.z;
|
||||
// 计算法线判断是否面向相机(世界坐标,来自缓冲)
|
||||
var ax = VB_Wx[a], ay = VB_Wy[a], az = VB_Wz[a];
|
||||
var bx = VB_Wx[b], by = VB_Wy[b], bz = VB_Wz[b];
|
||||
var gx = VB_Wx[c], gy = VB_Wy[c], gz = VB_Wz[c];
|
||||
var e1x = bx - ax, e1y = by - ay, e1z = bz - az;
|
||||
var e2x = gx - ax, e2y = gy - ay, e2z = gz - az;
|
||||
var nx = e1y * e2z - e1z * e2y;
|
||||
var ny = e1z * e2x - e1x * e2z;
|
||||
var nz = e1x * e2y - e1y * e2x;
|
||||
var cx = (va.x + vb.x + vc.x) / 3;
|
||||
var cy = (va.y + vb.y + vc.y) / 3;
|
||||
var cz = (va.z + vb.z + vc.z) / 3;
|
||||
var viewX = camInfo.pos.x - cx;
|
||||
var viewY = camInfo.pos.y - cy;
|
||||
var viewZ = camInfo.pos.z - cz;
|
||||
var dot = nx * viewX + ny * viewY + nz * viewZ;
|
||||
var cx = (ax + bx + gx) / 3;
|
||||
var cy = (ay + by + gy) / 3;
|
||||
var cz = (az + bz + gz) / 3;
|
||||
var dot = nx * (Cam.px - cx) + ny * (Cam.py - cy) + nz * (Cam.pz - cz);
|
||||
if (dot <= 0) continue; // 背向相机,跳过
|
||||
|
||||
// 光栅化三角形到像素掩码
|
||||
RasterizeTriangle(pixels, screenW, screenH, sa.x, sa.y, sb.x, sb.y, sc.x, sc.y);
|
||||
RasterizeTriangle(pixels, screenW, screenH, gen, VB_Sx[a], VB_Sy[a], VB_Sx[b], VB_Sy[b], VB_Sx[c], VB_Sy[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 找出边界像素并绘制(只在坦克边界框内遍历)
|
||||
// 找出边界像素并绘制(只在坦克边界框内遍历;用单条路径 + 横向连续合并,替代逐像素 fillRect)
|
||||
var bx0 = Math.max(0, Math.floor(minX) - 1);
|
||||
var by0 = Math.max(0, Math.floor(minY) - 1);
|
||||
var bx1 = Math.min(screenW - 1, Math.ceil(maxX) + 1);
|
||||
var by1 = Math.min(screenH - 1, Math.ceil(maxY) + 1);
|
||||
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
var outlineCount = 0;
|
||||
for (var y = by0; y <= by1; y++) {
|
||||
var rowOffset = y * screenW;
|
||||
for (var x = bx0; x <= bx1; x++) {
|
||||
if (pixels[rowOffset + x] === 0) continue;
|
||||
// 检查4个邻居是否有未填充像素
|
||||
var runStart = -1;
|
||||
for (var x = bx0; x <= bx1 + 1; x++) {
|
||||
var isBoundary = false;
|
||||
if (x === 0 || pixels[rowOffset + x - 1] === 0) isBoundary = true;
|
||||
else if (x === screenW - 1 || pixels[rowOffset + x + 1] === 0) isBoundary = true;
|
||||
else if (y === 0 || pixels[rowOffset - screenW + x] === 0) isBoundary = true;
|
||||
else if (y === screenH - 1 || pixels[rowOffset + screenW + x] === 0) isBoundary = true;
|
||||
if (x <= bx1 && pixels[rowOffset + x] === gen) {
|
||||
// 检查4个邻居是否有未填充像素(== gen 即本辆坦克填充)
|
||||
if (x === 0 || pixels[rowOffset + x - 1] !== gen) isBoundary = true;
|
||||
else if (x === screenW - 1 || pixels[rowOffset + x + 1] !== gen) isBoundary = true;
|
||||
else if (y === 0 || pixels[rowOffset - screenW + x] !== gen) isBoundary = true;
|
||||
else if (y === screenH - 1 || pixels[rowOffset + screenW + x] !== gen) isBoundary = true;
|
||||
}
|
||||
if (isBoundary) {
|
||||
ctx.fillRect(x, y, 3, 3);
|
||||
if (runStart < 0) runStart = x;
|
||||
outlineCount++;
|
||||
} else if (runStart >= 0) {
|
||||
ctx.rect(runStart, y, x - runStart + 2, 3); // 横向连续的边界像素合并为一条
|
||||
runStart = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清除像素掩码(供下一个坦克使用)
|
||||
for (var y2 = by0; y2 <= by1; y2++) {
|
||||
var rowOff = y2 * screenW;
|
||||
for (var x2 = bx0; x2 <= bx1; x2++) {
|
||||
pixels[rowOff + x2] = 0;
|
||||
}
|
||||
}
|
||||
ctx.fill();
|
||||
|
||||
if (diagStats) diagStats.outlineEdges += outlineCount;
|
||||
return outlineCount;
|
||||
@@ -565,7 +620,21 @@
|
||||
window.addEventListener('resize', ResizeCanvas);
|
||||
|
||||
// ===== 诊断统计 =====
|
||||
var DiagStats = { totalNodes: 0, filteredNodes: 0, renderedNodes: 0, ghostNodes: 0, outlineEdges: 0 };
|
||||
var DiagStats = { totalNodes: 0, filteredNodes: 0, renderedNodes: 0, outlineEdges: 0 };
|
||||
var LastDegradeLogFrame = -9999; // 退化诊断日志节流
|
||||
|
||||
// 退化诊断(节流输出):定位"存活坦克模型没画出来"的根因(皮肤/部件/GPU/炮塔逐级)
|
||||
function LogTankDiag(tankName, tankState, S, hullCount, turretCount, rendered) {
|
||||
if (esp.frameCount - LastDegradeLogFrame <= 120) return;
|
||||
LastDegradeLogFrame = esp.frameCount;
|
||||
console.warn('[透视][退化诊断] ' + tankName + ' state=' + tankState +
|
||||
' | 皮肤=' + S.hullSource + ' 部件=' + S.hullParts +
|
||||
' 车身[见/网格/GPU成功/失败]=' + S.hull.seen + '/' + S.hull.hasMesh + '/' + S.hull.gpuOk + '/' + S.hull.gpuFail +
|
||||
' | 炮塔 组件=' + S.turretComp + ' 根节点=' + S.turretRoot +
|
||||
' 炮塔[见/网格/GPU成功/失败]=' + S.turret.seen + '/' + S.turret.hasMesh + '/' + S.turret.gpuOk + '/' + S.turret.gpuFail +
|
||||
' | 收集 车身=' + hullCount + ' 炮塔=' + turretCount + ' 绘制=' + rendered +
|
||||
' | 本帧 总=' + DiagStats.totalNodes + ' 过滤=' + DiagStats.filteredNodes);
|
||||
}
|
||||
|
||||
// ===== ESP状态 =====
|
||||
var esp = {
|
||||
@@ -644,11 +713,158 @@
|
||||
};
|
||||
window.__hornet3DWireframe__ = esp;
|
||||
|
||||
// ===== 金箱子标记 =====
|
||||
// 金箱子是独立实体(不是坦克)。引擎侧标志:
|
||||
// · 补给实体 = entity.j10q_1(bonusData 组件,见 module_87072 的 ctt())
|
||||
// · 类型枚举 mE(module_10032):GOLD_BOX = 6
|
||||
// 做法:实体基类的组件创建方法 nyz()(module_61378「BattleEntity.createComponent」)上挂观察钩子,
|
||||
// 发现「带 j10q_1 且类型=6」的实体就登记,之后每帧按它自己的位置画金色标记。
|
||||
// 钩子目标沿 tank 的原型链找 nyz 的宿主原型 —— 不需要任何导出键。
|
||||
var GoldBoxes = [];
|
||||
var GoldPending = [];
|
||||
var EntityProtoHooked = false;
|
||||
var GOLD_BOX_TYPE = 6;
|
||||
|
||||
function FindEnumOf(Obj) {
|
||||
for (var K in Obj) {
|
||||
try {
|
||||
var V = Obj[K];
|
||||
if (V && typeof V === 'object' && typeof V.k3_1 === 'number' && typeof V.equals === 'function') return V;
|
||||
} catch (e) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 引擎口径:有 bonusData 且类型是 GOLD_BOX
|
||||
function IsGoldBoxEntity(Entity) {
|
||||
if (!Entity || !Entity.j10q_1) return false;
|
||||
var Type = FindEnumOf(Entity.j10q_1);
|
||||
return !!(Type && Type.k3_1 === GOLD_BOX_TYPE);
|
||||
}
|
||||
|
||||
function RegisterGoldBox(Entity) {
|
||||
for (var i = 0; i < GoldBoxes.length; i++) if (GoldBoxes[i] === Entity) return;
|
||||
GoldBoxes.push(Entity);
|
||||
console.log('[透视] 发现金箱子,已加入标记(当前 ' + GoldBoxes.length + ' 个)');
|
||||
}
|
||||
|
||||
function InstallEntityHook(Tank) {
|
||||
if (EntityProtoHooked || !Tank) return;
|
||||
var Proto = Tank;
|
||||
while (Proto && !Object.prototype.hasOwnProperty.call(Proto, 'nyz')) Proto = Object.getPrototypeOf(Proto);
|
||||
if (!Proto || typeof Proto.nyz !== 'function') return;
|
||||
var Orig = Proto.nyz;
|
||||
Proto.nyz = function () {
|
||||
var R = Orig.apply(this, arguments);
|
||||
try {
|
||||
if (IsGoldBoxEntity(this)) RegisterGoldBox(this);
|
||||
else if (this && this.j10q_1 === undefined && GoldPending.length < 300) {
|
||||
GoldPending.push({ e: this, f: esp.frameCount }); // 字段可能稍后才赋值,延后判定
|
||||
}
|
||||
} catch (E) {}
|
||||
return R;
|
||||
};
|
||||
EntityProtoHooked = true;
|
||||
console.log('[透视] 已挂补给实体观察钩子(金箱子)');
|
||||
}
|
||||
|
||||
// 金箱位置:优先物理组件(与坦克同款 gzh_1),否则退到 bonusData 里的节点世界矩阵/向量
|
||||
function GetGoldBoxPosition(Entity) {
|
||||
var Phys = FindComponentByField(Entity, 'gzh_1');
|
||||
if (Phys && Phys.gzh_1) {
|
||||
return { x: Phys.gzh_1.f20_1, y: Phys.gzh_1.g20_1, z: Phys.gzh_1.h20_1 };
|
||||
}
|
||||
var Bonus = Entity.j10q_1;
|
||||
for (var K in Bonus) {
|
||||
try {
|
||||
var V = Bonus[K];
|
||||
if (!V || typeof V !== 'object') continue;
|
||||
if (V.n35_1 && V.n35_1.length >= 15) {
|
||||
var M = V.n35_1;
|
||||
return { x: M[12], y: M[13], z: M[14] };
|
||||
}
|
||||
if (typeof V.f20_1 === 'number' && typeof V.g20_1 === 'number' && typeof V.h20_1 === 'number') {
|
||||
return { x: V.f20_1, y: V.g20_1, z: V.h20_1 };
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 金色菱形 + 十字 + 「金箱」标签(穿透显示,不遮挡判断)
|
||||
function DrawGoldBoxMarker(Pos, ScreenW, ScreenH) {
|
||||
var X = Pos.x - Cam.px, Y = Pos.y - Cam.py, Z = Pos.z - Cam.pz;
|
||||
var CamZ = X * Cam.fx + Y * Cam.fy + Z * Cam.fz;
|
||||
if (CamZ <= 0.1) return false;
|
||||
var CamX = X * Cam.rx + Y * Cam.ry + Z * Cam.rz;
|
||||
var CamY = X * Cam.ux + Y * Cam.uy + Z * Cam.uz;
|
||||
var Sx = Cam.halfW + (CamX / CamZ) * Cam.focal;
|
||||
var Sy = Cam.halfH - (CamY / CamZ) * Cam.focal;
|
||||
if (Sx < -60 || Sy < -60 || Sx > ScreenW + 60 || Sy > ScreenH + 60) return false;
|
||||
|
||||
var R = 12;
|
||||
ctx.save();
|
||||
ctx.strokeStyle = '#ffd700';
|
||||
ctx.fillStyle = 'rgba(255, 215, 0, 0.22)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(Sx, Sy - R);
|
||||
ctx.lineTo(Sx + R, Sy);
|
||||
ctx.lineTo(Sx, Sy + R);
|
||||
ctx.lineTo(Sx - R, Sy);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(Sx - R - 7, Sy); ctx.lineTo(Sx + R + 7, Sy);
|
||||
ctx.moveTo(Sx, Sy - R - 7); ctx.lineTo(Sx, Sy + R + 7);
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = '#ffd700';
|
||||
ctx.font = 'bold 12px Consolas,monospace';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('金箱', Sx, Sy - R - 9);
|
||||
ctx.restore();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== 冻结节点"拖拽跟随"诊断(节流 2s)=====
|
||||
var LastFrozenLogAt = 0;
|
||||
function LogDragDiag(Stats) {
|
||||
if (!Stats.draggedNodes) return;
|
||||
var Now = Date.now();
|
||||
if (Now - LastFrozenLogAt < 2000) return;
|
||||
LastFrozenLogAt = Now;
|
||||
console.log('[透视][冻结] 本帧拖拽跟随节点 ' + Stats.draggedNodes + '/' + Stats.totalNodes +
|
||||
'(引擎未更新这些节点矩阵,已按坦克位移平移,避免旧位置残留/模型丢失)');
|
||||
}
|
||||
|
||||
// ===== 渲染循环 =====
|
||||
function Render() {
|
||||
if (!esp.running) return;
|
||||
esp.frameCount++;
|
||||
|
||||
// 换图自刷新:gameMode 实例变化时重绑并清空该地图的缓存
|
||||
var NewGm = window.__gameMode__;
|
||||
if (NewGm && NewGm !== gm) {
|
||||
gm = NewGm;
|
||||
GpuDataCache.clear(); // 旧地图的 GPU 几何数据失效
|
||||
TankPrevPos.clear(); // 位置历史(判断"在动")失效
|
||||
GoldBoxes.length = 0; // 上一局的箱子实体全部作废
|
||||
GoldPending.length = 0;
|
||||
GpuCacheFrameCount = 0;
|
||||
console.log('[透视] 检测到新战斗,已重置缓存');
|
||||
}
|
||||
// 旧实例已失效、新实例尚未捕获:清屏并显示等待提示,避免继续用悬空引用
|
||||
if (!window.__gameMode__) {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = 'rgba(255, 220, 120, 0.9)';
|
||||
ctx.font = 'bold 12px Consolas,monospace';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('[' + Mode.toUpperCase() + '] 等待战局…(ght 未捕获)', 5, canvas.height - 5);
|
||||
requestAnimationFrame(Render);
|
||||
return;
|
||||
}
|
||||
|
||||
// 定期清空 GPU 数据缓存
|
||||
GpuCacheFrameCount++;
|
||||
if (GpuCacheFrameCount >= GpuCacheClearInterval) {
|
||||
@@ -656,7 +872,7 @@
|
||||
GpuCacheFrameCount = 0;
|
||||
}
|
||||
|
||||
DiagStats = { totalNodes: 0, filteredNodes: 0, renderedNodes: 0, ghostNodes: 0, outlineEdges: 0 };
|
||||
DiagStats = { totalNodes: 0, filteredNodes: 0, draggedNodes: 0, renderedNodes: 0, outlineEdges: 0, goldBoxes: 0 };
|
||||
|
||||
try {
|
||||
var screenW = canvas.width;
|
||||
@@ -681,6 +897,8 @@
|
||||
if (pPos) camInfo.pos = { x: pPos.x, y: pPos.y, z: pPos.z + 100 };
|
||||
}
|
||||
|
||||
UpdateCam(camInfo, screenW, screenH); // 每帧只算一次相机基(需在相机位置兜底之后),供顶点变换/投影复用
|
||||
|
||||
var tankList = gm.q100_1.r11l();
|
||||
var count = tankList.e1();
|
||||
var drawnCount = 0;
|
||||
@@ -688,11 +906,13 @@
|
||||
for (var i = 0; i < count; i++) {
|
||||
var tank = tankList.g1(i);
|
||||
if (!tank || tank === playerTank) continue;
|
||||
if (!EntityProtoHooked) InstallEntityHook(tank); // 借坦克实例找到实体基类原型,挂补给观察钩子
|
||||
|
||||
var physicsComp = FindComponentByField(tank, 'gzh_1');
|
||||
if (!physicsComp || !physicsComp.gzh_1) continue;
|
||||
var tankState = GetTankState(tank);
|
||||
if (tankState !== 3) continue;
|
||||
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 y147() 判定),0/1/4 才跳过
|
||||
if (tankState !== 2 && tankState !== 3) continue;
|
||||
|
||||
var pos = {
|
||||
x: physicsComp.gzh_1.f20_1,
|
||||
@@ -700,15 +920,18 @@
|
||||
z: physicsComp.gzh_1.h20_1
|
||||
};
|
||||
|
||||
// 坦克移动检测
|
||||
// 本帧该坦克是否在移动(供「残留节点」检测:坦克在动而节点矩阵不动 = 旧位置遗留)
|
||||
// 用位移的指数滑动平均,而不是「单帧位移 > 10 单位」——后者对慢速移动几乎永远为假,
|
||||
// 会让残留检测形同虚设(残留漏掉的根因就在这里)
|
||||
var tankId = tank.hyt_1;
|
||||
var prevPos = TankPrevPos.get(tankId);
|
||||
var tankIsMoving = false;
|
||||
var tankMove = 0;
|
||||
if (prevPos) {
|
||||
var pdx = pos.x - prevPos.x, pdy = pos.y - prevPos.y, pdz = pos.z - prevPos.z;
|
||||
tankIsMoving = (pdx*pdx + pdy*pdy + pdz*pdz) > 100;
|
||||
tankMove = (prevPos.move || 0) * 0.85 + Math.sqrt(pdx * pdx + pdy * pdy + pdz * pdz);
|
||||
}
|
||||
TankPrevPos.set(tankId, { x: pos.x, y: pos.y, z: pos.z });
|
||||
var tankIsMoving = tankMove > 0.5; // 0.5 单位/帧 ≈ 0.3 m/s;静置坦克的抖动低于此值
|
||||
TankPrevPos.set(tankId, { x: pos.x, y: pos.y, z: pos.z, move: tankMove });
|
||||
|
||||
// 距离检查(50000 = 500米)
|
||||
var dx = pos.x - camInfo.pos.x;
|
||||
@@ -723,70 +946,29 @@
|
||||
if (!ShouldRender(tankName)) continue;
|
||||
// 颜色按队伍:友方=蓝,敌方=红
|
||||
var color = friendly ? 'rgba(68, 136, 255, 0.6)' : 'rgba(255, 68, 68, 0.6)';
|
||||
var tankColor = friendly ? 'rgba(68, 136, 255, 0.9)' : 'rgba(255, 68, 68, 0.9)';
|
||||
|
||||
// 先画中心点、距离和血量(独立于3D模型渲染)
|
||||
var centerProj = Project3D(pos, camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
|
||||
|
||||
if (centerProj) {
|
||||
// 血量信息
|
||||
var health = GetTankHealth(tank);
|
||||
var barW = 60, barH = 6;
|
||||
var barX = centerProj.x - barW / 2;
|
||||
var barY = centerProj.y - barH - 4;
|
||||
if (health) {
|
||||
// 背景
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
|
||||
ctx.fillRect(barX - 1, barY - 1, barW + 2, barH + 2);
|
||||
// 血量百分比颜色:绿>60%, 黄>30%, 红
|
||||
var hpColor = health.percent > 0.6 ? '#44ff44' :
|
||||
health.percent > 0.3 ? '#ffaa00' : '#ff4444';
|
||||
ctx.fillStyle = hpColor;
|
||||
ctx.fillRect(barX, barY, barW * health.percent, barH);
|
||||
// 边框
|
||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeRect(barX, barY, barW, barH);
|
||||
// 名称(血量条上方)
|
||||
ctx.fillStyle = tankColor;
|
||||
ctx.font = 'bold 11px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(tankName, centerProj.x, barY - 14);
|
||||
// 距离(血量条上方第二行)
|
||||
ctx.font = '10px Arial';
|
||||
ctx.fillText(Math.round(distance / 100) + 'm', centerProj.x, barY - 3);
|
||||
// 血量数值(血量条下方)
|
||||
ctx.fillStyle = hpColor;
|
||||
ctx.font = '10px Arial';
|
||||
ctx.fillText(Math.round(health.current) + '/' + Math.round(health.max), centerProj.x, barY + barH + 10);
|
||||
} else {
|
||||
ctx.fillStyle = tankColor;
|
||||
ctx.font = 'bold 11px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(tankName, centerProj.x, centerProj.y - 18);
|
||||
ctx.font = '10px Arial';
|
||||
ctx.fillText(Math.round(distance / 100) + 'm', centerProj.x, centerProj.y - 6);
|
||||
}
|
||||
// 中心点
|
||||
ctx.fillStyle = tankColor;
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerProj.x, centerProj.y, 2, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// 3D模型渲染(仅在mesh数据可用时)
|
||||
var meshNodes = GetTankMeshData(tank);
|
||||
var MeshStats = {
|
||||
hullSource: '', hullParts: 0, turretComp: false, turretRoot: false,
|
||||
hull: { seen: 0, hasMesh: 0, gpuOk: 0, gpuFail: 0 },
|
||||
turret: { seen: 0, hasMesh: 0, gpuOk: 0, gpuFail: 0 }
|
||||
};
|
||||
var meshNodes = GetTankMeshData(tank, MeshStats);
|
||||
if (!meshNodes || meshNodes.length === 0) {
|
||||
LogTankDiag(tankName, tankState, MeshStats, 0, 0, 0);
|
||||
DrawTankMarker(ctx, pos, camInfo, screenW, screenH, color); // 兜底:至少可见
|
||||
drawnCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否有炮塔
|
||||
var hasTurret = false;
|
||||
for (var ti = 0; ti < meshNodes.length; ti++) {
|
||||
if (meshNodes[ti].group === 'turret') { hasTurret = true; break; }
|
||||
// 统计各分组节点数(诊断用)
|
||||
var hullCount = 0, turretCount = 0;
|
||||
for (var gi = 0; gi < meshNodes.length; gi++) {
|
||||
if (meshNodes[gi].group === 'turret') turretCount++; else hullCount++;
|
||||
}
|
||||
if (!hasTurret) {
|
||||
if (turretCount === 0) { // 没有炮塔节点则不画模型,仅画兜底标记
|
||||
LogTankDiag(tankName, tankState, MeshStats, hullCount, turretCount, 0);
|
||||
DrawTankMarker(ctx, pos, camInfo, screenW, screenH, color);
|
||||
drawnCount++;
|
||||
continue;
|
||||
}
|
||||
@@ -794,47 +976,48 @@
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = LineWidth;
|
||||
|
||||
var renderedThisTank = 0;
|
||||
if (Mode === 'wireframe') {
|
||||
for (var ni = 0; ni < meshNodes.length; ni++) {
|
||||
var meshData = meshNodes[ni];
|
||||
var bpNode = meshData.node;
|
||||
var worldMatrix = IsNodeValid(bpNode, pos, tankIsMoving, DiagStats);
|
||||
if (!worldMatrix) continue;
|
||||
DrawWireframeNode(ctx, meshData, worldMatrix, pos, camInfo, screenW, screenH);
|
||||
DrawWireframeNode(ctx, meshData, worldMatrix, pos);
|
||||
DiagStats.renderedNodes++;
|
||||
renderedThisTank++;
|
||||
}
|
||||
} else {
|
||||
DrawTankOutline(ctx, meshNodes, pos, tankIsMoving, camInfo, screenW, screenH, DiagStats, color);
|
||||
renderedThisTank = DrawTankOutline(ctx, meshNodes, pos, tankIsMoving, screenW, screenH, DiagStats, color);
|
||||
}
|
||||
|
||||
// 诊断(节流):存活坦克模型退化时输出根因数据,便于一次性定位
|
||||
if ((renderedThisTank === 0 && meshNodes.length > 0) || hullCount === 0) {
|
||||
LogTankDiag(tankName, tankState, MeshStats, hullCount, turretCount, renderedThisTank);
|
||||
}
|
||||
// 一个节点都没画出来:画兜底标记,避免坦克完全不可见
|
||||
if (renderedThisTank === 0) {
|
||||
DrawTankMarker(ctx, pos, camInfo, screenW, screenH, color);
|
||||
}
|
||||
|
||||
drawnCount++;
|
||||
}
|
||||
|
||||
// 玩家血量显示(左上角)
|
||||
var playerHealth = GetTankHealth(playerTank);
|
||||
if (playerHealth) {
|
||||
var pBarW = 200, pBarH = 12;
|
||||
var pBarX = 10, pBarY = 10;
|
||||
// 背景
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
|
||||
ctx.fillRect(pBarX - 1, pBarY - 1, pBarW + 2, pBarH + 2);
|
||||
// 血量颜色
|
||||
var pHpColor = playerHealth.percent > 0.6 ? '#44ff44' :
|
||||
playerHealth.percent > 0.3 ? '#ffaa00' : '#ff4444';
|
||||
ctx.fillStyle = pHpColor;
|
||||
ctx.fillRect(pBarX, pBarY, pBarW * playerHealth.percent, pBarH);
|
||||
// 边框
|
||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeRect(pBarX, pBarY, pBarW, pBarH);
|
||||
// 文字
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = 'bold 11px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('HP: ' + Math.round(playerHealth.current) + ' / ' + Math.round(playerHealth.max) +
|
||||
' (' + Math.round(playerHealth.percent * 100) + '%)',
|
||||
pBarX + pBarW / 2, pBarY + pBarH - 1);
|
||||
// ===== 金箱子:清理失效项 → 评估候选 → 画金色标记 =====
|
||||
var goldDrawn = 0;
|
||||
for (var gci = GoldBoxes.length - 1; gci >= 0; gci--) {
|
||||
if (!IsGoldBoxEntity(GoldBoxes[gci])) GoldBoxes.splice(gci, 1); // 被拾取/销毁
|
||||
}
|
||||
for (var gpi = GoldPending.length - 1; gpi >= 0; gpi--) {
|
||||
var PendingIt = GoldPending[gpi];
|
||||
if (esp.frameCount - PendingIt.f > 90) { GoldPending.splice(gpi, 1); continue; }
|
||||
if (IsGoldBoxEntity(PendingIt.e)) { RegisterGoldBox(PendingIt.e); GoldPending.splice(gpi, 1); }
|
||||
}
|
||||
for (var gbi = 0; gbi < GoldBoxes.length; gbi++) {
|
||||
var GoldPos = GetGoldBoxPosition(GoldBoxes[gbi]);
|
||||
if (GoldPos && DrawGoldBoxMarker(GoldPos, screenW, screenH)) goldDrawn++;
|
||||
}
|
||||
DiagStats.goldBoxes = goldDrawn;
|
||||
|
||||
// 屏幕信息
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
@@ -846,8 +1029,11 @@
|
||||
} else {
|
||||
infoText += ' | Nodes: ' + DiagStats.renderedNodes + '/' + DiagStats.totalNodes;
|
||||
}
|
||||
infoText += ' | Ghost: ' + DiagStats.ghostNodes + ' | Frame: ' + esp.frameCount;
|
||||
infoText += ' | Frame: ' + esp.frameCount;
|
||||
if (DiagStats.draggedNodes > 0) infoText += ' | 拖拽:' + DiagStats.draggedNodes;
|
||||
if (DiagStats.goldBoxes > 0) infoText += ' | 金箱:' + DiagStats.goldBoxes;
|
||||
ctx.fillText(infoText, 5, screenH - 5);
|
||||
LogDragDiag(DiagStats);
|
||||
|
||||
} catch(e) {
|
||||
console.error('[透视] 错误:', e.message, e.stack ? e.stack.split('\n')[1] : '');
|
||||
|
||||
@@ -7,18 +7,13 @@
|
||||
function _start() {
|
||||
console.log('===== 3DTank瞄准警告启动 =====');
|
||||
|
||||
if (!window.__gameMode__) {
|
||||
console.error('请先运行 hook_gamemode.js');
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== 清理旧实例 =====
|
||||
// 允许在未进入战局 / ght 尚未捕获时启动:先出状态行,威胁判定等进入战局再算
|
||||
if (window.__hornetAimWarning__) {
|
||||
window.__hornetAimWarning__.Stop();
|
||||
console.log('已停止旧瞄准警告');
|
||||
}
|
||||
|
||||
var gm = window.__gameMode__;
|
||||
var gm = window.__gameMode__ || null;
|
||||
|
||||
// ===== 设置参数(localStorage 持久化)=====
|
||||
// Sensitivity: 灵敏度系数,>1 更灵敏(阈值更大,更易触发),<1 更迟钝
|
||||
@@ -86,7 +81,7 @@
|
||||
var GetTankHealth = lib.GetTankHealth;
|
||||
|
||||
// ===== 获取炮塔瞄准角度 =====
|
||||
// 从炮塔 Bp 节点世界矩阵(g35_1)提取水平面前向方向
|
||||
// 从炮塔 Bp 节点世界矩阵(n35_1)提取水平面前向方向
|
||||
// 返回 { angle: 炮塔朝向与"敌方→玩家"方向的夹角, distance: 距离, turretAngle: 炮塔朝向角度, turretDir: {x,y} }
|
||||
function GetTurretAimAngle(tank, enemyPos, playerPos) {
|
||||
var tdt = GetTDtComponent(tank);
|
||||
@@ -253,6 +248,25 @@
|
||||
frameCount++;
|
||||
requestAnimationFrame(Loop);
|
||||
|
||||
// 换图自刷新:gameMode 实例变化时重绑并清空该地图的缓存
|
||||
var NewGm = window.__gameMode__;
|
||||
if (NewGm && NewGm !== gm) {
|
||||
gm = NewGm;
|
||||
UMtComponent = null; // 碰撞检测器需从新场景重新获取
|
||||
RaycastCache.clear(); // 旧地图的视线遮挡缓存失效
|
||||
DeathInfo = null; // 清掉旧地图的死亡提示
|
||||
console.log('[瞄准] 检测到新战斗,已重置缓存');
|
||||
}
|
||||
// ght 尚未捕获 / 不在战局:清屏并显示等待提示
|
||||
if (!window.__gameMode__) {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = 'rgba(255, 220, 120, 0.85)';
|
||||
ctx.font = '11px Arial';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('[瞄准警告] 等待战局…(ght 未捕获)', 5, 18);
|
||||
return;
|
||||
}
|
||||
|
||||
var screenW = canvas.width;
|
||||
var screenH = canvas.height;
|
||||
ctx.clearRect(0, 0, screenW, screenH);
|
||||
|
||||
@@ -226,6 +226,18 @@
|
||||
|
||||
function loop(now) {
|
||||
if (!running) return;
|
||||
|
||||
// 换图自刷新:gameMode 实例变化时整体重启,重新 Hook 新相机的 o37
|
||||
var NewGm = window.__gameMode__;
|
||||
if (NewGm && NewGm !== gm) {
|
||||
console.log('[自由视角] 检测到新战斗,正在重启以绑定新相机...');
|
||||
self.Stop();
|
||||
_start();
|
||||
return;
|
||||
}
|
||||
// 旧实例已失效、新实例尚未捕获:跳过本帧
|
||||
if (!window.__gameMode__) { rafId = requestAnimationFrame(loop); return; }
|
||||
|
||||
var dt = (now - lastTime) / 1000;
|
||||
lastTime = now;
|
||||
if (dt > 0.1) dt = 0.1; // 防止卡顿后大跳
|
||||
|
||||
+41
-7
@@ -78,8 +78,13 @@
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 只有 ACTIVE(3) 才是战斗中的坦克
|
||||
function IsTankAlive(tank) { return GetTankState(tank) === 3; }
|
||||
// 可见/战斗中的坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)
|
||||
// 依据:引擎用 tankComponent.y147()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
|
||||
// 只认 ACTIVE 会漏掉半活跃状态(出生/过渡)的坦克
|
||||
function IsTankAlive(tank) {
|
||||
var s = GetTankState(tank);
|
||||
return s === 2 || s === 3;
|
||||
}
|
||||
|
||||
// ===== 获取坦克名称(yot 用户信息组件) =====
|
||||
// s120_1 = userName, u120_1 = clanTag(可为null), t120_1 = userRank
|
||||
@@ -313,22 +318,50 @@
|
||||
|
||||
// ===== 让元素可拖动(左键拖动,改变 left/top) =====
|
||||
// 适用于固定定位的小窗口(雷达、后视镜等)
|
||||
// key: 可选,传入后会把窗口位置存到 localStorage(hornet_layout_<key>)并在创建时还原
|
||||
// 实现要点:Pointer Events + setPointerCapture,保证 pointerup/pointercancel 必定回到元素,
|
||||
// 并在 window 捕获阶段兜底,避免游戏画布抢事件后"松手仍粘着鼠标"。
|
||||
function MakeDraggable(elem) {
|
||||
function MakeDraggable(elem, key) {
|
||||
if (!elem) return null;
|
||||
elem.style.cursor = 'move';
|
||||
|
||||
var StorageKey = key ? ('hornet_layout_' + key) : null;
|
||||
|
||||
function ClampX(v) { return Math.max(0, Math.min(window.innerWidth - 50, v)); }
|
||||
function ClampY(v) { return Math.max(0, Math.min(window.innerHeight - 30, v)); }
|
||||
|
||||
// 还原上次保存的位置
|
||||
if (StorageKey) {
|
||||
try {
|
||||
var __saved = localStorage.getItem(StorageKey);
|
||||
if (__saved) {
|
||||
var __p = JSON.parse(__saved);
|
||||
if (__p && typeof __p.left === 'number' && typeof __p.top === 'number') {
|
||||
elem.style.right = 'auto';
|
||||
elem.style.transform = 'none';
|
||||
elem.style.left = ClampX(__p.left) + 'px';
|
||||
elem.style.top = ClampY(__p.top) + 'px';
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function SavePos() {
|
||||
if (!StorageKey) return;
|
||||
try {
|
||||
var r = elem.getBoundingClientRect();
|
||||
localStorage.setItem(StorageKey, JSON.stringify({ left: Math.round(r.left), top: Math.round(r.top) }));
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
var Active = false;
|
||||
var PointerId = null;
|
||||
var GrabX = 0;
|
||||
var GrabY = 0;
|
||||
|
||||
function MoveTo(ClientX, ClientY) {
|
||||
var NextX = Math.max(0, Math.min(window.innerWidth - 50, ClientX - GrabX));
|
||||
var NextY = Math.max(0, Math.min(window.innerHeight - 30, ClientY - GrabY));
|
||||
elem.style.left = NextX + 'px';
|
||||
elem.style.top = NextY + 'px';
|
||||
elem.style.left = ClampX(ClientX - GrabX) + 'px';
|
||||
elem.style.top = ClampY(ClientY - GrabY) + 'px';
|
||||
}
|
||||
|
||||
function Begin(ClientX, ClientY) {
|
||||
@@ -352,6 +385,7 @@
|
||||
}
|
||||
PointerId = null;
|
||||
elem.style.cursor = 'move';
|
||||
SavePos();
|
||||
}
|
||||
|
||||
if (window.PointerEvent) {
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
// hornet_mouse.js — 鼠标输入稳定器
|
||||
// 目标:缓解原版「指针锁定下鼠标乱晃 / 难控制」的问题(游戏自身行为,非本工具链引入)。
|
||||
//
|
||||
// 游戏侧机制(module_03569):
|
||||
// · 锁定:Lh() 先 requestPointerLock({unadjustedMovement:true})(原始输入),**失败则静默回退**
|
||||
// 成不带 unadjustedMovement 的普通锁定 —— 后者会带上 OS 鼠标加速,手感立刻变飘。
|
||||
// · 视角:mousemove 里直接把 e.movementX / e.movementY 喂给输入管理器
|
||||
// (fal_1.ia9(qh(), movementX, movementY)),没有任何尖峰/跳变过滤。
|
||||
//
|
||||
// 本模块做三件事,全部可在面板「鼠标稳定」里开关:
|
||||
// ① 强制原始输入:接管 Element.prototype.requestPointerLock,始终带 unadjustedMovement,
|
||||
// 并把「回退/失败」打到控制台(手感异常的第一嫌疑人)。
|
||||
// ② 锁后/恢复跳变抑制:指针锁定刚建立、或事件流中断(切窗口/失焦)后恢复的头 DropMs 毫秒内
|
||||
// 丢弃 mousemove —— 这一两下常带巨大 movementX/Y,会直接把视角甩飞。
|
||||
// ③ 尖峰钳制:单事件 |movementX| / |movementY| 超过 MaxDelta(0 = 关闭)时截断,
|
||||
// 抑制驱动/焦点抖动造成的瞬时尖峰。
|
||||
//
|
||||
// 状态:HUD 里显示「鼠标: RAW 48/s 尖峰320 钳0 丢1」,或
|
||||
// console.log(window.__hornetTools__.Mouse.GetStatus())
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var lib = window.__hornetLib__;
|
||||
if (!lib) {
|
||||
console.error('[鼠标] 请先加载 hornet_lib.js');
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== 配置(localStorage 持久化)=====
|
||||
var CONFIG_KEY = 'hornet_mouse_cfg';
|
||||
var Config = {
|
||||
ForceRaw: true, // 强制原始输入(unadjustedMovement),关掉则完全不干预指针锁定
|
||||
DropMs: 120, // 锁定建立 / 事件流恢复后的忽略时长(ms,0 = 不丢事件)
|
||||
GapMs: 250, // 事件间隔超过它视为「恢复」,同样触发忽略窗口(ms)
|
||||
MaxDelta: 0 // 单事件位移钳制阈值(px,0 = 不钳制)
|
||||
};
|
||||
try {
|
||||
var Saved = JSON.parse(localStorage.getItem(CONFIG_KEY) || '{}');
|
||||
if (typeof Saved.ForceRaw === 'boolean') Config.ForceRaw = Saved.ForceRaw;
|
||||
if (typeof Saved.DropMs === 'number') Config.DropMs = Saved.DropMs;
|
||||
if (typeof Saved.GapMs === 'number') Config.GapMs = Saved.GapMs;
|
||||
if (typeof Saved.MaxDelta === 'number') Config.MaxDelta = Saved.MaxDelta;
|
||||
} catch (e) {}
|
||||
function SaveConfig() {
|
||||
try { localStorage.setItem(CONFIG_KEY, JSON.stringify(Config)); } catch (e) {}
|
||||
}
|
||||
|
||||
function Now() {
|
||||
return (window.performance && window.performance.now) ? window.performance.now() : Date.now();
|
||||
}
|
||||
|
||||
// ===== 运行状态与统计 =====
|
||||
var Stat = {
|
||||
running: false,
|
||||
rawMode: '未知', // 原始输入 / 带加速 / 未知
|
||||
locked: false,
|
||||
dropUntil: 0, // 该时刻前的 mousemove 全部丢弃
|
||||
dropped: 0,
|
||||
clamped: 0,
|
||||
events: 0,
|
||||
maxAbs: 0, // 本统计窗口内最大单事件位移
|
||||
lastEventAt: 0,
|
||||
rate: 0,
|
||||
rateEvents: 0,
|
||||
rateWindow: 0,
|
||||
lastAnomalyAt: 0
|
||||
};
|
||||
|
||||
var OrigRequestPointerLock = null;
|
||||
var Attached = false;
|
||||
|
||||
// ===== ① 指针锁定:强制原始输入 =====
|
||||
function InstallLockPatch() {
|
||||
if (OrigRequestPointerLock) return;
|
||||
OrigRequestPointerLock = Element.prototype.requestPointerLock;
|
||||
Element.prototype.requestPointerLock = function (Options) {
|
||||
var Opt = Options;
|
||||
if (Config.ForceRaw && !(Opt && Opt.unadjustedMovement)) {
|
||||
Opt = { unadjustedMovement: true }; // 显式请求原始输入(不改调用方对象)
|
||||
}
|
||||
// 只有在「本来没锁」时才算一次真正的锁定(避免已锁定时的重复请求反复刷新忽略窗口,
|
||||
// 那会让鼠标一直被丢弃而失去响应)
|
||||
var WasLocked = !!document.pointerLockElement;
|
||||
Stat.locked = true;
|
||||
if (!WasLocked) {
|
||||
Stat.lastEventAt = 0; // 重新计时,避免把旧的间隔当成「恢复」
|
||||
Stat.dropUntil = Config.DropMs > 0 ? (Now() + Config.DropMs) : 0;
|
||||
}
|
||||
|
||||
var P;
|
||||
try {
|
||||
P = OrigRequestPointerLock.call(this, Opt);
|
||||
} catch (Err) {
|
||||
console.error('[鼠标] requestPointerLock 调用异常:', Err && Err.message);
|
||||
return null;
|
||||
}
|
||||
var WantRaw = !!(Opt && Opt.unadjustedMovement);
|
||||
if (P && typeof P.then === 'function') {
|
||||
P.then(
|
||||
function () {
|
||||
Stat.rawMode = WantRaw ? '原始输入' : '带加速';
|
||||
console.log('[鼠标] 指针锁定成功,模式=' + Stat.rawMode +
|
||||
(WantRaw ? '' : '(带 OS 加速,手感会飘;可在面板勾选「强制原始输入」)'));
|
||||
},
|
||||
function (Err) {
|
||||
Stat.rawMode = '未知';
|
||||
console.warn('[鼠标] 指针锁定失败: ' + (Err && Err.message));
|
||||
},
|
||||
);
|
||||
} else {
|
||||
Stat.rawMode = WantRaw ? '原始输入' : '带加速';
|
||||
}
|
||||
return P;
|
||||
};
|
||||
}
|
||||
|
||||
function UninstallLockPatch() {
|
||||
if (!OrigRequestPointerLock) return;
|
||||
Element.prototype.requestPointerLock = OrigRequestPointerLock;
|
||||
OrigRequestPointerLock = null;
|
||||
}
|
||||
|
||||
// ===== ②③ mousemove 拦截:丢弃跳变 + 钳制尖峰 =====
|
||||
// 注册在 window 的捕获阶段:一定早于游戏挂在画布/document 上的处理器,丢弃/改写才有效
|
||||
function OnMouseMoveCapture(e) {
|
||||
Stat.events++;
|
||||
var T = Now();
|
||||
|
||||
// 事件流「恢复」判定(切窗口/失焦回来时的第一下常是巨幅位移)
|
||||
if (Config.GapMs > 0 && Stat.lastEventAt && (T - Stat.lastEventAt) > Config.GapMs && Config.DropMs > 0) {
|
||||
Stat.dropUntil = T + Config.DropMs;
|
||||
}
|
||||
Stat.lastEventAt = T;
|
||||
|
||||
// ② 忽略窗口内:整条事件丢弃(stopImmediatePropagation 阻断游戏处理器)
|
||||
if (Stat.dropUntil && T < Stat.dropUntil) {
|
||||
Stat.dropped++;
|
||||
e.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
var Dx = e.movementX, Dy = e.movementY;
|
||||
if (typeof Dx !== 'number' || typeof Dy !== 'number') return;
|
||||
|
||||
var Ax = Math.abs(Dx), Ay = Math.abs(Dy);
|
||||
if (Ax > Stat.maxAbs) Stat.maxAbs = Ax;
|
||||
if (Ay > Stat.maxAbs) Stat.maxAbs = Ay;
|
||||
|
||||
// ③ 尖峰钳制:改写事件上的 movementX/Y(own property 遮蔽原型 getter)
|
||||
if (Config.MaxDelta > 0 && (Ax > Config.MaxDelta || Ay > Config.MaxDelta)) {
|
||||
var Nx = Ax > Config.MaxDelta ? (Dx > 0 ? Config.MaxDelta : -Config.MaxDelta) : Dx;
|
||||
var Ny = Ay > Config.MaxDelta ? (Dy > 0 ? Config.MaxDelta : -Config.MaxDelta) : Dy;
|
||||
try {
|
||||
Object.defineProperty(e, 'movementX', { value: Nx, configurable: true });
|
||||
Object.defineProperty(e, 'movementY', { value: Ny, configurable: true });
|
||||
Stat.clamped++;
|
||||
} catch (Err) {
|
||||
// 属性不可写则退化为丢弃该事件(同样能压住甩飞)
|
||||
Stat.clamped++;
|
||||
e.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 事件率统计(2s 窗口),尖峰异常时节流提示,帮助定位是「抖动」还是「跳变」
|
||||
Stat.rateEvents++;
|
||||
if (!Stat.rateWindow) Stat.rateWindow = T;
|
||||
if (T - Stat.rateWindow >= 2000) {
|
||||
Stat.rate = Math.round((Stat.rateEvents * 1000) / (T - Stat.rateWindow));
|
||||
Stat.rateWindow = T;
|
||||
Stat.rateEvents = 0;
|
||||
var Bad = Stat.maxAbs > 400 && (T - Stat.lastAnomalyAt) > 3000;
|
||||
if (Bad) {
|
||||
Stat.lastAnomalyAt = T;
|
||||
console.warn('[鼠标] 出现大位移尖峰: ' + Stat.maxAbs.toFixed(0) + 'px(事件率 ' + Stat.rate +
|
||||
'/s,累计钳制 ' + Stat.clamped + ' 次)。若频繁甩飞,把「尖峰钳制」调成 250~400 试试');
|
||||
}
|
||||
Stat.maxAbs = 0; // 只统计窗口内最大值
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 启动 / 停止 =====
|
||||
function _start() {
|
||||
if (Stat.running) return;
|
||||
if (Config.ForceRaw) InstallLockPatch();
|
||||
if (!Attached) {
|
||||
window.addEventListener('mousemove', OnMouseMoveCapture, true);
|
||||
Attached = true;
|
||||
}
|
||||
Stat.running = true;
|
||||
console.log('[鼠标] 稳定器已启动 强制原始输入=' + Config.ForceRaw +
|
||||
' 锁后忽略=' + Config.DropMs + 'ms 尖峰钳制=' + (Config.MaxDelta > 0 ? Config.MaxDelta + 'px' : '关'));
|
||||
}
|
||||
|
||||
function _stop() {
|
||||
if (!Stat.running) return;
|
||||
UninstallLockPatch();
|
||||
if (Attached) {
|
||||
window.removeEventListener('mousemove', OnMouseMoveCapture, true);
|
||||
Attached = false;
|
||||
}
|
||||
Stat.running = false;
|
||||
Stat.dropped = 0; Stat.clamped = 0; Stat.events = 0; Stat.maxAbs = 0;
|
||||
Stat.dropUntil = 0; Stat.lastEventAt = 0; Stat.rawMode = '未知';
|
||||
console.log('[鼠标] 稳定器已停止');
|
||||
}
|
||||
|
||||
var Api = {
|
||||
config: Config,
|
||||
_start: _start,
|
||||
_stop: _stop,
|
||||
setForceRaw: function (On) { Config.ForceRaw = !!On; SaveConfig(); if (Stat.running) { if (On) InstallLockPatch(); else UninstallLockPatch(); } },
|
||||
setDropMs: function (Ms) { Config.DropMs = Math.max(0, Number(Ms) || 0); SaveConfig(); },
|
||||
setMaxDelta: function (Px) { Config.MaxDelta = Math.max(0, Number(Px) || 0); SaveConfig(); },
|
||||
getStatus: function () {
|
||||
return {
|
||||
running: Stat.running, rawMode: Stat.rawMode, rate: Stat.rate,
|
||||
maxAbs: Math.round(Stat.maxAbs), clamped: Stat.clamped, dropped: Stat.dropped, events: Stat.events
|
||||
};
|
||||
}
|
||||
};
|
||||
window.__hornetMouse__ = Api;
|
||||
|
||||
var Tool = {
|
||||
Start: function () { _start(); },
|
||||
Stop: function () { _stop(); },
|
||||
Status: function () {
|
||||
if (!Stat.running) return '已停止';
|
||||
return Stat.rawMode + ' ' + Stat.rate + '/s 尖峰' + Math.round(Stat.maxAbs) +
|
||||
' 钳' + Stat.clamped + ' 丢' + Stat.dropped;
|
||||
},
|
||||
GetRunning: function () { return Stat.running; },
|
||||
SetForceRaw: function (On) { Api.setForceRaw(On); },
|
||||
GetForceRaw: function () { return Config.ForceRaw; },
|
||||
SetDropMs: function (Ms) { Api.setDropMs(Ms); },
|
||||
GetDropMs: function () { return Config.DropMs; },
|
||||
SetMaxDelta: function (Px) { Api.setMaxDelta(Px); },
|
||||
GetMaxDelta: function () { return Config.MaxDelta; },
|
||||
GetStatus: function () { return Api.getStatus(); }
|
||||
};
|
||||
|
||||
window.__hornetTools__ = window.__hornetTools__ || {};
|
||||
window.__hornetTools__.Mouse = Tool;
|
||||
console.log('[3DTank] 鼠标稳定模块已加载');
|
||||
})();
|
||||
+145
-15
@@ -13,30 +13,55 @@
|
||||
console.log('已清理旧控制面板');
|
||||
}
|
||||
|
||||
// ===== 通用拖动功能 =====
|
||||
// 通用拖动功能
|
||||
// elem: 要拖动的元素,handle: 触发拖动的元素(默认=elem)
|
||||
// ignoreTags: 点击这些标签时不触发拖动(如 BUTTON)
|
||||
// key: 可选,传入后把窗口位置存到 localStorage(hornet_layout_<key>)并在创建时还原
|
||||
// 实现要点:Pointer Events + setPointerCapture 把指针"锁"在 handle 上,
|
||||
// pointerup/pointercancel 必定回到 handle;并在 window 捕获阶段加兜底,
|
||||
// 避免面板内 stopPropagation 或游戏画布抢事件导致"松手后仍粘着鼠标"。
|
||||
// 返回:{ End, IsActive },供隐藏面板时强制结束拖动
|
||||
function MakeDraggable(elem, handle, ignoreTags) {
|
||||
function MakeDraggable(elem, handle, ignoreTags, key) {
|
||||
handle = handle || elem;
|
||||
ignoreTags = ignoreTags || ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
|
||||
handle.style.cursor = 'move';
|
||||
|
||||
var StorageKey = key ? ('hornet_layout_' + key) : null;
|
||||
|
||||
function ClampX(v) { return Math.max(0, Math.min(window.innerWidth - 40, v)); }
|
||||
function ClampY(v) { return Math.max(0, Math.min(window.innerHeight - 24, v)); }
|
||||
|
||||
// 还原上次保存的位置
|
||||
if (StorageKey) {
|
||||
try {
|
||||
var __saved = localStorage.getItem(StorageKey);
|
||||
if (__saved) {
|
||||
var __p = JSON.parse(__saved);
|
||||
if (__p && typeof __p.left === 'number' && typeof __p.top === 'number') {
|
||||
elem.style.transform = 'none';
|
||||
elem.style.left = ClampX(__p.left) + 'px';
|
||||
elem.style.top = ClampY(__p.top) + 'px';
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function SavePos() {
|
||||
if (!StorageKey) return;
|
||||
try {
|
||||
var r = elem.getBoundingClientRect();
|
||||
localStorage.setItem(StorageKey, JSON.stringify({ left: Math.round(r.left), top: Math.round(r.top) }));
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
var Active = false;
|
||||
var PointerId = null;
|
||||
var GrabX = 0;
|
||||
var GrabY = 0;
|
||||
|
||||
function MoveTo(ClientX, ClientY) {
|
||||
var MaxX = window.innerWidth - 40;
|
||||
var MaxY = window.innerHeight - 24;
|
||||
var NextX = Math.max(0, Math.min(MaxX, ClientX - GrabX));
|
||||
var NextY = Math.max(0, Math.min(MaxY, ClientY - GrabY));
|
||||
elem.style.left = NextX + 'px';
|
||||
elem.style.top = NextY + 'px';
|
||||
elem.style.left = ClampX(ClientX - GrabX) + 'px';
|
||||
elem.style.top = ClampY(ClientY - GrabY) + 'px';
|
||||
}
|
||||
|
||||
function Begin(ClientX, ClientY) {
|
||||
@@ -59,6 +84,7 @@
|
||||
}
|
||||
PointerId = null;
|
||||
handle.style.cursor = 'move';
|
||||
SavePos();
|
||||
}
|
||||
|
||||
function CanStart(Target) {
|
||||
@@ -122,10 +148,67 @@
|
||||
{ key: 'Rearview', label: '后视镜', obj: tools.Rearview },
|
||||
{ key: 'AimWarning', label: '瞄准警告', obj: tools.AimWarning },
|
||||
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
||||
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox }
|
||||
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
||||
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse }
|
||||
];
|
||||
}
|
||||
|
||||
// ===== 工具启用状态(持久化 + 默认启用)=====
|
||||
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
||||
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse'];
|
||||
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true };
|
||||
var ToolEnabled = {};
|
||||
try {
|
||||
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
||||
ToolKeys.forEach(function(k) {
|
||||
ToolEnabled[k] = (typeof __savedEnabled[k] === 'boolean') ? __savedEnabled[k] : ToolDefaults[k];
|
||||
});
|
||||
} catch(e) {
|
||||
ToolKeys.forEach(function(k) { ToolEnabled[k] = ToolDefaults[k]; });
|
||||
}
|
||||
// 把各工具当前的运行状态写回持久化(开关时调用)
|
||||
function SaveToolEnabled() {
|
||||
try {
|
||||
var tools = window.__hornetTools__ || {};
|
||||
ToolKeys.forEach(function(k) {
|
||||
var t = tools[k];
|
||||
if (t && typeof t.GetRunning === 'function') ToolEnabled[k] = !!t.GetRunning();
|
||||
});
|
||||
localStorage.setItem('hornet_tool_enabled', JSON.stringify(ToolEnabled));
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// 需要 ght 才能初始化的工具(要 hook 相机 / GL)——等捕获后再启动,避免失败报错刷屏
|
||||
var GameModeTools = { FreeLook: true, Rearview: true, WarSandbox: true };
|
||||
|
||||
// 自动按保存状态开启:覆盖层(雷达/透视/瞄准)无 ght 也能先开并出 UI;
|
||||
// 每 30 帧检查一次,全部进入运行状态即停
|
||||
var AutoEnableDone = false;
|
||||
var AutoEnableFrame = 0;
|
||||
function TryAutoEnable() {
|
||||
if (AutoEnableDone) return;
|
||||
AutoEnableFrame++;
|
||||
if (AutoEnableFrame % 30 !== 0) return;
|
||||
|
||||
var HasGm = !!window.__gameMode__;
|
||||
var tools = window.__hornetTools__ || {};
|
||||
var pending = 0;
|
||||
ToolKeys.forEach(function(k) {
|
||||
if (!ToolEnabled[k]) return;
|
||||
if (GameModeTools[k] && !HasGm) { pending++; return; } // 等 ght 捕获
|
||||
var t = tools[k];
|
||||
if (!t || typeof t.Start !== 'function') return;
|
||||
if (typeof t.GetRunning === 'function' && t.GetRunning()) return;
|
||||
pending++;
|
||||
try { t.Start(); } catch(e) {}
|
||||
});
|
||||
if (pending === 0) {
|
||||
AutoEnableDone = true;
|
||||
UpdateButtons();
|
||||
console.log('[3DTank] 已按保存状态自动开启工具(覆盖层无 ght 也可先开;后视镜/沙盘/自由视角等 ght 捕获后开)');
|
||||
}
|
||||
}
|
||||
|
||||
// ===== HUD(左上角状态显示,可拖动)=====
|
||||
var hud = document.createElement('div');
|
||||
hud.id = '3dtank-hud';
|
||||
@@ -137,7 +220,7 @@
|
||||
'white-space:pre;line-height:1.6;text-shadow:0 0 3px rgba(125,249,255,0.4);' +
|
||||
'user-select:none;-webkit-user-select:none;box-shadow:0 2px 12px rgba(0,0,0,0.4);';
|
||||
document.body.appendChild(hud);
|
||||
var HudDrag = MakeDraggable(hud);
|
||||
var HudDrag = MakeDraggable(hud, null, null, 'hud');
|
||||
|
||||
// ===== 面板(可拖动,Alt+T 切换)=====
|
||||
var panel = document.createElement('div');
|
||||
@@ -402,6 +485,31 @@
|
||||
if (tools.Radar) tools.Radar.SetOpacity(v);
|
||||
});
|
||||
|
||||
// ===== 鼠标稳定设置 =====
|
||||
// 强制原始输入:游戏锁定失败会静默回退成带 OS 加速的普通锁定,手感会飘
|
||||
// 锁后忽略:锁定刚建立 / 失焦恢复后的头几毫秒位移常是巨幅跳变,直接丢弃
|
||||
// 尖峰钳制:单事件位移超过阈值就截断(0 = 关闭)
|
||||
var mouseSec = MakeSettingsSection('鼠标稳定');
|
||||
var mouseRawCtl = mouseSec.checkbox('强制原始输入', function(on) {
|
||||
var tools = window.__hornetTools__ || {};
|
||||
if (tools.Mouse) tools.Mouse.SetForceRaw(on);
|
||||
});
|
||||
var mouseDropCtl = mouseSec.slider('锁后忽略(ms)', 0, 500, 20, function(v){ return v.toFixed(0); }, function(v) {
|
||||
var tools = window.__hornetTools__ || {};
|
||||
if (tools.Mouse) tools.Mouse.SetDropMs(v);
|
||||
});
|
||||
var mouseClampCtl = mouseSec.slider('尖峰钳制(px)', 0, 1000, 25, function(v){ return v.toFixed(0); }, function(v) {
|
||||
var tools = window.__hornetTools__ || {};
|
||||
if (tools.Mouse) tools.Mouse.SetMaxDelta(v);
|
||||
});
|
||||
(function () { // 回填鼠标模块里已保存的配置
|
||||
var tools = window.__hornetTools__ || {};
|
||||
if (!tools.Mouse) return;
|
||||
mouseRawCtl.set(tools.Mouse.GetForceRaw());
|
||||
mouseDropCtl.set(tools.Mouse.GetDropMs());
|
||||
mouseClampCtl.set(tools.Mouse.GetMaxDelta());
|
||||
})();
|
||||
|
||||
// ===== 后视镜设置 =====
|
||||
var rvSec = MakeSettingsSection('后视镜设置');
|
||||
var rvFovCtl = rvSec.slider('FOV', 0.5, 2.5, 0.05, function(v){ return v.toFixed(2); }, function(v) {
|
||||
@@ -487,7 +595,7 @@
|
||||
|
||||
document.body.appendChild(panel);
|
||||
// 面板通过标题栏拖动
|
||||
var PanelDrag = MakeDraggable(panel, title);
|
||||
var PanelDrag = MakeDraggable(panel, title, null, 'panel');
|
||||
|
||||
// ===== 阻止面板内事件冒泡到 window(防止游戏/工具拦截键盘鼠标)=====
|
||||
// 鼠标事件:面板上所有鼠标事件都阻止冒泡(防止游戏转视角/开炮等)
|
||||
@@ -570,6 +678,7 @@
|
||||
t.obj.Start();
|
||||
}
|
||||
UpdateButtons();
|
||||
SaveToolEnabled();
|
||||
};
|
||||
btnBox.appendChild(btn);
|
||||
|
||||
@@ -620,6 +729,7 @@
|
||||
// ===== 更新 HUD =====
|
||||
function UpdateHud() {
|
||||
requestAnimationFrame(UpdateHud);
|
||||
TryAutoEnable(); // gameMode 捕获后自动按保存状态开启工具
|
||||
var ght = window.__gameMode__;
|
||||
var ghtStatus = ght ? '已捕获' : '未捕获';
|
||||
var ghtColor = ght ? '#7df9ff' : '#f5a623';
|
||||
@@ -688,13 +798,28 @@
|
||||
PanelDrag.End(); // 防止隐藏时拖动状态残留(粘手)
|
||||
}
|
||||
|
||||
// 释放鼠标指针锁定:游戏中鼠标被 Pointer Lock 捕获时指针隐藏、锁定在画布上,
|
||||
// 面板点不到,需退出锁定让光标恢复可交互
|
||||
function ReleasePointerLock() {
|
||||
try {
|
||||
if (document.exitPointerLock && document.pointerLockElement) {
|
||||
document.exitPointerLock();
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function ShowPanel() {
|
||||
panel.style.display = 'block';
|
||||
ReleasePointerLock();
|
||||
UpdateButtons();
|
||||
SyncWfSettings();
|
||||
}
|
||||
|
||||
function TogglePanel() {
|
||||
if (panel.style.display === 'block') {
|
||||
HidePanel();
|
||||
} else {
|
||||
panel.style.display = 'block';
|
||||
UpdateButtons();
|
||||
SyncWfSettings();
|
||||
ShowPanel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,10 +844,15 @@
|
||||
if (tool.GetRunning()) tool.Stop();
|
||||
else tool.Start();
|
||||
UpdateButtons();
|
||||
SaveToolEnabled();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// F5 刷新页面(游戏会吞掉 F5)——捕获阶段兜底,先于游戏处理
|
||||
window.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'F5') { e.preventDefault(); e.stopImmediatePropagation(); location.reload(); }
|
||||
}, true);
|
||||
window.addEventListener('keydown', OnHotkey);
|
||||
// 热键系统定义完成,更新显示
|
||||
UpdateHotkeyDisplay();
|
||||
@@ -730,7 +860,7 @@
|
||||
// ===== 暴露接口 =====
|
||||
window.__hornetPanel__ = {
|
||||
Toggle: TogglePanel,
|
||||
Show: function() { panel.style.display = 'block'; UpdateButtons(); SyncWfSettings(); },
|
||||
Show: ShowPanel,
|
||||
Hide: HidePanel,
|
||||
UpdateButtons: UpdateButtons,
|
||||
RebuildButtons: BuildButtons,
|
||||
|
||||
@@ -50,8 +50,9 @@
|
||||
console.log('[Hornet Prehook] __webpack_require__ 已捕获');
|
||||
console.log('[Hornet Prehook] window.__wp_require__ 就绪');
|
||||
|
||||
// 加载 hornet_bundle.js(默认关闭:URL 加 ?hornet=1 才加载,避免日志遮挡)
|
||||
if (!window.__hornetTools__ && /[?&]hornet=1(&|$)/.test(location.search)) {
|
||||
// 加载 hornet_bundle.js(默认关闭:加 #hornet 才加载)
|
||||
// 务必用 hash:查询串会被游戏当成 config 参数,导致 Hash Request 多出名字、上游关闭连接
|
||||
if (!window.__hornetTools__ && /#hornet/.test(location.hash)) {
|
||||
var s = document.createElement('script');
|
||||
s.src = '/play/static/js/unpacked/hornet_bundle.js';
|
||||
s.onload = function() {
|
||||
|
||||
+64
-15
@@ -6,18 +6,13 @@
|
||||
function _start() {
|
||||
console.log('===== 3DTank雷达启动 =====');
|
||||
|
||||
if (!window.__gameMode__) {
|
||||
console.error('请先运行 hook_gamemode.js');
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== 清理旧雷达 =====
|
||||
// 允许在未进入战局 / ght 尚未捕获时启动:先出雷达框,内容等进入战局再出
|
||||
if (window.__hornetRadar__) {
|
||||
window.__hornetRadar__.stop();
|
||||
console.log('已停止旧雷达');
|
||||
}
|
||||
|
||||
var gm = window.__gameMode__;
|
||||
var gm = window.__gameMode__ || null;
|
||||
|
||||
// ===== 引用公共库(hornet_lib.js) =====
|
||||
var lib = window.__hornetLib__;
|
||||
@@ -34,6 +29,9 @@
|
||||
// 坦克位置:使用公共库
|
||||
var GetTankPosition = lib.GetTankPosition;
|
||||
|
||||
// 坦克状态:使用公共库(0=DEAD,1=DEAD_PHANTOM,2=SEMI_ACTIVE,3=ACTIVE,4=DISABLED)
|
||||
var GetTankState = lib.GetTankState;
|
||||
|
||||
// ===== 获取坦克方向(Kkt 组件的 dzc_1) =====
|
||||
function getTankDirection(tank) {
|
||||
var hullComp = FindComponentByField(tank, 'vzl_1');
|
||||
@@ -128,6 +126,19 @@
|
||||
// 友方判断:使用公共库
|
||||
function IsFriendly(tank, playerTank) { return lib.IsFriendly(tank, playerTank, gm); }
|
||||
|
||||
// 画死亡标记(物理体仍存在但已阵亡):红色 ×
|
||||
function DrawDeadCross(x, y) {
|
||||
var s = 5;
|
||||
ctx.strokeStyle = '#ff4444';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - s, y - s);
|
||||
ctx.lineTo(x + s, y + s);
|
||||
ctx.moveTo(x + s, y - s);
|
||||
ctx.lineTo(x - s, y + s);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// ===== 获取全局碰撞检测器(uMt 组件,挂在 GameMode entity 上) =====
|
||||
var UMtComponent = null;
|
||||
function getUMtComponent() {
|
||||
@@ -412,7 +423,7 @@
|
||||
canvas.height = 320;
|
||||
canvas.style.cssText = 'position:fixed;top:10px;right:10px;z-index:99999;pointer-events:auto;cursor:move;border:2px solid rgba(255,255,255,0.3);border-radius:5px;background:rgba(0,0,0,0.3);box-shadow:0 0 10px rgba(0,0,0,0.3);';
|
||||
document.body.appendChild(canvas);
|
||||
if (lib.MakeDraggable) lib.MakeDraggable(canvas);
|
||||
if (lib.MakeDraggable) lib.MakeDraggable(canvas, 'radar');
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
var cx = canvas.width / 2;
|
||||
@@ -523,13 +534,35 @@
|
||||
|
||||
radar.frameCount++;
|
||||
|
||||
// ===== 新战斗/新地图自刷新:gameMode 实例变化时重置缓存并重新采样地形 =====
|
||||
var NewGm = window.__gameMode__;
|
||||
if (NewGm && NewGm !== gm) {
|
||||
gm = NewGm;
|
||||
UMtComponent = null; // 碰撞检测器需从新场景重新获取
|
||||
radar.lastPlayerPos = null;
|
||||
radar.playerHeading = 0;
|
||||
Terrain.heights = null; // 丢弃旧地图高度图,触发重新采样
|
||||
Terrain.newHeights = null;
|
||||
Terrain.sampling = false;
|
||||
Terrain.ready = false;
|
||||
Terrain.lastSampleX = 99999;
|
||||
Terrain.lastSampleY = 99999;
|
||||
radar.tankCount = 0;
|
||||
console.log('[雷达] 检测到新战斗/新地图,已重置缓存并重新采样地形');
|
||||
}
|
||||
// ght 尚未捕获 / 不在战局:仍画静态雷达框,内容留空(等进入战局自动出)
|
||||
var Ready = !!gm;
|
||||
|
||||
try {
|
||||
var tankList = gm.q100_1.r11l();
|
||||
var count = tankList.e1();
|
||||
var tankList = null, count = 0;
|
||||
if (Ready) {
|
||||
tankList = gm.q100_1.r11l();
|
||||
count = tankList.e1();
|
||||
}
|
||||
radar.tankCount = count;
|
||||
|
||||
// 获取玩家坦克(带备用方案)
|
||||
var playerTank = GetPlayerTank();
|
||||
var playerTank = Ready ? GetPlayerTank() : null;
|
||||
radar.playerFound = (playerTank !== null && playerTank !== undefined);
|
||||
|
||||
// 自由视角激活时,用虚拟相机位置
|
||||
@@ -578,8 +611,8 @@
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// 获取相机朝向(偏航角)
|
||||
var camHeading = getCameraHeading();
|
||||
// 获取相机朝向(偏航角)——仅在战局内
|
||||
var camHeading = Ready ? getCameraHeading() : null;
|
||||
var playerAngle = radar.playerHeading;
|
||||
|
||||
// 自由视角激活时,直接用虚拟相机 yaw(取反:雷达旋转方向与相机yaw相反)
|
||||
@@ -607,7 +640,7 @@
|
||||
if (playerPos) drawTerrain(ctx, playerPos, playerAngle);
|
||||
|
||||
// 绘制所有坦克
|
||||
var friendlyCount = 0, enemyCount = 0;
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var tank = tankList.g1(i);
|
||||
if (!tank) continue;
|
||||
@@ -638,6 +671,14 @@
|
||||
if (radarY < cy - radius) radarY = cy - radius;
|
||||
if (radarY > cy + radius) radarY = cy + radius;
|
||||
|
||||
// 死亡判断(同 3D透视):可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2);其余画红 ×
|
||||
var tankState = GetTankState(tank);
|
||||
if (tankState !== 2 && tankState !== 3) {
|
||||
DrawDeadCross(radarX, radarY);
|
||||
deadCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断友方/敌方
|
||||
var friendly = IsFriendly(tank, playerTank);
|
||||
var color = friendly ? '#4488ff' : '#ff4444';
|
||||
@@ -671,11 +712,19 @@
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('N', cx, cy - radius + 12);
|
||||
|
||||
// 等待战局提示(ght 尚未捕获 / 不在战局)
|
||||
if (!Ready) {
|
||||
ctx.fillStyle = 'rgba(255, 220, 120, 0.95)';
|
||||
ctx.font = 'bold 11px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('等待战局…', cx, cy + 4);
|
||||
}
|
||||
|
||||
// 信息文本
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
|
||||
ctx.font = '9px Arial';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ')', 5, 12);
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ')', 5, 12);
|
||||
if (radar.playerFound) {
|
||||
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
|
||||
} else {
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
uiCanvas.height = Config.height;
|
||||
uiCanvas.style.cssText = 'position:fixed;top:10px;right:10px;width:' + Config.width + 'px;height:' + Config.height + 'px;z-index:99999;border:2px solid rgba(120,200,255,0.6);border-radius:6px;pointer-events:auto;cursor:move;box-shadow:0 0 12px rgba(0,0,0,0.6);opacity:' + RearviewOpacity + ';';
|
||||
document.body.appendChild(uiCanvas);
|
||||
if (lib.MakeDraggable) lib.MakeDraggable(uiCanvas);
|
||||
if (lib.MakeDraggable) lib.MakeDraggable(uiCanvas, 'rearview');
|
||||
var uiCtx = uiCanvas.getContext('2d');
|
||||
|
||||
// ===== UI 绘制函数 =====
|
||||
@@ -563,7 +563,19 @@
|
||||
// ===== 主循环 =====
|
||||
function Loop() {
|
||||
if (!running) return;
|
||||
|
||||
// 换图自刷新:gameMode 实例变化时整体重启,重新获取场景/相机/GL hook
|
||||
var NewGm = window.__gameMode__;
|
||||
if (NewGm && NewGm !== gm) {
|
||||
console.log('[后视] 检测到新战斗,正在重启后视镜...');
|
||||
Stop();
|
||||
_start();
|
||||
return;
|
||||
}
|
||||
|
||||
requestAnimationFrame(Loop);
|
||||
// 旧实例已失效、新实例尚未捕获:跳过本帧
|
||||
if (!window.__gameMode__) return;
|
||||
RenderRearview();
|
||||
}
|
||||
|
||||
|
||||
+70
-12
@@ -1,17 +1,16 @@
|
||||
// ===== 3DTank Hornet Service Worker =====
|
||||
// 功能:拦截 main.*.js 请求,注入 window.__wp_require__ 捕获行
|
||||
// 用途:当无法修改 main 文件、无法预 hook 时,通过网络层注入
|
||||
// 两个职责:
|
||||
//
|
||||
// 使用方法:
|
||||
// 1. 确保 hornet_sw.js 在 /play/static/js/unpacked/ 目录
|
||||
// 2. 在浏览器控制台执行:
|
||||
// navigator.serviceWorker.register('/play/static/js/unpacked/hornet_sw.js')
|
||||
// .then(() => { console.log('SW registered, reload page'); location.reload(); });
|
||||
// 3. 页面刷新后,SW 拦截 main.*.js,注入捕获行
|
||||
// 4. window.__wp_require__ 就绪后,SW 注入 hornet_bundle.js
|
||||
// ① 单包本地缓存(主用途):把 /play/static/js/unpacked/ 下的散装小文件
|
||||
// (126 个 module_*.js + resources.json)用单个 unpacked.pack.json 就地命中,
|
||||
// 不再逐个走磁盘小文件。包由 tools/pack_unpacked.js 生成。
|
||||
// 作用域必须是 /(serve.js 用 Service-Worker-Allowed: / 放行),这样首页 / 发起的
|
||||
// /play/... 请求才能被接管;加载器会自动注册它。
|
||||
//
|
||||
// 卸载方法:
|
||||
// navigator.serviceWorker.getRegistration().then(r => r.unregister()).then(() => location.reload())
|
||||
// ② main.*.js 网络层注入(备用):无法改 main 文件时,往 __webpack_require__ 注入
|
||||
// window.__wp_require__ 捕获行,并追加 hornet_bundle.js 加载。
|
||||
//
|
||||
// 卸载:navigator.serviceWorker.getRegistration().then(r => r.unregister()).then(() => location.reload())
|
||||
|
||||
var SW_DEBUG = '[Hornet SW]';
|
||||
var MAIN_JS_PATTERN = /\/main\.[a-f0-9]+\.js$/;
|
||||
@@ -20,6 +19,52 @@ var INJECT_LINE = 'window.__wp_require__=__webpack_require__;';
|
||||
var BUNDLE_MARKER = '__webpack_require__(78231)';
|
||||
var BUNDLE_INJECT = ';var __hb=document.createElement("script");__hb.src="/play/static/js/unpacked/hornet_bundle.js";document.head.appendChild(__hb);';
|
||||
|
||||
// ===== 单包缓存 =====
|
||||
var PACK_URL = '/play/static/js/unpacked.pack.json';
|
||||
var PACK_PATH_RE = /^\/play\/static\/js\/unpacked\/(module_\d+\.js|resources\.json)$/;
|
||||
var PackPromise = null;
|
||||
var PackMap = null;
|
||||
var PackVersion = '';
|
||||
|
||||
function LoadPack() {
|
||||
if (PackPromise) return PackPromise;
|
||||
PackPromise = fetch(PACK_URL, { cache: 'no-cache' })
|
||||
.then(function (Resp) {
|
||||
if (!Resp.ok) throw new Error('pack HTTP ' + Resp.status);
|
||||
return Resp.json();
|
||||
})
|
||||
.then(function (Pack) {
|
||||
PackMap = Pack.files || {};
|
||||
PackVersion = Pack.version || '';
|
||||
console.log(SW_DEBUG, '单包已载入: ' + (Pack.count || 0) + ' 个文件 版本=' + PackVersion);
|
||||
return PackMap;
|
||||
})
|
||||
.catch(function (Err) {
|
||||
console.warn(SW_DEBUG, '单包载入失败(回退逐文件):', Err && Err.message);
|
||||
PackMap = null;
|
||||
PackPromise = null; // 允许下次重试
|
||||
return null;
|
||||
});
|
||||
return PackPromise;
|
||||
}
|
||||
|
||||
function PackResponse(Name) {
|
||||
if (!PackMap) return null;
|
||||
var Text = PackMap[Name];
|
||||
if (typeof Text !== 'string') return null;
|
||||
var Type = /\.json$/.test(Name)
|
||||
? 'application/json; charset=utf-8'
|
||||
: 'application/javascript; charset=utf-8';
|
||||
return new Response(Text, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': Type,
|
||||
'X-Hornet-Pack': PackVersion,
|
||||
'Cache-Control': 'no-cache',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
self.addEventListener('install', function(event) {
|
||||
self.skipWaiting();
|
||||
});
|
||||
@@ -30,8 +75,21 @@ self.addEventListener('activate', function(event) {
|
||||
|
||||
self.addEventListener('fetch', function(event) {
|
||||
var url = event.request.url;
|
||||
var PathName = '';
|
||||
try { PathName = new URL(url).pathname; } catch (Err) {}
|
||||
|
||||
// 拦截 main.*.js
|
||||
// ① 单包命中:散装小文件(126 个模块 + resources.json)一次读包解决
|
||||
if (PACK_PATH_RE.test(PathName)) {
|
||||
var Name = PathName.slice(PathName.lastIndexOf('/') + 1);
|
||||
event.respondWith(
|
||||
LoadPack().then(function () {
|
||||
return PackResponse(Name) || fetch(event.request); // 包里没有的才回退网络
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ② 拦截 main.*.js
|
||||
if (MAIN_JS_PATTERN.test(url)) {
|
||||
event.respondWith(
|
||||
fetch(event.request).then(function(response) {
|
||||
|
||||
@@ -36,12 +36,16 @@
|
||||
function getTankDirection(tank) {
|
||||
// 从车体皮肤组件(KMt)的Bp节点世界矩阵提取前向方向
|
||||
// dzc_1 是局部空间向量且可能未设置,不可靠
|
||||
var hullComp = FindComponentByField(tank, 't14l_1') ||
|
||||
// 皮肤字段:新 build 是 w14w_1;旧 build 是 t14l_1(新版 t14l_1 已改成悬停车体状态 Qmt)
|
||||
var hullComp = FindComponentByField(tank, 'w14w_1') ||
|
||||
FindComponentByField(tank, 't14l_1') ||
|
||||
FindComponentByField(tank, 'u14l_1') ||
|
||||
FindComponentByField(tank, 'p14l_1');
|
||||
if (!hullComp || !hullComp.t14l_1) return null;
|
||||
var skin = hullComp.t14l_1;
|
||||
if (!skin || !skin.s17b_1) return null;
|
||||
if (!hullComp) return null;
|
||||
var skin = (hullComp.w14w_1 && hullComp.w14w_1.s17b_1) ? hullComp.w14w_1 :
|
||||
(hullComp.t14l_1 && hullComp.t14l_1.s17b_1) ? hullComp.t14l_1 :
|
||||
(hullComp.p14l_1 && hullComp.p14l_1.s17b_1) ? hullComp.p14l_1 : null;
|
||||
if (!skin) return null;
|
||||
try {
|
||||
var partCount = skin.s17b_1.e1();
|
||||
for (var p = 0; p < partCount; p++) {
|
||||
@@ -51,8 +55,8 @@
|
||||
for (var n = 0; n < nodeCount; n++) {
|
||||
var bpNode = part.v17b_1.g1(n);
|
||||
if (!bpNode || !bpNode.n35_1) continue;
|
||||
// 跳过幽灵节点(z34_1 < 0.9)
|
||||
if (bpNode.g35_1 !== undefined && bpNode.g35_1 < 0.9) continue;
|
||||
// 不按 g35_1 过滤:它是引擎的细节/淡出权重(0~1),不是幽灵标志,
|
||||
// 过滤会漏掉低细节节点、导致取不到朝向
|
||||
var m = bpNode.n35_1;
|
||||
// 列主序世界矩阵:Col0=(m[0],m[1],m[2]) Col1=(m[4],m[5],m[6]) Col2=(m[8],m[9],m[10])
|
||||
// 游戏坐标:x,y 水平面; z(h20_1)=高度。找"上"列(|z|最大),其余为水平方向
|
||||
@@ -132,6 +136,30 @@
|
||||
'user-select:none;-webkit-user-select:none;';
|
||||
document.body.appendChild(container);
|
||||
|
||||
// ===== 窗口布局持久化(位置 + 尺寸)=====
|
||||
function SaveWinLayout() {
|
||||
try {
|
||||
var r = container.getBoundingClientRect();
|
||||
localStorage.setItem('hornet_layout_warsandbox', JSON.stringify({
|
||||
left: Math.round(r.left), top: Math.round(r.top),
|
||||
width: Math.round(r.width), height: Math.round(r.height)
|
||||
}));
|
||||
} catch(e) {}
|
||||
}
|
||||
try {
|
||||
var __wsSaved = localStorage.getItem('hornet_layout_warsandbox');
|
||||
if (__wsSaved) {
|
||||
var __wsP = JSON.parse(__wsSaved);
|
||||
if (__wsP && typeof __wsP.left === 'number' && typeof __wsP.top === 'number') {
|
||||
container.style.transform = 'none';
|
||||
container.style.left = Math.max(0, __wsP.left) + 'px';
|
||||
container.style.top = Math.max(0, __wsP.top) + 'px';
|
||||
if (typeof __wsP.width === 'number') container.style.width = Math.max(320, __wsP.width) + 'px';
|
||||
if (typeof __wsP.height === 'number') container.style.height = Math.max(240, __wsP.height) + 'px';
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
var titleBar = document.createElement('div');
|
||||
titleBar.style.cssText =
|
||||
'display:flex;justify-content:space-between;align-items:center;padding:10px 16px;' +
|
||||
@@ -168,6 +196,29 @@
|
||||
}
|
||||
resizeCanvas();
|
||||
|
||||
// ===== 右下角缩放手柄:允许自由缩放窗口 =====
|
||||
var resizeGrip = document.createElement('div');
|
||||
resizeGrip.style.cssText =
|
||||
'position:absolute;right:0;bottom:0;width:18px;height:18px;cursor:nwse-resize;z-index:2;' +
|
||||
'background:linear-gradient(135deg,transparent 45%,rgba(125,249,255,0.35) 45%);' +
|
||||
'border-bottom-right-radius:12px;';
|
||||
container.appendChild(resizeGrip);
|
||||
|
||||
var __rsx = 0, __rsy = 0, __rsw = 0, __rsh = 0;
|
||||
BindPointerDrag(resizeGrip, function(e) {
|
||||
var r = container.getBoundingClientRect();
|
||||
__rsx = e.clientX; __rsy = e.clientY; __rsw = r.width; __rsh = r.height;
|
||||
return true;
|
||||
}, function(e) {
|
||||
container.style.transform = 'none';
|
||||
container.style.width = Math.max(320, __rsw + (e.clientX - __rsx)) + 'px';
|
||||
container.style.height = Math.max(240, __rsh + (e.clientY - __rsy)) + 'px';
|
||||
resizeCanvas();
|
||||
}, function() {
|
||||
resizeCanvas();
|
||||
SaveWinLayout();
|
||||
});
|
||||
|
||||
// ===== FBO 创建 =====
|
||||
var sandboxFbo = null, sandboxTex = null, sandboxDepthRb = null;
|
||||
var pixels = new Uint8Array(FBO_W * FBO_H * 4);
|
||||
@@ -314,7 +365,7 @@
|
||||
var nx = Math.max(0, Math.min(window.innerWidth - 100, dwx + e.clientX - dsx));
|
||||
var ny = Math.max(0, Math.min(window.innerHeight - 40, dwy + e.clientY - dsy));
|
||||
container.style.left = nx + 'px'; container.style.top = ny + 'px';
|
||||
}, function() {});
|
||||
}, function() { SaveWinLayout(); });
|
||||
|
||||
// ===== 地图平移 =====
|
||||
var psx = 0, psy = 0, pcx = 0, pcy = 0;
|
||||
@@ -580,7 +631,19 @@
|
||||
|
||||
function render() {
|
||||
if (!running) return;
|
||||
|
||||
// 换图自刷新:gameMode 实例变化时整体重启,重新获取场景/相机/GL hook
|
||||
var NewGm = window.__gameMode__;
|
||||
if (NewGm && NewGm !== gm) {
|
||||
console.log('[沙盘] 检测到新战斗,正在重启战争沙盘...');
|
||||
self.Stop();
|
||||
_start();
|
||||
return;
|
||||
}
|
||||
|
||||
frameCount++;
|
||||
// 旧实例已失效、新实例尚未捕获:跳过本帧
|
||||
if (!window.__gameMode__) { rafId = requestAnimationFrame(render); return; }
|
||||
var cw = canvas.width, ch = canvas.height;
|
||||
|
||||
// 初始化视图中心
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// pack_unpacked.js — 把切割产物打成单个包,减少「一堆小文件」的请求开销
|
||||
//
|
||||
// 打包对象:3dtank.com/play/static/js/unpacked/ 下的
|
||||
// · module_*.js (126 个代码模块)
|
||||
// · resources.json (资源映射表)
|
||||
// 产物:3dtank.com/play/static/js/unpacked.pack.json
|
||||
// { version, base, files: { "<文件名>": "<内容>" } }
|
||||
// version = 文件名+内容的 sha1,用于 SW 缓存版本号(内容不变则版本不变)
|
||||
//
|
||||
// 谁在用:
|
||||
// 1) 加载器(main.*.js)优先读这个包,一次请求拿到全部模块(失败才回退逐文件 fetch)
|
||||
// 2) hornet_sw.js 用它把 /play/static/js/unpacked/* 的请求就地命中(不再走磁盘小文件)
|
||||
//
|
||||
// 用法:node pack_unpacked.js [unpacked目录] [输出文件]
|
||||
// 不带参数时默认打包 ../../../3dtank.com/play/static/js/unpacked
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const DEFAULT_DIR = path.resolve(__dirname, '..', '3dtank.com', 'play', 'static', 'js', 'unpacked');
|
||||
const UNPACKED_DIR = process.argv[2] ? path.resolve(process.argv[2]) : DEFAULT_DIR;
|
||||
const OUT_FILE = process.argv[3]
|
||||
? path.resolve(process.argv[3])
|
||||
: path.join(path.dirname(UNPACKED_DIR), 'unpacked.pack.json');
|
||||
|
||||
function main() {
|
||||
if (!fs.existsSync(UNPACKED_DIR)) {
|
||||
console.error('[ERROR] 目录不存在: ' + UNPACKED_DIR);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const Names = fs
|
||||
.readdirSync(UNPACKED_DIR)
|
||||
.filter((N) => /^module_\d+\.js$/.test(N) || N === 'resources.json')
|
||||
.sort();
|
||||
|
||||
if (Names.length === 0) {
|
||||
console.error('[ERROR] 没找到 module_*.js / resources.json(先跑 split.js 切割)');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const Hash = crypto.createHash('sha1');
|
||||
const Files = {};
|
||||
let Total = 0;
|
||||
for (const Name of Names) {
|
||||
const Text = fs.readFileSync(path.join(UNPACKED_DIR, Name), 'utf8');
|
||||
Files[Name] = Text;
|
||||
Hash.update(Name).update('\u0000').update(Text);
|
||||
Total += Buffer.byteLength(Text, 'utf8');
|
||||
}
|
||||
|
||||
const Pack = {
|
||||
version: Hash.digest('hex').slice(0, 16),
|
||||
base: '/play/static/js/unpacked/',
|
||||
count: Names.length,
|
||||
files: Files,
|
||||
};
|
||||
const Json = JSON.stringify(Pack);
|
||||
fs.writeFileSync(OUT_FILE, Json);
|
||||
|
||||
console.log('[OK] 打包 ' + Names.length + ' 个文件 ' + (Total / 1048576).toFixed(2) + ' MB');
|
||||
console.log(' 版本: ' + Pack.version);
|
||||
console.log(' 输出: ' + OUT_FILE + ' (' + (Json.length / 1048576).toFixed(2) + ' MB)');
|
||||
}
|
||||
|
||||
main();
|
||||
+96
-14
@@ -240,10 +240,33 @@ function tryExtractResource(valueSrc) {
|
||||
window.__modules__ = {};
|
||||
const __base_url__ = window.__script_base_url__ || './';
|
||||
|
||||
// 6.1 加载资源模块 (从 resources.json 批量注册)
|
||||
const __resource_resp__ = await fetch(__base_url__ + 'unpacked/resources.json');
|
||||
if (!__resource_resp__.ok) throw new Error('resources.json load failed: HTTP ' + __resource_resp__.status);
|
||||
const __resource_data__ = await __resource_resp__.json();
|
||||
// 6.0 单包(unpacked.pack.json):一次请求拿到 resources.json + 全部代码模块,
|
||||
// 避免 126 个小文件碎请求;没有包时自动回退逐文件加载(见 6.2)
|
||||
const __pack_files__ = await (async () => {
|
||||
try {
|
||||
const __pack_resp__ = await fetch(__base_url__ + 'unpacked.pack.json', { cache: 'no-cache' });
|
||||
if (!__pack_resp__.ok) {
|
||||
console.warn('[Hornet] 单包不可用(HTTP ' + __pack_resp__.status + '),回退逐文件加载');
|
||||
return null;
|
||||
}
|
||||
const __pack__ = await __pack_resp__.json();
|
||||
console.log('[Hornet] 单包已载入: ' + (__pack__.count || 0) + ' 个文件 版本=' + __pack__.version);
|
||||
return __pack__.files || null;
|
||||
} catch (__pack_err__) {
|
||||
console.warn('[Hornet] 单包不可用,回退逐文件加载: ' + (__pack_err__ && __pack_err__.message));
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
// 6.1 加载资源模块 (resources.json;优先从单包里取)
|
||||
let __resource_data__ = null;
|
||||
if (__pack_files__ && typeof __pack_files__['resources.json'] === 'string') {
|
||||
__resource_data__ = JSON.parse(__pack_files__['resources.json']);
|
||||
} else {
|
||||
const __resource_resp__ = await fetch(__base_url__ + 'unpacked/resources.json');
|
||||
if (!__resource_resp__.ok) throw new Error('resources.json load failed: HTTP ' + __resource_resp__.status);
|
||||
__resource_data__ = await __resource_resp__.json();
|
||||
}
|
||||
const __resource_map__ = __resource_data__.resourceMap;
|
||||
for (const __id__ in __resource_map__) {
|
||||
if (!Object.prototype.hasOwnProperty.call(__resource_map__, __id__)) continue;
|
||||
@@ -257,16 +280,25 @@ for (const __id__ in __resource_map__) {
|
||||
})(__path__);
|
||||
}
|
||||
|
||||
// 6.2 加载代码模块 (fetch + eval 独立文件)
|
||||
// 6.2 加载代码模块:单包命中直接 eval(无网络请求);缺的/没包时回退逐文件 fetch
|
||||
const __code_ids__ = [${codeIdsArrayLiteral}];
|
||||
await Promise.all(__code_ids__.map(async (__id__) => {
|
||||
const __padded__ = typeof __id__ === 'number' ? String(__id__).padStart(5, '0') : __id__;
|
||||
const __url__ = __base_url__ + 'unpacked/module_' + __padded__ + '.js';
|
||||
const __resp__ = await fetch(__url__);
|
||||
if (!__resp__.ok) throw new Error('Module ' + __id__ + ' load failed: HTTP ' + __resp__.status + ' @ ' + __url__);
|
||||
const __code__ = await __resp__.text();
|
||||
(0, eval)(__code__);
|
||||
}));
|
||||
const __mod_name__ = (__id__) => 'module_' + (typeof __id__ === 'number' ? String(__id__).padStart(5, '0') : __id__) + '.js';
|
||||
const __missing__ = [];
|
||||
for (const __id__ of __code_ids__) {
|
||||
const __name__ = __mod_name__(__id__);
|
||||
const __src__ = __pack_files__ ? __pack_files__[__name__] : null;
|
||||
if (typeof __src__ === 'string') (0, eval)(__src__);
|
||||
else __missing__.push(__id__);
|
||||
}
|
||||
if (__missing__.length) {
|
||||
if (__pack_files__) console.warn('[Hornet] 单包缺少 ' + __missing__.length + ' 个模块,回退逐文件加载');
|
||||
await Promise.all(__missing__.map(async (__id__) => {
|
||||
const __url__ = __base_url__ + 'unpacked/' + __mod_name__(__id__);
|
||||
const __resp__ = await fetch(__url__);
|
||||
if (!__resp__.ok) throw new Error('Module ' + __id__ + ' load failed: HTTP ' + __resp__.status + ' @ ' + __url__);
|
||||
(0, eval)(await __resp__.text());
|
||||
}));
|
||||
}
|
||||
|
||||
var __webpack_modules__ = window.__modules__;
|
||||
`;
|
||||
@@ -277,8 +309,43 @@ var __webpack_modules__ = window.__modules__;
|
||||
// ===== 暴露 webpack require(hornet 工具链 hook_gamemode/hornet_lib 依赖)=====
|
||||
window.__wp_require__ = __webpack_require__;
|
||||
|
||||
// ===== 加载 hornet_bundle(默认关闭:URL 加 ?hornet=1 才加载,避免日志遮挡)=====
|
||||
// ===== 出错时不自动刷新页面 =====
|
||||
// 游戏在致命错误/断线后会调用 location.reload(),err toast 一闪就被刷掉、看不到原因。
|
||||
// 拦截自动刷新并保留页面:① 接管 location.reload;② 不可写时用 beforeunload 守卫兜底。
|
||||
// 需要刷新时按 F5:先放行一次守卫,再用原始 reload 真正刷新。
|
||||
var __hornetRealReload__ = window.location.reload.bind(window.location);
|
||||
var __reloadHijacked__ = false;
|
||||
try {
|
||||
window.location.reload = function () {
|
||||
console.warn('[Hornet] 已拦截自动刷新(保留页面,便于查看 err toast)。调用栈:\n' + new Error().stack);
|
||||
};
|
||||
__reloadHijacked__ = (window.location.reload !== __hornetRealReload__);
|
||||
} catch (__reloadErr__) { __reloadHijacked__ = false; }
|
||||
window.addEventListener('beforeunload', function (e) {
|
||||
if (window.__hornetAllowUnload__) { window.__hornetAllowUnload__ = false; return; }
|
||||
if (__reloadHijacked__) return;
|
||||
e.preventDefault();
|
||||
e.returnValue = '';
|
||||
});
|
||||
console.log('[Hornet] 自动刷新拦截: ' + (__reloadHijacked__ ? 'location.reload 已接管' : 'beforeunload 守卫'));
|
||||
|
||||
// ===== F5 刷新页面(游戏会吞掉 F5,这里在捕获阶段兜底)=====
|
||||
window.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'F5') {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
window.__hornetAllowUnload__ = true;
|
||||
__hornetRealReload__();
|
||||
}
|
||||
}, true);
|
||||
|
||||
// ===== 加载 hornet_bundle(默认加载;纯净页面用 #nohornet)=====
|
||||
// 开关必须用 hash,不能用查询串:游戏在 module_13431 里把 location.search 的所有查询参数
|
||||
// 注册成 config 参数,于是 ?hornet=1 会让 Hash Request 多出资源名 "hornet",真实服务器直接关闭连接(1005)。
|
||||
if (/[?&]hornet=1(&|$)/.test(location.search)) {
|
||||
console.warn('[Hornet] 请勿使用 ?hornet=1:查询参数会被游戏当成 config 参数,导致上游握手失败(1005)');
|
||||
}
|
||||
if (!/#nohornet/.test(location.hash) && !window.__hornetTools__) {
|
||||
try {
|
||||
const __hornet_url__ = __base_url__ + 'unpacked/hornet_bundle.js';
|
||||
const __hornet_resp__ = await fetch(__hornet_url__);
|
||||
@@ -294,6 +361,21 @@ var __webpack_modules__ = window.__modules__;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 注册 Service Worker(仅本机镜像)
|
||||
// 作用域必须是 /:首页 / 发起的 /play/... 请求才会被接管(serve.js 放行 Service-Worker-Allowed)
|
||||
// 用途:把 unpacked 下的散装小文件用单包就地命中(hornet_sw.js 内置单包缓存)
|
||||
if ('serviceWorker' in navigator && /^(localhost|127\\.0\\.0\\.1|\\[::1\\])$/.test(location.hostname)) {
|
||||
navigator.serviceWorker
|
||||
.register('/hornet_sw.js', { scope: '/', updateViaCache: 'none' })
|
||||
.then(function (Reg) {
|
||||
console.log('[Hornet] Service Worker 就绪(作用域 ' + Reg.scope + '),unpacked 小文件将由单包命中');
|
||||
return Reg.update();
|
||||
})
|
||||
.catch(function (Err) {
|
||||
console.warn('[Hornet] Service Worker 注册失败: ' + (Err && Err.message));
|
||||
});
|
||||
}
|
||||
|
||||
`
|
||||
: '';
|
||||
let runtimeWithHornet = runtimeCode;
|
||||
|
||||
Reference in new issue
Block a user