diff --git a/js/rpg_core/Graphics.js b/js/rpg_core/Graphics.js index 93a252a0..8b20562e 100644 --- a/js/rpg_core/Graphics.js +++ b/js/rpg_core/Graphics.js @@ -11,6 +11,9 @@ function Graphics() { Graphics._cssFontLoading = document.fonts && document.fonts.ready && document.fonts.ready.then; Graphics._fontLoaded = null; Graphics._videoVolume = 1; +Graphics._showErrorDetailEnabled = false; +Graphics._progressEnabled = false; +Graphics._errorMessage = ""; /** * Initializes the graphics system. @@ -411,24 +414,46 @@ Graphics.printError = function(name, message) { this._clearUpperCanvas(); }; -/** - * Shows the stacktrace of error. - * - * @static - * @method printStackTrace - */ -Graphics.printStackTrace = function(stack) { - if (this._errorPrinter) { - stack = (stack || '') - .replace(/file:.*js\//g, '') - .replace(/http:.*js\//g, '') - .replace(/https:.*js\//g, '') - .replace(/chrome-extension:.*js\//g, '') - .replace(/\n/g, '
'); - this._makeStackTrace(decodeURIComponent(stack)); +Graphics._makeErrorStackLog =function(e){ + if(e.stack){ + var log = e.stack.replace(/file:.*js\//g, '') + .replace(/http:.*js\//g, '') + .replace(/https:.*js\//g, '') + .replace(/chrome-extension:.*js\//g, '') + .replace(/\n/g, '
'); + return log; + } + return ''; +}; +Graphics._makeEventInfo = function(e){ + if(e.rpgmvErrorLog){ + return e.rpgmvErrorLog.createErrorHTML(); } + return ""; }; +Graphics.createErrorHTML = function(error){ + return this._makeEventInfo(error)+ this._makeErrorStackLog(error); +}; + +Graphics.setErrorDetailEnabled =function(state){ + this._showErrorDetailEnabled = !!state; +}; + +Graphics.printErrorDetail =function(e){ + if ( this._showErrorDetailEnabled && this._errorPrinter){ + var html = this.createErrorHTML(e); + var detail = document.createElement('div'); + var style = detail.style; + style.color = 'white'; + style.textAlign = 'left'; + style.fontSize = '18px'; + detail.innerHTML = html + '
' ; + this._errorPrinter.appendChild(detail); + } +}; + + /** * Sets the error message. * diff --git a/js/rpg_managers/SceneManager.js b/js/rpg_managers/SceneManager.js index d4c8d804..6815cda1 100644 --- a/js/rpg_managers/SceneManager.js +++ b/js/rpg_managers/SceneManager.js @@ -197,11 +197,18 @@ SceneManager.onKeyDown = function(event) { } }; +SceneManager.showErrorLog = function(e){ + console.error(e.stack); + if(e.rpgmvErrorLog){ + console.error(e.rpgmvErrorLog.createConsoleMessage() ); + } +}; + SceneManager.catchException = function(e) { if (e instanceof Error) { Graphics.printError(e.name, e.message); - Graphics.printStackTrace(e.stack); - console.error(e.stack); + Graphics.printErrorDetail(e); + this.showErrorLog(e); } else { Graphics.printError('UnknownError', e); } diff --git a/js/rpg_objects/Game_Character.js b/js/rpg_objects/Game_Character.js index 85bfed0d..67718352 100644 --- a/js/rpg_objects/Game_Character.js +++ b/js/rpg_objects/Game_Character.js @@ -80,6 +80,7 @@ Game_Character.prototype.restoreMoveRoute = function() { this._moveRoute = this._originalMoveRoute; this._moveRouteIndex = this._originalMoveRouteIndex; this._originalMoveRoute = null; + this._moveRouteLog = null; }; Game_Character.prototype.isMoveRouteForcing = function() { @@ -262,10 +263,28 @@ Game_Character.prototype.processMoveCommand = function(command) { AudioManager.playSe(params[0]); break; case gc.ROUTE_SCRIPT: - eval(params[0]); + this.evalRouteScript(params[0]); break; } }; +Game_Character.prototype.evalRouteScript = function(script){ + var gc = Game_Character; + try { + eval(script); + } catch (error) { + + if(this._moveRouteLog){ + this._moveRouteLog.setMoveRouteIndex(this._moveRouteIndex); + this._moveRouteLog.addLog('target:'+this.debugName()); + this._moveRouteLog.addLog("script:"+script); + this.saveErrorCode(error); + } + throw(error); + } +}; +Game_Character.prototype.saveErrorCode =function(exeption){ + exeption.rpgmvErrorLog = this._moveRouteLog; +}; Game_Character.prototype.deltaXFrom = function(x) { return $gameMap.deltaX(this.x, x); diff --git a/js/rpg_objects/Game_CharacterBase.js b/js/rpg_objects/Game_CharacterBase.js index a3cda3b9..84211be4 100644 --- a/js/rpg_objects/Game_CharacterBase.js +++ b/js/rpg_objects/Game_CharacterBase.js @@ -48,6 +48,7 @@ Game_CharacterBase.prototype.initMembers = function() { this._jumpCount = 0; this._jumpPeak = 0; this._movementSuccess = true; + this._moveRouteLog =null; }; Game_CharacterBase.prototype.pos = function(x, y) { @@ -588,3 +589,11 @@ Game_CharacterBase.prototype.endAnimation = function() { Game_CharacterBase.prototype.endBalloon = function() { this._balloonPlaying = false; }; + +Game_CharacterBase.prototype.setMoveRouteLog = function(callLog){ + this._moveRouteLog = callLog; +}; +Game_CharacterBase.prototype.debugName = function(){ + return "CharacterBase"; +}; + diff --git a/js/rpg_objects/Game_CommonEvent.js b/js/rpg_objects/Game_CommonEvent.js index 5a9a707c..044de620 100644 --- a/js/rpg_objects/Game_CommonEvent.js +++ b/js/rpg_objects/Game_CommonEvent.js @@ -36,10 +36,14 @@ Game_CommonEvent.prototype.isActive = function() { return event.trigger === 2 && $gameSwitches.value(event.switchId); }; +Game_CommonEvent.prototype.setupEvent = function(){ + this._interpreter.setup(this.list()); + this._interpreter.setEventCallLog(new Game_LogCommonEvent(this._commonEventId)); +}; Game_CommonEvent.prototype.update = function() { if (this._interpreter) { if (!this._interpreter.isRunning()) { - this._interpreter.setup(this.list()); + this.setupEvent(); } this._interpreter.update(); } diff --git a/js/rpg_objects/Game_Event.js b/js/rpg_objects/Game_Event.js index e1924ba7..597f49e1 100644 --- a/js/rpg_objects/Game_Event.js +++ b/js/rpg_objects/Game_Event.js @@ -48,6 +48,22 @@ Game_Event.prototype.list = function() { return this.page().list; }; +Game_Event.prototype.debugName = function(){ + var event = this.event(); + if(event){ + return "MapEvent:"+ this._eventId +"("+ event.name+")"; + } + return ""; +}; + +Game_Event.prototype.createLogClass = function(){ + return new Game_LogMapEvent( + this._mapId, + this._eventId, + this._pageIndex + ); +}; + Game_Event.prototype.isCollidedWithCharacters = function(x, y) { return (Game_Character.prototype.isCollidedWithCharacters.call(this, x, y) || this.isCollidedWithPlayerCharacters(x, y)); @@ -280,6 +296,12 @@ Game_Event.prototype.setupPageSettings = function() { this.setThrough(page.through); this.setMoveRoute(page.moveRoute); this._moveType = page.moveType; + + if(this._moveType === 3){ + var log =new Game_LogMoveRoute(this.createLogClass()); + this.setMoveRouteLog( log); + } + this._trigger = page.trigger; if (this._trigger === 4) { this._interpreter = new Game_Interpreter(); @@ -287,7 +309,6 @@ Game_Event.prototype.setupPageSettings = function() { this._interpreter = null; } }; - Game_Event.prototype.isOriginalPattern = function() { return this.pattern() === this._originalPattern; }; @@ -322,6 +343,7 @@ Game_Event.prototype.updateParallel = function() { if (this._interpreter) { if (!this._interpreter.isRunning()) { this._interpreter.setup(this.list(), this._eventId); + this._interpreter.setEventCallLog(this.createLogClass()); } this._interpreter.update(); } diff --git a/js/rpg_objects/Game_Follower.js b/js/rpg_objects/Game_Follower.js index d27a87f2..53108218 100644 --- a/js/rpg_objects/Game_Follower.js +++ b/js/rpg_objects/Game_Follower.js @@ -55,3 +55,8 @@ Game_Follower.prototype.chaseCharacter = function(character) { } this.setMoveSpeed($gamePlayer.realMoveSpeed()); }; + +Game_Follower.prototype.debugName = function(){ + return "follower[" + this._memberIndex+"]"; +}; + diff --git a/js/rpg_objects/Game_Interpreter.js b/js/rpg_objects/Game_Interpreter.js index 56b36b83..0d825aea 100644 --- a/js/rpg_objects/Game_Interpreter.js +++ b/js/rpg_objects/Game_Interpreter.js @@ -34,6 +34,7 @@ Game_Interpreter.prototype.clear = function() { this._comments = ''; this._character = null; this._childInterpreter = null; + this._callLog = null; }; Game_Interpreter.prototype.setup = function(list, eventId) { @@ -44,6 +45,10 @@ Game_Interpreter.prototype.setup = function(list, eventId) { Game_Interpreter.requestImages(list); }; +Game_Interpreter.prototype.setEventCallLog = function(callLog){ + this._callLog = callLog; +}; + Game_Interpreter.prototype.eventId = function() { return this._eventId; }; @@ -55,6 +60,7 @@ Game_Interpreter.prototype.isOnCurrentMap = function() { Game_Interpreter.prototype.setupReservedCommonEvent = function() { if ($gameTemp.isCommonEventReserved()) { this.setup($gameTemp.reservedCommonEvent().list); + this.setEventCallLog(new Game_LogCommonEvent($gameTemp._commonEventId) ); $gameTemp.clearCommonEvent(); return true; } else { @@ -543,7 +549,7 @@ Game_Interpreter.prototype.command111 = function() { result = Input.isPressed(this._params[1]); break; case 12: // Script - result = !!eval(this._params[1]); + result = !!this.evalScript(this._params[1]); break; case 13: // Vehicle result = ($gamePlayer.vehicle() === $gameMap.vehicle(this._params[1])); @@ -605,10 +611,13 @@ Game_Interpreter.prototype.command115 = function() { // Common Event Game_Interpreter.prototype.command117 = function() { - var commonEvent = $dataCommonEvents[this._params[0]]; + var commonEventId =this._params[0]; + var commonEvent = $dataCommonEvents[commonEventId]; if (commonEvent) { var eventId = this.isOnCurrentMap() ? this._eventId : 0; this.setupChild(commonEvent.list, eventId); + this._childInterpreter.setEventCallLog(new Game_LogCommonEvent(commonEventId)); + } return true; }; @@ -680,7 +689,7 @@ Game_Interpreter.prototype.command122 = function() { value = this.gameDataOperand(this._params[4], this._params[5], this._params[6]); break; case 4: // Script - value = eval(this._params[4]); + value = this.evalScript(this._params[4]); break; } for (var i = this._params[0]; i <= this._params[1]; i++) { @@ -689,6 +698,20 @@ Game_Interpreter.prototype.command122 = function() { return true; }; +Game_Interpreter.prototype.evalScript = function(script){ + try { + return eval(script); + } catch (error) { + if(this._callLog){ + this._callLog.addLog(this.errorCode(this._index)); + this._callLog.addLog("ScriptError"); + this._callLog.addLog(script); + this.saveErrorCode(error); + } + throw(error); + } +}; + Game_Interpreter.prototype.gameDataOperand = function(type, param1, param2) { switch (type) { case 0: // Item @@ -1027,6 +1050,9 @@ Game_Interpreter.prototype.command205 = function() { if (this._params[1].wait) { this.setWaitMode('route'); } + var log =new Game_LogMoveRoute(this._callLog); + log.setEventCommandLine(this._index); + this._character.setMoveRouteLog(log); } return true; }; @@ -1732,11 +1758,16 @@ Game_Interpreter.prototype.command354 = function() { // Script Game_Interpreter.prototype.command355 = function() { var script = this.currentCommand().parameters[0] + '\n'; - while (this.nextEventCode() === 655) { - this._index++; - script += this.currentCommand().parameters[0] + '\n'; + var index =this._index+1; + + var eventCode = this._list[index]; + while(eventCode && eventCode.code ===655){ + script += eventCode.parameters[0]+"\n"; + ++index; + eventCode = this._list[index]; } - eval(script); + this.evalScript(script); + this._index = index-1; return true; }; @@ -1744,13 +1775,63 @@ Game_Interpreter.prototype.command355 = function() { Game_Interpreter.prototype.command356 = function() { var args = this._params[0].split(" "); var command = args.shift(); - this.pluginCommand(command, args); + try { + this.pluginCommand(command, args); + } catch (error) { + if(this._callLog){ + this._callLog.addLog(this.errorCode(this._index)); + this._callLog.addLog("command:"+command); + this._callLog.addLog("args:"+args); + this.saveErrorCode(error); + } + throw(error); + } return true; }; Game_Interpreter.prototype.pluginCommand = function(command, args) { // to be overridden by plugins }; +Game_Interpreter.codeName = function(code){ + + + switch (code) { + case 111: + return "Conditional Branch"; + case 122: + return "Control Variables"; + case 355: + return "Script"; + case 356: + return "Plugin Command"; + } + return ""; +}; +Game_Interpreter.prototype.errorCode = function(errorLine){ + var data= this._list[errorLine]; + var lineText = "line:"+(errorLine+1); + if(!data){ + return lineText +" Out of Code range" + } + + if(data.code ===355){ + for(var i = errorLine+1; i< this._list.length;++i){ + var scriptData = this._list[i]; + if(scriptData && scriptData.code !==655){ + if( errorLine < (i-1) ){ + lineText +="-"+i; + } + break; + } + } + } + return lineText + " " + Game_Interpreter.codeName(data.code); +}; + +Game_Interpreter.prototype.saveErrorCode =function(exeption){ + exeption.rpgmvErrorLog = this._callLog; +}; + Game_Interpreter.requestImagesByPluginCommand = function(command,args){ }; diff --git a/js/rpg_objects/Game_Log.js b/js/rpg_objects/Game_Log.js new file mode 100644 index 00000000..47526eee --- /dev/null +++ b/js/rpg_objects/Game_Log.js @@ -0,0 +1,190 @@ +function Game_LogBase(){ + this.initialize.apply(this,arguments); +} + +Game_LogBase.prototype.initialize = function(){ + this._additionalLog =[]; +}; + +Game_LogBase.prototype.createMessage = function(){ + return 'unknown error'; +}; + +Game_LogBase.prototype.createErrorHTML = function(){ + var addError = this.createAdditionalError('
'); + return this.createMessage() +addError+ '

'; +}; + +Game_LogBase.prototype.createConsoleMessage = function(){ + return this.createMessage() + this.createAdditionalError("\n"); +}; + +Game_LogBase.prototype.addLog = function(text){ + if(!this._additionalLog){ + this._additionalLog =[]; + } + this._additionalLog.push(text); +}; + +Game_LogBase.prototype.createAdditionalError = function(brStr){ + if(!this._additionalLog){return "";} + var result =brStr; + for(var i=0; i < this._additionalLog.length; ++i){ + result += this._additionalLog[i] + brStr; + } + return result; +}; + +function Game_LogMapEvent(){ + this.initialize.apply(this,arguments); +} + +Game_LogMapEvent.prototype = Object.create(Game_LogBase.prototype); +Game_LogMapEvent.prototype.constructor = Game_LogMapEvent; + +Game_LogMapEvent.prototype.initialize = function(mapId,eventId,page){ + this._mapId = mapId; + this._eventId = eventId; + this._page = page; +}; + +Game_LogMapEvent.prototype.event = function(){ + if($gameMap.mapId() === this._mapId){ + var event = $gameMap.event(this._eventId); + if(event){ + return event; + } + } + return null; +}; + +Game_LogMapEvent.prototype.getEventName = function(){ + var event = this.event(); + if(event){ + return event.debugName(); + } + return ""; +} + +Game_LogMapEvent.prototype.createMessage = function(){ + var event = this.event(); + if(event){ + return ( "MapID: %1,%2, page: %3").format(this._mapId,event.debugName(),this._page+1); + } + return ""; +}; + + +function Game_LogMoveRoute(){ + this.initialize.apply(this,arguments); +} +Game_LogMoveRoute.prototype = Object.create(Game_LogBase.prototype); +Game_LogMoveRoute.prototype.constructor = Game_LogCommonEvent; +Game_LogMoveRoute.prototype.initialize =function(sorce){ + this._moveRouteSorce =sorce; + this._eventCommandLine =NaN; + this._moveRouteIndex =NaN; +}; +Game_LogMoveRoute.prototype.sorceMessage =function(){ + if(this._moveRouteSorce){ + return this._moveRouteSorce.createMessage(); + } + return 'unknown'; +}; +Game_LogMoveRoute.prototype.createMessage =function(){ + return 'moveRouteError'; +}; +Game_LogMoveRoute.prototype.setEventCommandLine =function(index){ + this._eventCommandLine = index; +}; + +Game_LogMoveRoute.prototype.setMoveRouteIndex = function(index){ + this._moveRouteIndex = index; +}; +Game_LogMoveRoute.prototype.createLineMassage =function(){ + var moveRouteIndex =(this._moveRouteIndex || 0) +1; + if(isNaN(this._eventCommandLine)){ + return '(MoveRouteCostom) line:'+moveRouteIndex; + } + return 'line:'+( this._eventCommandLine+ 1 + moveRouteIndex); +}; + +Game_LogMoveRoute.prototype.createAdditionalError =function(brStr){ + var origin= Game_LogBase.prototype.createAdditionalError.call(this,brStr); + return (brStr+'sorce:'+this.sorceMessage() + + brStr +this.createLineMassage() + + origin); +}; +function Game_LogCommonEvent(){ + this.initialize.apply(this,arguments); +} + +Game_LogCommonEvent.prototype = Object.create(Game_LogBase.prototype); +Game_LogCommonEvent.prototype.constructor = Game_LogCommonEvent; + +Game_LogCommonEvent.prototype.initialize = function(eventId){ + this._eventId = eventId; + this._parent =null; +}; + +Game_LogCommonEvent.prototype.getEventName = function(){ + var event = $dataCommonEvents[this._eventId]; + if(event){ + if(event.name ===''){ + return 'unnamed'; + } + return event.name; + } + return ""; +}; + +Game_LogCommonEvent.prototype.createMessage = function(){ + var name = this.getEventName(); + return("CommonEvent: %1(%2)").format( + this._eventId , + name + ); +}; + +function Game_LogBattleEvent(){ + this.initialize.apply(this,arguments); +} + +Game_LogBattleEvent.prototype = Object.create(Game_LogBase.prototype); +Game_LogBattleEvent.prototype.constructor = Game_LogBattleEvent; +Game_LogBattleEvent.prototype.initialize = function(troopId,page){ + this._troopId = troopId; + this._page =page; +}; + +Game_LogBattleEvent.prototype.getEventName = function(){ + var troop = $dataTroops[this._troopId]; + if(troop){ + return troop.name; + } + return ""; +}; + +Game_LogBattleEvent.prototype.createMessage = function(){ + var name = this.getEventName(); + return ("BattleEvent TroopID: %1(%2), page: %3").format( + this._troopId, + name, + 1+this._page + ); +}; + +function Game_LogEventTest(){ + this.initialize.apply(this,arguments); +} + +Game_LogEventTest.prototype = Object.create(Game_LogBase.prototype); +Game_LogEventTest.prototype.constructor = Game_LogBattleEvent; + +Game_LogEventTest.prototype.initialize = function(){ +}; + +Game_LogEventTest.prototype.createMessage = function(){ + return ('EventTest'); +}; + diff --git a/js/rpg_objects/Game_Map.js b/js/rpg_objects/Game_Map.js index 10352822..309219f8 100644 --- a/js/rpg_objects/Game_Map.js +++ b/js/rpg_objects/Game_Map.js @@ -756,6 +756,7 @@ Game_Map.prototype.setupStartingEvent = function() { Game_Map.prototype.setupTestEvent = function() { if ($testEvent) { this._interpreter.setup($testEvent, 0); + this._interpreter.setEventCallLog(new Game_LogEventTest()); $testEvent = null; return true; } @@ -769,6 +770,7 @@ Game_Map.prototype.setupStartingMapEvent = function() { if (event.isStarting()) { event.clearStartingFlag(); this._interpreter.setup(event.list(), event.eventId()); + this._interpreter.setEventCallLog(event.createLogClass()); return true; } } @@ -780,6 +782,7 @@ Game_Map.prototype.setupAutorunCommonEvent = function() { var event = $dataCommonEvents[i]; if (event && event.trigger === 1 && $gameSwitches.value(event.switchId)) { this._interpreter.setup(event.list); + this._interpreter.setEventCallLog( new Game_LogCommonEvent(i)); return true; } } diff --git a/js/rpg_objects/Game_Player.js b/js/rpg_objects/Game_Player.js index 1af6d352..748d89bd 100644 --- a/js/rpg_objects/Game_Player.js +++ b/js/rpg_objects/Game_Player.js @@ -619,3 +619,7 @@ Game_Player.prototype.areFollowersGathering = function() { Game_Player.prototype.areFollowersGathered = function() { return this._followers.areGathered(); }; + +Game_Player.prototype.debugName = function(){ + return "player"; +}; diff --git a/js/rpg_objects/Game_Troop.js b/js/rpg_objects/Game_Troop.js index fb520c5c..7f9718ad 100644 --- a/js/rpg_objects/Game_Troop.js +++ b/js/rpg_objects/Game_Troop.js @@ -159,6 +159,7 @@ Game_Troop.prototype.setupBattleEvent = function() { var page = pages[i]; if (this.meetsConditions(page) && !this._eventFlags[i]) { this._interpreter.setup(page.list); + this._interpreter.setEventCallLog(new Game_LogBattleEvent(this._troopId,i)); if (page.span <= 1) { this._eventFlags[i] = true; } diff --git a/js/rpg_objects/Game_Vehicle.js b/js/rpg_objects/Game_Vehicle.js index 012961d7..04f72e2f 100644 --- a/js/rpg_objects/Game_Vehicle.js +++ b/js/rpg_objects/Game_Vehicle.js @@ -231,3 +231,7 @@ Game_Vehicle.prototype.isLandOk = function(x, y, d) { } return true; }; + +Game_Vehicle.prototype.debugName = function(){ + return "vehicle("+this._type+")"; +}; diff --git a/plugins/Community_Basic.js b/plugins/Community_Basic.js index 0a05828f..71191c30 100644 --- a/plugins/Community_Basic.js +++ b/plugins/Community_Basic.js @@ -64,6 +64,13 @@ * @desc The message when error occurred * @default Error occurred. Please ask to the creator of this game. * + * @param showErrorLogDetail + * @type boolean + * @text Detailed error display + * @desc When set to ON, + * details are displayed on the screen when the game stops due to an error. + * @default true + * * @param enableProgressBar * @type boolean * @desc Show progress bar when it takes a long time to load resources @@ -146,6 +153,12 @@ * @text エラーメッセージ * @default エラーが発生しました。ゲームの作者にご連絡ください。 * + * @param showErrorLogDetail + * @type boolean + * @text エラーの詳細表示 + * @desc ONにすると、ゲームがエラーで停止したときに画面に詳細を表示します。 + * @default true + * * @param enableProgressBar * @type boolean * @text ロード進捗バー有効化 @@ -183,6 +196,9 @@ var errorMessage = parameters['errorMessage']; var enableProgressBar = parameters['enableProgressBar'] === 'true'; + var showErrorLogDetail = parameters['showErrorLogDetail']==='true'; + + var windowWidth; var windowHeight; @@ -264,4 +280,5 @@ DataManager.setAutoSaveFileId(autoSaveFileId); Graphics.setErrorMessage(errorMessage); Graphics.setProgressEnabled(enableProgressBar); -})(); \ No newline at end of file + Graphics.setErrorDetailEnabled(showErrorLogDetail); +})(); diff --git a/rpg_objects.json b/rpg_objects.json index 4abf6d91..c1aaf48b 100644 --- a/rpg_objects.json +++ b/rpg_objects.json @@ -29,5 +29,6 @@ "js/rpg_objects/Game_Followers.js", "js/rpg_objects/Game_Vehicle.js", "js/rpg_objects/Game_Event.js", + "js/rpg_objects/Game_Log.js", "js/rpg_objects/Game_Interpreter.js" -] \ No newline at end of file +]