Skip to content

Commit 9ee8532

Browse files
committed
language changes: restructurion to cope with rust-lang/rust#12158.
- the parser is now based on the iterator interface (finally), which returns a combined parsed item. - the parsed item includes Encoding, that eliminates the need of the BmsUsesEncoding special message. - the player has some more methods refactored out of the tick method.
1 parent 5c5d490 commit 9ee8532

File tree

11 files changed

+959
-836
lines changed

11 files changed

+959
-836
lines changed

src/engine/input.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ pub fn read_keymap(keyspec: &KeySpec, getenv: |&str| -> Option<~str>) -> Result<
201201
}
202202

203203
let mut map = ::std::hashmap::HashMap::new();
204-
let add_mapping = |kind: Option<KeyKind>, input: Input, vinput: VirtualInput| {
204+
let add_mapping = |map: &mut KeyMap, kind: Option<KeyKind>,
205+
input: Input, vinput: VirtualInput| {
205206
if kind.map_or(true, |kind| vinput.active_in_key_spec(kind, keyspec)) {
206207
map.insert(input, vinput);
207208
}
@@ -218,7 +219,7 @@ pub fn read_keymap(keyspec: &KeySpec, getenv: |&str| -> Option<~str>) -> Result<
218219
match parse_input(s) {
219220
Some(input) => {
220221
for &vinput in vinputs.iter() {
221-
add_mapping(kind, input, vinput);
222+
add_mapping(&mut map, kind, input, vinput);
222223
}
223224
}
224225
None => {
@@ -240,7 +241,7 @@ pub fn read_keymap(keyspec: &KeySpec, getenv: |&str| -> Option<~str>) -> Result<
240241
let envvar2 = format!("ANGOLMOIS_{}{}_KEY", key.to_str(), kind.to_char());
241242
for s in getenv(envvar).or(getenv(envvar2)).iter() {
242243
match parse_input(*s) {
243-
Some(input) => { add_mapping(Some(kind), input, LaneInput(lane)); }
244+
Some(input) => { add_mapping(&mut map, Some(kind), input, LaneInput(lane)); }
244245
None => { return Err(format!("Unknown key name in the environment variable {}: {}",
245246
envvar, *s)); }
246247
}

src/engine/keyspec.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ pub fn key_spec(bms: &Bms, preset: Option<~str>,
260260
};
261261

262262
let mut keyspec = ~KeySpec { split: 0, order: ~[], kinds: ~[None, ..NLANES] };
263-
let parse_and_add = |keys: &str| -> Option<uint> {
263+
let parse_and_add = |keyspec: &mut KeySpec, keys: &str| -> Option<uint> {
264264
match parse_key_spec(keys) {
265265
None | Some([]) => None,
266266
Some(left) => {
@@ -276,15 +276,15 @@ pub fn key_spec(bms: &Bms, preset: Option<~str>,
276276
};
277277

278278
if !leftkeys.is_empty() {
279-
match parse_and_add(leftkeys) {
279+
match parse_and_add(keyspec, leftkeys) {
280280
None => { return Err(format!("Invalid key spec for left hand side: {}", leftkeys)); }
281281
Some(nkeys) => { keyspec.split += nkeys; }
282282
}
283283
} else {
284284
return Err(~"No key model is specified using -k or -K");
285285
}
286286
if !rightkeys.is_empty() {
287-
match parse_and_add(rightkeys) {
287+
match parse_and_add(keyspec, rightkeys) {
288288
None => { return Err(format!("Invalid key spec for right hand side: {}", rightkeys)); }
289289
Some(nkeys) => { // no split panes except for Couple Play
290290
if bms.meta.mode != CouplePlay { keyspec.split += nkeys; }

src/engine/player.rs

+109-105
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,98 @@ impl Player {
428428
self.beep.play(Some(0), 0);
429429
}
430430

431+
/// Returns true if the given lane is previously pressed and now unpressed.
432+
/// When the virtual input is mapped to multiple actual inputs
433+
/// it can update the internal state but still return false.
434+
pub fn is_unpressed(&mut self, lane: Lane, continuous: bool, state: InputState) -> bool {
435+
let lane = lane.to_uint();
436+
if state == Neutral || (continuous && self.joystate[lane] != state) {
437+
if continuous {
438+
self.joystate[lane] = state;
439+
true
440+
} else {
441+
if self.keymultiplicity[lane] > 0 {
442+
self.keymultiplicity[lane] -= 1;
443+
}
444+
(self.keymultiplicity[lane] == 0)
445+
}
446+
} else {
447+
false
448+
}
449+
}
450+
451+
/// Returns true if the given lane is previously unpressed and now pressed.
452+
/// When the virtual input is mapped to multiple actual inputs
453+
/// it can update the internal state but still return false.
454+
pub fn is_pressed(&mut self, lane: Lane, continuous: bool, state: InputState) -> bool {
455+
let lane = lane.to_uint();
456+
if state != Neutral {
457+
if continuous {
458+
self.joystate[lane] = state;
459+
true
460+
} else {
461+
self.keymultiplicity[lane] += 1;
462+
(self.keymultiplicity[lane] == 1)
463+
}
464+
} else {
465+
false
466+
}
467+
}
468+
469+
/// Processes the unpress event at given lane:
470+
/// checks if we need to issue a MISS grade.
471+
pub fn process_unpress(&mut self, lane: Lane) {
472+
// if LN grading is in progress and it is not within the threshold then
473+
// MISS grade is issued
474+
let nextlndone =
475+
self.thru[lane.to_uint()].as_ref().and_then(|thru| {
476+
thru.find_next_of_type(|obj| {
477+
obj.object_lane() == Some(lane) &&
478+
obj.is_lndone()
479+
})
480+
});
481+
for p in nextlndone.iter() {
482+
let delta = (p.loc.vtime - self.cur.loc.vtime) * self.gradefactor;
483+
if num::abs(delta) < BAD_CUTOFF {
484+
self.nograding[p.index] = true;
485+
} else {
486+
self.update_grade_to_miss();
487+
}
488+
}
489+
self.thru[lane.to_uint()] = None;
490+
}
491+
492+
/// Processes the press event at given lane:
493+
/// plays the closest key sound if any, and grades the closest gradable object if possible.
494+
pub fn process_press(&mut self, lane: Lane) {
495+
// plays the closest key sound
496+
let soundable =
497+
self.cur.find_closest_of_type(VirtualTime, |obj| {
498+
obj.object_lane() == Some(lane) && obj.is_soundable()
499+
});
500+
for p in soundable.iter() {
501+
for &sref in p.sounds().iter() {
502+
self.play_sound(sref, false);
503+
}
504+
}
505+
506+
// tries to grade the closest gradable object in the grading area
507+
let gradable =
508+
self.cur.find_closest_of_type(VirtualTime, |obj| {
509+
obj.object_lane() == Some(lane) && obj.is_gradable()
510+
});
511+
for p in gradable.iter() {
512+
if p.index >= self.checked.index && !self.nograding[p.index] && !p.is_lndone() {
513+
let dist = (p.loc.vtime - self.cur.loc.vtime) * self.gradefactor;
514+
if num::abs(dist) < BAD_CUTOFF {
515+
if p.is_lnstart() { self.thru[lane.to_uint()] = Some(p.clone()); }
516+
self.nograding[p.index] = true;
517+
self.update_grade_from_distance(dist);
518+
}
519+
}
520+
}
521+
}
522+
431523
/// Updates the player state. Returns `true` if the caller should keep calling `tick`.
432524
pub fn tick(&mut self) -> bool {
433525
let opts_ = self.opts.clone();
@@ -446,21 +538,19 @@ impl Player {
446538
}
447539

448540
self.now = get_ticks();
449-
let mut cur = self.cur.clone();
450-
let mut checked = self.checked.clone();
451-
let mut thru = self.thru.clone();
452541
let prev = self.cur.clone();
453542

454543
let curtime = (self.now - self.origintime) as f64 / 1000.0 + self.origin.loc.time;
455544
match self.reverse {
456545
Some(ref reverse) => {
457546
assert!(self.bpm.to_f64() < 0.0 && curtime >= reverse.loc.time);
458547
let newpos = reverse.loc.pos + self.bpm.sec_to_measure(curtime - reverse.loc.time);
459-
cur.seek(ActualPos, newpos - cur.loc.pos);
548+
self.cur.seek(ActualPos, newpos - self.cur.loc.pos);
460549
}
461550
None => {
462551
// apply object-like effects while advancing `self.cur`
463-
for p in cur.mut_until(ActualTime, curtime - cur.loc.time) {
552+
let mut cur = self.cur.clone();
553+
for p in cur.mut_until(ActualTime, curtime - self.cur.loc.time) {
464554
match p.data() {
465555
BGM(sref) => {
466556
self.play_sound_if_nonzero(sref, true);
@@ -487,30 +577,33 @@ impl Player {
487577
_ => {}
488578
}
489579
}
580+
self.cur = cur;
490581
}
491582
}
492583

493584
// grade objects that have escaped the grading area
494585
if !opts.is_autoplay() {
495-
for p in checked.mut_upto(&cur) {
496-
let dist = (cur.loc.vtime - p.loc.vtime) * self.gradefactor;
586+
let mut checked = self.checked.clone();
587+
for p in checked.mut_upto(&self.cur) {
588+
let dist = (self.cur.loc.vtime - p.loc.vtime) * self.gradefactor;
497589
if dist < BAD_CUTOFF { break; }
498590

499591
if !self.nograding[p.index] {
500592
for &Lane(lane) in p.object_lane().iter() {
501593
let missable =
502594
match p.data() {
503595
Visible(..) | LNStart(..) => true,
504-
LNDone(..) => thru[lane].is_some(),
596+
LNDone(..) => self.thru[lane].is_some(),
505597
_ => false,
506598
};
507599
if missable {
508600
self.update_grade_to_miss();
509-
thru[lane] = None;
601+
self.thru[lane] = None;
510602
}
511603
}
512604
}
513605
}
606+
self.checked = checked;
514607
}
515608

516609
// process inputs
@@ -537,91 +630,6 @@ impl Player {
537630

538631
if opts.is_exclusive() { continue; }
539632

540-
// Returns true if the given lane is previously pressed and now unpressed.
541-
// When the virtual input is mapped to multiple actual inputs it can update
542-
// the internal state but still return false.
543-
let is_unpressed = |lane: Lane, continuous: bool, state: InputState| {
544-
let lane = lane.to_uint();
545-
if state == Neutral || (continuous && self.joystate[lane] != state) {
546-
if continuous {
547-
self.joystate[lane] = state; true
548-
} else {
549-
if self.keymultiplicity[lane] > 0 {
550-
self.keymultiplicity[lane] -= 1;
551-
}
552-
(self.keymultiplicity[lane] == 0)
553-
}
554-
} else {
555-
false
556-
}
557-
};
558-
559-
// Returns true if the given lane is previously unpressed and now pressed.
560-
// When the virtual input is mapped to multiple actual inputs it can update
561-
// the internal state but still return false.
562-
let is_pressed = |lane: Lane, continuous: bool, state: InputState| {
563-
let lane = lane.to_uint();
564-
if state != Neutral {
565-
if continuous {
566-
self.joystate[lane] = state; true
567-
} else {
568-
self.keymultiplicity[lane] += 1;
569-
(self.keymultiplicity[lane] == 1)
570-
}
571-
} else {
572-
false
573-
}
574-
};
575-
576-
let process_unpress = |lane: Lane| {
577-
// if LN grading is in progress and it is not within the threshold then
578-
// MISS grade is issued
579-
for thru in thru[lane.to_uint()].iter() {
580-
let nextlndone = thru.find_next_of_type(|obj| {
581-
obj.object_lane() == Some(lane) && obj.is_lndone()
582-
});
583-
for p in nextlndone.iter() {
584-
let delta = (p.loc.vtime - cur.loc.vtime) * self.gradefactor;
585-
if num::abs(delta) < BAD_CUTOFF {
586-
self.nograding[p.index] = true;
587-
} else {
588-
self.update_grade_to_miss();
589-
}
590-
}
591-
}
592-
thru[lane.to_uint()] = None;
593-
};
594-
595-
let process_press = |lane: Lane| {
596-
// plays the closest key sound
597-
let soundable =
598-
cur.find_closest_of_type(VirtualTime, |obj| {
599-
obj.object_lane() == Some(lane) && obj.is_soundable()
600-
});
601-
for p in soundable.iter() {
602-
for &sref in p.sounds().iter() {
603-
self.play_sound(sref, false);
604-
}
605-
}
606-
607-
// tries to grade the closest gradable object in the grading area
608-
let gradable =
609-
cur.find_closest_of_type(VirtualTime, |obj| {
610-
obj.object_lane() == Some(lane) && obj.is_gradable()
611-
});
612-
for p in gradable.iter() {
613-
if p.index >= checked.index && !self.nograding[p.index] && !p.is_lndone() {
614-
let dist = (p.loc.vtime - cur.loc.vtime) * self.gradefactor;
615-
if num::abs(dist) < BAD_CUTOFF {
616-
if p.is_lnstart() { thru[lane.to_uint()] = Some(p.clone()); }
617-
self.nograding[p.index] = true;
618-
self.update_grade_from_distance(dist);
619-
}
620-
}
621-
}
622-
true
623-
};
624-
625633
match (vkey, state) {
626634
(SpeedDownInput, Positive) | (SpeedDownInput, Negative) => {
627635
let current = self.targetspeed.unwrap_or(self.playspeed);
@@ -639,11 +647,11 @@ impl Player {
639647
}
640648
(LaneInput(lane), state) => {
641649
if !opts.is_autoplay() {
642-
if is_unpressed(lane, continuous, state) {
643-
process_unpress(lane);
650+
if self.is_unpressed(lane, continuous, state) {
651+
self.process_unpress(lane);
644652
}
645-
if is_pressed(lane, continuous, state) {
646-
process_press(lane);
653+
if self.is_pressed(lane, continuous, state) {
654+
self.process_press(lane);
647655
}
648656
}
649657
}
@@ -654,17 +662,17 @@ impl Player {
654662

655663
// process bombs
656664
if !opts.is_autoplay() {
657-
for p in prev.upto(&cur) {
665+
for p in prev.upto(&self.cur) {
658666
match p.data() {
659667
Bomb(lane,sref,damage) if self.key_pressed(lane) => {
660668
// ongoing long note is not graded twice
661-
thru[lane.to_uint()] = None;
669+
self.thru[lane.to_uint()] = None;
662670
for &sref in sref.iter() {
663671
self.play_sound(sref, false);
664672
}
665673
if !self.update_grade_from_damage(damage) {
666674
// instant death
667-
self.cur = cur.find_end();
675+
self.cur = self.cur.find_end();
668676
return false;
669677
}
670678
}
@@ -673,10 +681,6 @@ impl Player {
673681
}
674682
}
675683

676-
self.cur = cur;
677-
self.checked = checked;
678-
self.thru = thru;
679-
680684
// determines if we should keep playing
681685
if self.cur.index == self.timeline.borrow().objs.len() {
682686
if opts.is_autoplay() {

0 commit comments

Comments
 (0)