Catch (nearly) all exceptions thrown by OsuParser.

- Properly handle bad input and log a warning.  The game may run with some gameplay errors (ex. if no base TimingPoint is parsed), but it should not crash.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-24 13:38:59 -04:00
parent 39dcdf6dee
commit 83e486054f
2 changed files with 222 additions and 171 deletions

View File

@ -133,46 +133,51 @@ public class OsuParser {
break; break;
if ((tokens = tokenize(line)) == null) if ((tokens = tokenize(line)) == null)
continue; continue;
switch (tokens[0]) { try {
case "AudioFilename": switch (tokens[0]) {
osu.audioFilename = new File(file.getParent() + File.separator + tokens[1]); case "AudioFilename":
break; osu.audioFilename = new File(file.getParent() + File.separator + tokens[1]);
case "AudioLeadIn": break;
osu.audioLeadIn = Integer.parseInt(tokens[1]); case "AudioLeadIn":
break; osu.audioLeadIn = Integer.parseInt(tokens[1]);
// case "AudioHash": // deprecated break;
// osu.audioHash = tokens[1]; // case "AudioHash": // deprecated
// break; // osu.audioHash = tokens[1];
case "PreviewTime": // break;
osu.previewTime = Integer.parseInt(tokens[1]); case "PreviewTime":
break; osu.previewTime = Integer.parseInt(tokens[1]);
case "Countdown": break;
osu.countdown = Byte.parseByte(tokens[1]); case "Countdown":
break; osu.countdown = Byte.parseByte(tokens[1]);
case "SampleSet": break;
osu.sampleSet = tokens[1]; case "SampleSet":
break; osu.sampleSet = tokens[1];
case "StackLeniency": break;
osu.stackLeniency = Float.parseFloat(tokens[1]); case "StackLeniency":
break; osu.stackLeniency = Float.parseFloat(tokens[1]);
case "Mode": break;
osu.mode = Byte.parseByte(tokens[1]); case "Mode":
osu.mode = Byte.parseByte(tokens[1]);
/* Non-Opsu! standard files not implemented (obviously). */ /* Non-Opsu! standard files not implemented (obviously). */
if (osu.mode != 0) if (osu.mode != 0)
return null; return null;
break; break;
case "LetterboxInBreaks": case "LetterboxInBreaks":
osu.letterboxInBreaks = (Integer.parseInt(tokens[1]) == 1); osu.letterboxInBreaks = (Integer.parseInt(tokens[1]) == 1);
break; break;
case "WidescreenStoryboard": case "WidescreenStoryboard":
osu.widescreenStoryboard = (Integer.parseInt(tokens[1]) == 1); osu.widescreenStoryboard = (Integer.parseInt(tokens[1]) == 1);
break; break;
case "EpilepsyWarning": case "EpilepsyWarning":
osu.epilepsyWarning = (Integer.parseInt(tokens[1]) == 1); osu.epilepsyWarning = (Integer.parseInt(tokens[1]) == 1);
default: default:
break; break;
}
} catch (Exception e) {
Log.warn(String.format("Failed to read line '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
} }
} }
break; break;
@ -186,27 +191,32 @@ public class OsuParser {
/* Not implemented. */ /* Not implemented. */
// if ((tokens = tokenize(line)) == null) // if ((tokens = tokenize(line)) == null)
// continue; // continue;
// switch (tokens[0]) { // try {
// case "Bookmarks": // switch (tokens[0]) {
// String[] bookmarks = tokens[1].split(","); // case "Bookmarks":
// osu.bookmarks = new int[bookmarks.length]; // String[] bookmarks = tokens[1].split(",");
// for (int i = 0; i < bookmarks.length; i++) // osu.bookmarks = new int[bookmarks.length];
// osu.bookmarks[i] = Integer.parseInt(bookmarks[i]); // for (int i = 0; i < bookmarks.length; i++)
// break; // osu.bookmarks[i] = Integer.parseInt(bookmarks[i]);
// case "DistanceSpacing": // break;
// osu.distanceSpacing = Float.parseFloat(tokens[1]); // case "DistanceSpacing":
// break; // osu.distanceSpacing = Float.parseFloat(tokens[1]);
// case "BeatDivisor": // break;
// osu.beatDivisor = Byte.parseByte(tokens[1]); // case "BeatDivisor":
// break; // osu.beatDivisor = Byte.parseByte(tokens[1]);
// case "GridSize": // break;
// osu.gridSize = Integer.parseInt(tokens[1]); // case "GridSize":
// break; // osu.gridSize = Integer.parseInt(tokens[1]);
// case "TimelineZoom": // break;
// osu.timelineZoom = Integer.parseInt(tokens[1]); // case "TimelineZoom":
// break; // osu.timelineZoom = Integer.parseInt(tokens[1]);
// default: // break;
// break; // default:
// break;
// }
// } catch (Exception e) {
// Log.warn(String.format("Failed to read editor line '%s' for file '%s'.",
// line, file.getAbsolutePath()), e);
// } // }
} }
break; break;
@ -219,37 +229,42 @@ public class OsuParser {
break; break;
if ((tokens = tokenize(line)) == null) if ((tokens = tokenize(line)) == null)
continue; continue;
switch (tokens[0]) { try {
case "Title": switch (tokens[0]) {
osu.title = tokens[1]; case "Title":
break; osu.title = tokens[1];
case "TitleUnicode": break;
osu.titleUnicode = tokens[1]; case "TitleUnicode":
break; osu.titleUnicode = tokens[1];
case "Artist": break;
osu.artist = tokens[1]; case "Artist":
break; osu.artist = tokens[1];
case "ArtistUnicode": break;
osu.artistUnicode = tokens[1]; case "ArtistUnicode":
break; osu.artistUnicode = tokens[1];
case "Creator": break;
osu.creator = tokens[1]; case "Creator":
break; osu.creator = tokens[1];
case "Version": break;
osu.version = tokens[1]; case "Version":
break; osu.version = tokens[1];
case "Source": break;
osu.source = tokens[1]; case "Source":
break; osu.source = tokens[1];
case "Tags": break;
osu.tags = tokens[1].toLowerCase(); case "Tags":
break; osu.tags = tokens[1].toLowerCase();
case "BeatmapID": break;
osu.beatmapID = Integer.parseInt(tokens[1]); case "BeatmapID":
break; osu.beatmapID = Integer.parseInt(tokens[1]);
case "BeatmapSetID": break;
osu.beatmapSetID = Integer.parseInt(tokens[1]); case "BeatmapSetID":
break; osu.beatmapSetID = Integer.parseInt(tokens[1]);
break;
}
} catch (Exception e) {
Log.warn(String.format("Failed to read metadata '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
} }
} }
break; break;
@ -262,25 +277,30 @@ public class OsuParser {
break; break;
if ((tokens = tokenize(line)) == null) if ((tokens = tokenize(line)) == null)
continue; continue;
switch (tokens[0]) { try {
case "HPDrainRate": switch (tokens[0]) {
osu.HPDrainRate = Float.parseFloat(tokens[1]); case "HPDrainRate":
break; osu.HPDrainRate = Float.parseFloat(tokens[1]);
case "CircleSize": break;
osu.circleSize = Float.parseFloat(tokens[1]); case "CircleSize":
break; osu.circleSize = Float.parseFloat(tokens[1]);
case "OverallDifficulty": break;
osu.overallDifficulty = Float.parseFloat(tokens[1]); case "OverallDifficulty":
break; osu.overallDifficulty = Float.parseFloat(tokens[1]);
case "ApproachRate": break;
osu.approachRate = Float.parseFloat(tokens[1]); case "ApproachRate":
break; osu.approachRate = Float.parseFloat(tokens[1]);
case "SliderMultiplier": break;
osu.sliderMultiplier = Float.parseFloat(tokens[1]); case "SliderMultiplier":
break; osu.sliderMultiplier = Float.parseFloat(tokens[1]);
case "SliderTickRate": break;
osu.sliderTickRate = Float.parseFloat(tokens[1]); case "SliderTickRate":
break; osu.sliderTickRate = Float.parseFloat(tokens[1]);
break;
}
} catch (Exception e) {
Log.warn(String.format("Failed to read difficulty '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
} }
} }
if (osu.approachRate == -1f) // not in old format if (osu.approachRate == -1f) // not in old format
@ -302,10 +322,15 @@ public class OsuParser {
osu.bg = file.getParent() + File.separator + tokens[2]; osu.bg = file.getParent() + File.separator + tokens[2];
break; break;
case "2": // break periods case "2": // break periods
if (osu.breaks == null) // optional, create if needed try {
osu.breaks = new ArrayList<Integer>(); if (osu.breaks == null) // optional, create if needed
osu.breaks.add(Integer.parseInt(tokens[1])); osu.breaks = new ArrayList<Integer>();
osu.breaks.add(Integer.parseInt(tokens[2])); osu.breaks.add(Integer.parseInt(tokens[1]));
osu.breaks.add(Integer.parseInt(tokens[2]));
} catch (Exception e) {
Log.warn(String.format("Failed to read break period '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
}
break; break;
default: default:
/* Not implemented. */ /* Not implemented. */
@ -321,21 +346,26 @@ public class OsuParser {
if (line.charAt(0) == '[') if (line.charAt(0) == '[')
break; break;
// parse timing point try {
OsuTimingPoint timingPoint = new OsuTimingPoint(line); // parse timing point
OsuTimingPoint timingPoint = new OsuTimingPoint(line);
// calculate BPM // calculate BPM
if (!timingPoint.isInherited()) { if (!timingPoint.isInherited()) {
int bpm = Math.round(60000 / timingPoint.getBeatLength()); int bpm = Math.round(60000 / timingPoint.getBeatLength());
if (osu.bpmMin == 0) if (osu.bpmMin == 0)
osu.bpmMin = osu.bpmMax = bpm; osu.bpmMin = osu.bpmMax = bpm;
else if (bpm < osu.bpmMin) else if (bpm < osu.bpmMin)
osu.bpmMin = bpm; osu.bpmMin = bpm;
else if (bpm > osu.bpmMax) else if (bpm > osu.bpmMax)
osu.bpmMax = bpm; osu.bpmMax = bpm;
}
osu.timingPoints.add(timingPoint);
} catch (Exception e) {
Log.warn(String.format("Failed to read timing point '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
} }
osu.timingPoints.add(timingPoint);
} }
break; break;
case "[Colours]": case "[Colours]":
@ -348,23 +378,28 @@ public class OsuParser {
break; break;
if ((tokens = tokenize(line)) == null) if ((tokens = tokenize(line)) == null)
continue; continue;
switch (tokens[0]) { try {
case "Combo1": switch (tokens[0]) {
case "Combo2": case "Combo1":
case "Combo3": case "Combo2":
case "Combo4": case "Combo3":
case "Combo5": case "Combo4":
case "Combo6": case "Combo5":
case "Combo7": case "Combo6":
case "Combo8": case "Combo7":
String[] rgb = tokens[1].split(","); case "Combo8":
colors.add(new Color( String[] rgb = tokens[1].split(",");
Integer.parseInt(rgb[0]), colors.add(new Color(
Integer.parseInt(rgb[1]), Integer.parseInt(rgb[0]),
Integer.parseInt(rgb[2]) Integer.parseInt(rgb[1]),
)); Integer.parseInt(rgb[2])
default: ));
break; default:
break;
}
} catch (Exception e) {
Log.warn(String.format("Failed to read color '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
} }
} }
if (!colors.isEmpty()) if (!colors.isEmpty())
@ -380,24 +415,34 @@ public class OsuParser {
break; break;
/* Only type counts parsed at this time. */ /* Only type counts parsed at this time. */
tokens = line.split(","); tokens = line.split(",");
type = Integer.parseInt(tokens[3]); try {
if ((type & OsuHitObject.TYPE_CIRCLE) > 0) type = Integer.parseInt(tokens[3]);
osu.hitObjectCircle++; if ((type & OsuHitObject.TYPE_CIRCLE) > 0)
else if ((type & OsuHitObject.TYPE_SLIDER) > 0) osu.hitObjectCircle++;
osu.hitObjectSlider++; else if ((type & OsuHitObject.TYPE_SLIDER) > 0)
else //if ((type & OsuHitObject.TYPE_SPINNER) > 0) osu.hitObjectSlider++;
osu.hitObjectSpinner++; else //if ((type & OsuHitObject.TYPE_SPINNER) > 0)
osu.hitObjectSpinner++;
} catch (Exception e) {
Log.warn(String.format("Failed to read hit object '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
}
} }
// map length = last object end time (TODO: end on slider?) try {
if ((type & OsuHitObject.TYPE_SPINNER) > 0) { // map length = last object end time (TODO: end on slider?)
// some 'endTime' fields contain a ':' character (?) if ((type & OsuHitObject.TYPE_SPINNER) > 0) {
int index = tokens[5].indexOf(':'); // some 'endTime' fields contain a ':' character (?)
if (index != -1) int index = tokens[5].indexOf(':');
tokens[5] = tokens[5].substring(0, index); if (index != -1)
osu.endTime = Integer.parseInt(tokens[5]); tokens[5] = tokens[5].substring(0, index);
} else if (type != 0) osu.endTime = Integer.parseInt(tokens[5]);
osu.endTime = Integer.parseInt(tokens[2]); } else if (type != 0)
osu.endTime = Integer.parseInt(tokens[2]);
} catch (Exception e) {
Log.warn(String.format("Failed to read hit object end time '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
}
break; break;
default: default:
line = in.readLine(); line = in.readLine();
@ -463,20 +508,25 @@ public class OsuParser {
if (tokenCount < 4) if (tokenCount < 4)
continue; continue;
// create a new OsuHitObject for each line try {
OsuHitObject hitObject = new OsuHitObject(line); // create a new OsuHitObject for each line
OsuHitObject hitObject = new OsuHitObject(line);
// set combo info // set combo info
// - new combo: get next combo index, reset combo number // - new combo: get next combo index, reset combo number
// - else: maintain combo index, increase combo number // - else: maintain combo index, increase combo number
if (hitObject.isNewCombo()) { if (hitObject.isNewCombo()) {
comboIndex = (comboIndex + 1) % osu.combo.length; comboIndex = (comboIndex + 1) % osu.combo.length;
comboNumber = 1; comboNumber = 1;
}
hitObject.setComboIndex(comboIndex);
hitObject.setComboNumber(comboNumber++);
osu.objects[objectIndex++] = hitObject;
} catch (Exception e) {
Log.warn(String.format("Failed to read hit object '%s' for OsuFile '%s'.",
line, osu.toString()), e);
} }
hitObject.setComboIndex(comboIndex);
hitObject.setComboNumber(comboNumber++);
osu.objects[objectIndex++] = hitObject;
} }
} catch (IOException e) { } catch (IOException e) {
Log.error(String.format("Failed to read file '%s'.", osu.getFile().getAbsolutePath()), e); Log.error(String.format("Failed to read file '%s'.", osu.getFile().getAbsolutePath()), e);

View File

@ -755,6 +755,7 @@ public class Game extends BasicGameState {
breakTime = 0; breakTime = 0;
breakSound = false; breakSound = false;
timingPointIndex = 0; timingPointIndex = 0;
beatLengthBase = beatLength = 1;
pauseTime = -1; pauseTime = -1;
pausedMouseX = -1; pausedMouseX = -1;
pausedMouseY = -1; pausedMouseY = -1;