2024-10-22 09:17:28 +08:00

440 lines
16 KiB
JavaScript

var WXAssetBundleLibrary = {
$WXFS: {},
WXFSInit: function (ttl, capacity) {
function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var WXMap = /*#__PURE__*/function () {
function WXMap(hash, rename) {
_classCallCheck(this, WXMap);
this.hash = hash;
this.rename = rename;
this.size = 0;
}
_createClass(WXMap, [{
key: "get",
value: function get(key) {
return this.hash.get(this.rename(key));
}
}, {
key: "set",
value: function set(key, value) {
this.delete(key);
this.size += value;
return this.hash.set(this.rename(key), value);
}
}, {
key: "has",
value: function has(key) {
return this.hash.has(this.rename(key));
}
}, {
key: "delete",
value: function _delete(key) {
this.size -= this.hash.get(this.rename(key))|0;
return this.hash.delete(this.rename(key));
}
}]);
return WXMap;
}();
WXFS.WXABErrorSteps = {
"kWebRequestResponse": 0,
"kLoadBundleFromFile": 1,
"kCacheGet" : 2
};
WXFS.disk = new WXMap(unityNamespace.WXAssetBundles,unityNamespace.PathInFileOS);
WXFS.msg = "";
WXFS.fd2wxStream = new Map;
WXFS.path2fd = new Map;
WXFS.fs = wx.getFileSystemManager();
WXFS.nowfd = FS.MAX_OPEN_FDS + 1;
WXFS.isWXAssetBundle = function(url){
if(WXFS._url2path.has(url)||url.startsWith(GameGlobal.unityNamespace.DATA_CDN)||url.startsWith('/vfs_streamingassets')){
return unityNamespace.isWXAssetBundle(WXFS.url2path(url));
}
return unityNamespace.isWXAssetBundle(url);
}
WXFS.newfd = function(){
return WXFS.nowfd++;
}
WXFS.doWXAccess = function(path, amode){
if (amode & ~7) {
return -28;
}
try{
WXFS.fs.accessSync(path);
} catch(e){
return -44;
}
return 0
}
var WXFileCache = /*#__PURE__*/function () {
function WXFileCache(ttl, capacity) {
_classCallCheck(this, WXFileCache);
this.ttl = ttl;
if (capacity > 0) this.capacity = capacity;
this.hash = new Map();
this.size = 0;
this.maxSize = 0;
this.obsolete = "";
}
// record obsolete file path when file not found
_createClass(WXFileCache, [{
key: "record",
value: function record(path) {
if (!this.obsolete.includes(path)) {
if (this.obsolete != "") this.obsolete += ";";
this.obsolete += path;
}
}
}, {
key: "get",
value: function get(key) {
var temp = this.hash.get(key);
if (temp !== undefined) {
if(temp.cleanable && unityNamespace.isAndroid && temp.time + this.ttl * 1000 < Date.now()){
try {
var check_path = WXFS.fd2wxStream.get(key).path
if(!GameGlobal.manager.getCachePath(check_path)){
throw new Error("No such file in the wx cache system")
}
WXFS.fs.statSync(check_path)
} catch (e) {
GameGlobal.manager.reporter.wxAssetBundle.reportEmptyContent({stage: WXFS.WXABErrorSteps['kCacheGet'], path: check_path, error: !!e ? e.toString() : 'unknown'});
GameGlobal.manager.Logger.pluginLog('[WXAssetBundle]Android statSync path: ' + check_path + ' error: ' + (!!e ? e.toString() : 'unknown'));
}
}
this.hash.delete(key);
temp.time = Date.now();
this.hash.set(key, temp);
return temp.ab;
}
return -1;
}
}, {
key: "put",
value: function put(key, ab, cleanable) {
if(!ab)return;
cleanable = cleanable != undefined ? cleanable : true;
var value = {
ab: ab,
time: Date.now(),
cleanable: cleanable
};
var temp = this.hash.get(key);
if (temp !== undefined) {
this.size -= temp.ab.byteLength;
this.hash.delete(key);
this.hash.set(key, value);
} else {
if (this.capacity !== undefined && this.size >= this.capacity) {
var idx = this.hash.keys().next().value;
this.size -= idx.ab.byteLength;
this.hash.delete(idx);
this.hash.set(key, value);
} else {
this.hash.set(key, value);
}
}
this.size += value.ab.byteLength;
this.maxSize = Math.max(this.size, this.maxSize);
}
}, {
key: "cleanable",
value: function cleanable(key, _cleanable) {
_cleanable = _cleanable != undefined ? _cleanable : true;
var temp = this.hash.get(key);
if (temp !== undefined) {
// this.hash.delete(key);
// temp.time = Date.now();
temp.cleanable = _cleanable;
this.hash.set(key, temp);
return 0;
} else {
return -1;
}
}
}, {
key: "cleanbytime",
value: function cleanbytime(deadline) {
var iter = this.hash.keys(),
key,
value;
while ((key = iter.next().value) != undefined && (value = this.hash.get(key)).time < deadline) {
if (value.cleanable) {
this.size -= value.ab.byteLength;
this.hash.delete(key);
}
}
}
}, {
key: "RegularCleaning",
value: function RegularCleaning(kIntervalSecond) {
var _this = this;
setInterval(function () {
_this.cleanbytime(Date.now() - _this.ttl * 1000);
}, kIntervalSecond * 1000);
}
}, {
key: "delete",
value: function _delete(key) {
this.size -= this.hash.get(key).ab.byteLength;
return this.hash.delete(key)
}
}, {
key: "has",
value: function _has(key) {
return this.hash.has(key)
}
}
]);
return WXFileCache;
}();
WXFS.cache = new WXFileCache(ttl, capacity);
if(!unityNamespace.isAndroid) {
WXFS.cache.RegularCleaning(1);
}
WXFS.wxstat = function(path){
try {
var fd = WXFS.path2fd.get(path)
if (fd !== undefined){
var stat = {
mode: 33206,
size: WXFS.cache.get(fd).byteLength,
dev: 1,
ino: 1,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
atime: new Date(),
mtime: new Date(0),
ctime: new Date(),
blksize: 4096
}
stat.blocks = Math.ceil(stat.size / stat.blksize);
return stat;
}
var stat = WXFS.fs.statSync(path);
// something not in wx.FileSystemManager, just fill in 0/1
stat.dev = 1;
stat.ino = 1;
stat.nlink = 1;
stat.uid = 0;
stat.gid = 0;
stat.rdev = 0;
stat.atime = new Date(stat.lastAccessedTime * 1000);
stat.mtime = new Date(0); // if update modified time, wasm will log error "Archive file was modified when opened"
stat.ctime = new Date(stat.lastModifiedTime * 1000); // time of permission modification, just use mtime to instand
delete stat.lastAccessedTime;
delete stat.lastModifiedTime;
stat.blksize = 4096;
stat.blocks = Math.ceil(stat.size / stat.blksize);
return stat;
} catch (e){
console.error(e)
throw e;
}
}
WXFS._url2path = new Map();
WXFS.url2path = function(url) {
if(WXFS._url2path.has(url)){
return WXFS._url2path.get(url);
}
url = url.replaceAll(' ', '%20')
if(url.startsWith('/vfs_streamingassets/')){
var path = url.replace('/vfs_streamingassets/', wx.env.USER_DATA_PATH + "/__GAME_FILE_CACHE/StreamingAssets/");
}
else{
var path = url.replace(GameGlobal.unityNamespace.DATA_CDN, wx.env.USER_DATA_PATH+'/__GAME_FILE_CACHE/');
}
if(path.indexOf('?') > -1){
path = path.substring(0,path.indexOf("?"));
}
WXFS._url2path.set(url, path);
return path;
};
WXFS.LoadBundleFromFile = function(path){
try {
var res = WXFS.fs.readFileSync(path);
} catch(e) {
var err_msg = !!e ? e.toString() : 'unknown';
}
var expected_size = WXFS.disk.get(path);
if(!res || res.byteLength != expected_size){
var wxab_error = {
stage: WXFS.WXABErrorSteps['kLoadBundleFromFile'],
path: path,
size: (!!res ? res.byteLength : 0),
expected_size: expected_size,
error: err_msg
};
GameGlobal.manager.reporter.wxAssetBundle.reportEmptyContent(wxab_error);
GameGlobal.manager.Logger.pluginLog('[WXAssetBundle]readFileSync at path ' + path + ' return size ' + (!!res?res.byteLength:0) + ', different from expected size ' + expected_size + ' error: ' + err_msg);
wx.setStorageSync("wxfs_unserviceable",true);
GameGlobal.onCrash();
return "";
}
return res;
};
WXFS.read = function(stream, buffer, offset, length, position){
var contents = WXFS.cache.get(stream.fd);
if (contents === -1) {
var res = WXFS.LoadBundleFromFile(stream.path);
WXFS.cache.put(stream.fd, res);
contents = res;
}
if (position >= stream.node.usedBytes) return 0;
var size = Math.min(stream.node.usedBytes - position, length);
assert(size >= 0);
buffer.set(new Uint8Array(contents.slice(position, position + size)), offset);
return size;
};
},
GetObsoleteFilePath: function () {
var bufferSize = lengthBytesUTF8(WXFS.cache.obsolete) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(WXFS.cache.obsolete, buffer, bufferSize);
WXFS.cache.obsolete = "";
return buffer;
},
UnCleanbyPath: function (ptr) {
var url = UTF8ToString(ptr);
var path = WXFS.url2path(url);
if(!WXFS.disk.has(path)){
WXFS.disk.set(path, 0);
}
},
UnloadbyPath: function (ptr) {
var path = WXFS.url2path(UTF8ToString(ptr));
var fd = WXFS.path2fd.get(path);
if(WXFS.cache.has(fd)){
WXFS.cache.delete(fd);
}
if(WXFS.disk.has(path)){
WXFS.disk.delete(path);
}
},
CheckWXFSReady: function () {
return WXFS.fs!==undefined;
},
WXGetBundleFromXML: function(url, id, callback, needRetry){
needRetry = needRetry?needRetry:true;
var _url = UTF8ToString(url);
var _id = UTF8ToString(id);
var len = lengthBytesUTF8(_id) + 1;
var idPtr = _malloc(len);
stringToUTF8(_id, idPtr, len);
var xhr = new GameGlobal.unityNamespace.UnityLoader.UnityCache.XMLHttpRequest;
xhr.open('GET', _url, true);
xhr.responseType = "arraybuffer";
xhr.onload = function (e) {
if (xhr.status >= 400 && needRetry) {
setTimeout(function () {
_WXGetBundleFromXML(url, false);
}, 1000);
xhr=null;
return false;
}
if (callback) {
var kWebRequestOK = 0;
var kNoResponseBuffer = 1111;
var xhrByteArray = new Uint8Array(xhr.response);
if (xhrByteArray.length != 0) {
var arrayBuffer = xhr.response;
var path = WXFS.url2path(_url);
var numberfd = WXFS.path2fd.get(path);
if (numberfd == undefined) {
numberfd = WXFS.newfd();
WXFS.path2fd.set(path, numberfd);
}
var wxStream = WXFS.fd2wxStream.get(numberfd);
if (wxStream == undefined) {
wxStream = {
fd: numberfd,
path: path,
seekable: true,
position: 0,
stream_ops: MEMFS.stream_ops,
ungotten: [],
node:{mode:32768,usedBytes:xhrByteArray.length},
error: false
};
wxStream.stream_ops.read = WXFS.read;
WXFS.fd2wxStream.set(numberfd, wxStream);
}
WXFS.cache.put(numberfd, arrayBuffer, xhr.isReadFromCache);
WXFS.disk.set(path, xhrByteArray.length);
dynCall("viii", callback, [idPtr, kWebRequestOK, 0]);
if(xhr.isReadFromCache){
_free(idPtr);
}
} else {
dynCall('viii', callback, [idPtr, kNoResponseBuffer, 0]);
_free(idPtr);
}
}
};
xhr.onsave = function xhr_onsave(e){
WXFS.cache.cleanable(WXFS.path2fd.get(e));
_free(idPtr);
}
function XHRHandleError(err, code) {
if (needRetry) {
return setTimeout(function () {
_WXGetBundleFromXML(url, false);
}, 1e3);
}
if (callback) {
var len = lengthBytesUTF8(err) + 1;
var buffer = _malloc(len);
stringToUTF8(err, buffer, len);
dynCall("viii", callback, [idPtr, code, buffer]);
_free(buffer);
_free(idPtr);
}
}
xhr.onerror = function xhr_onerror(e) {
var kWebErrorUnknown = 2;
XHRHandleError("Unknown error.", kWebErrorUnknown);
};
xhr.ontimeout = function xhr_onerror(e) {
var kWebErrorTimeout = 14;
XHRHandleError("Connection timed out.", kWebErrorTimeout);
};
xhr.onabort = function xhr_onerror(e) {
var kWebErrorAborted = 17;
XHRHandleError("Aborted.", kWebErrorAborted);
}
xhr.send();
},
WXGetBundleNumberInMemory: function () {
return WXFS&&WXFS.cache&&WXFS.cache.hash&&WXFS.cache.hash.size;
},
WXGetBundleNumberOnDisk: function () {
return WXFS&&WXFS.disk&&WXFS.disk.hash&&WXFS.disk.hash.size;
},
WXGetBundleSizeInMemory: function () {
return WXFS&&WXFS.cache&&WXFS.cache.size;
},
WXGetBundleSizeOnDisk: function () {
return WXFS&&WXFS.disk&&WXFS.disk.size;
}
};
autoAddDeps(WXAssetBundleLibrary, '$WXFS');
mergeInto(LibraryManager.library, WXAssetBundleLibrary);