Skip to content

Commit c06a2df

Browse files
authored
Merge pull request #78 from rpgtkoolmv/add_retry
add retry loading system
2 parents 9423cac + c35814b commit c06a2df

File tree

11 files changed

+231
-15
lines changed

11 files changed

+231
-15
lines changed

js/rpg_core/Bitmap.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -791,11 +791,15 @@ Bitmap.prototype.decode = function(){
791791
this._callLoadListeners();
792792
break;
793793

794-
case 'requesting': case 'decrypting':
794+
case 'requesting': case 'decrypting':
795795
this._decodeAfterRequest = true;
796+
if (!this._loader) {
797+
this._loader = ResourceHandler.createLoader(this._url, this._requestImage.bind(this, this._url), this._onError.bind(this));
798+
this._image.onerror = this._loader;
799+
}
796800
break;
797801

798-
case 'pending':
802+
case 'pending': case 'error':
799803
this._decodeAfterRequest = true;
800804
this._requestImage(this._url);
801805
break;
@@ -849,6 +853,9 @@ Bitmap.request = function(url){
849853
};
850854

851855
Bitmap.prototype._requestImage = function(url){
856+
if (this._decodeAfterRequest && !this._loader) {
857+
this._loader = ResourceHandler.createLoader(url, this._requestImage.bind(this, url), this._onError.bind(this));
858+
}
852859
this._image = new Image();
853860
this._url = url;
854861
this._loadingState = 'requesting';
@@ -859,7 +866,7 @@ Bitmap.prototype._requestImage = function(url){
859866
} else {
860867
this._image.src = url;
861868
this._image.onload = Bitmap.prototype._onLoad.bind(this);
862-
this._image.onerror = Bitmap.prototype._onError.bind(this);
869+
this._image.onerror = this._loader || Bitmap.prototype._onError.bind(this);
863870
}
864871
};
865872

js/rpg_core/Decrypter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Decrypter.decryptImg = function(url, bitmap) {
3636
var arrayBuffer = Decrypter.decryptArrayBuffer(requestFile.response);
3737
bitmap._image.src = Decrypter.createBlobUrl(arrayBuffer);
3838
bitmap._image.onload = Bitmap.prototype._onLoad.bind(bitmap);
39-
bitmap._image.onerror = Bitmap.prototype._onError.bind(bitmap);
39+
bitmap._image.onerror = bitmap._loader || Bitmap.prototype._onError.bind(bitmap);
4040
}
4141
};
4242
};

js/rpg_core/Graphics.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Graphics.initialize = function(width, height, type) {
3232
this._scale = 1;
3333
this._realScale = 1;
3434

35+
this._errorShowed = false;
3536
this._errorPrinter = null;
3637
this._canvas = null;
3738
this._video = null;
@@ -271,6 +272,40 @@ Graphics.endLoading = function() {
271272
this._upperCanvas.style.opacity = 0;
272273
};
273274

275+
/**
276+
* Displays the loading error text to the screen.
277+
*
278+
* @static
279+
* @method printLoadingError
280+
* @param {String} url The url of the resource failed to load
281+
*/
282+
Graphics.printLoadingError = function(url) {
283+
if (this._errorPrinter && !this._errorShowed) {
284+
this._errorPrinter.innerHTML = this._makeErrorHtml('Loading Error', 'Failed to load: ' + url);
285+
var button = document.createElement('button');
286+
button.innerHTML = 'Retry';
287+
button.style.fontSize = '24px';
288+
button.style.color = '#ffffff';
289+
button.style.backgroundColor = '#000000';
290+
button.onclick = ResourceHandler.retry.bind(ResourceHandler);
291+
this._errorPrinter.appendChild(button);
292+
this._loadingCount = -Infinity;
293+
}
294+
};
295+
296+
/**
297+
* Erases the loading error text.
298+
*
299+
* @static
300+
* @method eraseLoadingError
301+
*/
302+
Graphics.eraseLoadingError = function() {
303+
if (this._errorPrinter && !this._errorShowed) {
304+
this._errorPrinter.innerHTML = '';
305+
this.startLoading();
306+
}
307+
};
308+
274309
/**
275310
* Displays the error text to the screen.
276311
*
@@ -280,6 +315,7 @@ Graphics.endLoading = function() {
280315
* @param {String} message The message of the error
281316
*/
282317
Graphics.printError = function(name, message) {
318+
this._errorShowed = true;
283319
if (this._errorPrinter) {
284320
this._errorPrinter.innerHTML = this._makeErrorHtml(name, message);
285321
}
@@ -369,9 +405,20 @@ Graphics.isFontLoaded = function(name) {
369405
* @param {String} src
370406
*/
371407
Graphics.playVideo = function(src) {
408+
this._videoLoader = ResourceHandler.createLoader(null, this._playVideo.bind(this, src), this._onVideoError.bind(this));
409+
this._playVideo(src);
410+
};
411+
412+
/**
413+
* @static
414+
* @method _playVideo
415+
* @param {String} src
416+
* @private
417+
*/
418+
Graphics._playVideo = function(src) {
372419
this._video.src = src;
373420
this._video.onloadeddata = this._onVideoLoad.bind(this);
374-
this._video.onerror = this._onVideoError.bind(this);
421+
this._video.onerror = this._videoLoader;
375422
this._video.onended = this._onVideoEnd.bind(this);
376423
this._video.load();
377424
this._videoLoading = true;

js/rpg_core/ResourceHandler.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//-----------------------------------------------------------------------------
2+
/**
3+
* The static class that handles resource loading.
4+
*
5+
* @class ResourceHandler
6+
*/
7+
function ResourceHandler() {
8+
throw new Error('This is a static class');
9+
}
10+
11+
ResourceHandler._reloaders = [];
12+
ResourceHandler._defaultRetryInterval = [500, 1000, 3000];
13+
14+
ResourceHandler.createLoader = function(url, retryMethod, resignMethod, retryInterval) {
15+
retryInterval = retryInterval || this._defaultRetryInterval;
16+
var reloaders = this._reloaders;
17+
var retryCount = 0;
18+
return function() {
19+
if (retryCount < retryInterval.length) {
20+
setTimeout(retryMethod, retryInterval[retryCount]);
21+
retryCount++;
22+
} else {
23+
if (resignMethod) {
24+
resignMethod();
25+
}
26+
if (url) {
27+
if (reloaders.length === 0) {
28+
Graphics.printLoadingError(url);
29+
}
30+
reloaders.push(function() {
31+
retryCount = 0;
32+
retryMethod();
33+
});
34+
}
35+
}
36+
};
37+
};
38+
39+
ResourceHandler.exists = function() {
40+
return this._reloaders.length > 0;
41+
};
42+
43+
ResourceHandler.retry = function() {
44+
if (this._reloaders.length > 0) {
45+
Graphics.eraseLoadingError();
46+
this._reloaders.forEach(function(reloader) {
47+
reloader();
48+
});
49+
this._reloaders.length = 0;
50+
}
51+
};

js/rpg_core/WebAudio.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ WebAudio.prototype.initialize = function(url) {
1515
WebAudio.initialize();
1616
}
1717
this.clear();
18+
this._loader = ResourceHandler.createLoader(url, this._load.bind(this, url), function() {
19+
this._hasError = true;
20+
}.bind(this));
1821
this._load(url);
1922
this._url = url;
2023
};
@@ -482,9 +485,7 @@ WebAudio.prototype._load = function(url) {
482485
this._onXhrLoad(xhr);
483486
}
484487
}.bind(this);
485-
xhr.onerror = function() {
486-
this._hasError = true;
487-
}.bind(this);
488+
xhr.onerror = this._loader;
488489
xhr.send();
489490
}
490491
};

js/rpg_managers/DataManager.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ DataManager.loadDataFile = function(name, src) {
8282
DataManager.onLoad(window[name]);
8383
}
8484
};
85-
xhr.onerror = function() {
85+
xhr.onerror = this._mapLoader || function() {
8686
DataManager._errorUrl = DataManager._errorUrl || url;
8787
};
8888
window[name] = null;
@@ -102,6 +102,7 @@ DataManager.isDatabaseLoaded = function() {
102102
DataManager.loadMapData = function(mapId) {
103103
if (mapId > 0) {
104104
var filename = 'Map%1.json'.format(mapId.padZero(3));
105+
this._mapLoader = ResourceHandler.createLoader('data/' + filename, this.loadDataFile.bind(this, '$dataMap', filename));
105106
this.loadDataFile('$dataMap', filename);
106107
} else {
107108
this.makeEmptyMap();

js/rpg_managers/ImageManager.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,6 @@ ImageManager.clear = function() {
116116
};
117117

118118
ImageManager.isReady = function() {
119-
var bitmap = null;
120-
if(bitmap = this._imageCache.getErrorBitmap()){
121-
throw new Error('Failed to load: ' + bitmap.url);
122-
}
123119
return this._imageCache.isReady();
124120
};
125121

js/rpg_managers/SceneManager.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ SceneManager.changeScene = function() {
248248
};
249249

250250
SceneManager.updateScene = function() {
251+
if (ResourceHandler.exists() && Input.isTriggered('ok')) {
252+
ResourceHandler.retry();
253+
this.updateInputData();
254+
}
251255
if (this._scene) {
252256
if (!this._sceneStarted && this._scene.isReady()) {
253257
this._scene.start();

js/rpg_scenes/Scene_Base.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ Scene_Base.prototype.start = function() {
4545
Scene_Base.prototype.update = function() {
4646
this.updateFade();
4747
this.updateChildren();
48-
AudioManager.checkErrors();
4948
};
5049

5150
Scene_Base.prototype.stop = function() {

plugins/Debug_FailLoading.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*:
2+
* @plugindesc Fail to load images, audio, movies and map data.
3+
* @author RM CoreScript team
4+
*
5+
* @param failImage
6+
* @desc Probability of image loading failure (0-1)
7+
* @default 0.5
8+
*
9+
* @param failAudio
10+
* @desc Probability of audio loading failure (0-1)
11+
* @default 0.5
12+
*
13+
* @param failMovie
14+
* @desc Probability of movie loading failure (0-1)
15+
* @default 0.5
16+
*
17+
* @param failMapData
18+
* @desc Probability of map data loading failure (0-1)
19+
* @default 0.5
20+
*/
21+
22+
/*:ja
23+
* @plugindesc 画像や音声、動画やマップデータの読み込みに失敗します。
24+
* @author RM CoreScript team
25+
*
26+
* @param failImage
27+
* @desc 画像の読み込みに失敗する確率 (0-1)
28+
* @default 0.5
29+
*
30+
* @param failAudio
31+
* @desc 音声の読み込みに失敗する確率 (0-1)
32+
* @default 0.5
33+
*
34+
* @param failMovie
35+
* @desc 動画の読み込みに失敗する確率 (0-1)
36+
* @default 0.5
37+
*
38+
* @param failMapData
39+
* @desc マップデータ読み込みに失敗する確率 (0-1)
40+
* @default 0.5
41+
*/
42+
43+
(function() {
44+
function toNumber(str, def) {
45+
return isNaN(str) ? def : +(str || def);
46+
}
47+
48+
var parameters = PluginManager.parameters('Debug_FailLoading');
49+
var failImage = toNumber(parameters['failImage'], 0.5);
50+
var failAudio = toNumber(parameters['failAudio'], 0.5);
51+
var failMovie = toNumber(parameters['failMovie'], 0.5);
52+
var failMapData = toNumber(parameters['failMapData'], 0.5);
53+
54+
var _Bitmap_onLoad = Bitmap.prototype._onLoad;
55+
Bitmap.prototype._onLoad = function() {
56+
if (Math.random() < failImage) {
57+
this._image.onerror();
58+
} else {
59+
_Bitmap_onLoad.apply(this, arguments);
60+
}
61+
};
62+
63+
WebAudio.prototype._load = function(url) {
64+
if (WebAudio._context) {
65+
var xhr = new XMLHttpRequest();
66+
if(Decrypter.hasEncryptedAudio) url = Decrypter.extToEncryptExt(url);
67+
xhr.open('GET', url);
68+
xhr.responseType = 'arraybuffer';
69+
xhr.onload = function() {
70+
if (Math.random() < failAudio) {
71+
xhr.onerror();
72+
} else if (xhr.status < 400) {
73+
this._onXhrLoad(xhr);
74+
}
75+
}.bind(this);
76+
xhr.onerror = this._loader;
77+
xhr.send();
78+
}
79+
};
80+
81+
var _Graphics_onVideoLoad = Graphics._onVideoLoad;
82+
Graphics._onVideoLoad = function() {
83+
if (Math.random() < failMovie) {
84+
this._video.onerror();
85+
} else {
86+
_Graphics_onVideoLoad.apply(this, arguments);
87+
}
88+
};
89+
90+
DataManager.loadDataFile = function(name, src) {
91+
var xhr = new XMLHttpRequest();
92+
var url = 'data/' + src;
93+
xhr.open('GET', url);
94+
xhr.overrideMimeType('application/json');
95+
xhr.onload = function() {
96+
if (name === '$dataMap' && Math.random() < failMapData) {
97+
xhr.onerror();
98+
} else if (xhr.status < 400) {
99+
window[name] = JSON.parse(xhr.responseText);
100+
DataManager.onLoad(window[name]);
101+
}
102+
};
103+
xhr.onerror = this._mapLoader || function() {
104+
DataManager._errorUrl = DataManager._errorUrl || url;
105+
};
106+
window[name] = null;
107+
xhr.send();
108+
};
109+
})();

0 commit comments

Comments
 (0)