Skip to content

Commit 1dc2a5d

Browse files
authored
Merge pull request #373 from ChickenPige0n/rpe-150-update
RPE 1.5.0 update
2 parents 81dc46c + c766848 commit 1dc2a5d

File tree

16 files changed

+407
-126
lines changed

16 files changed

+407
-126
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@ inner.rs
4343

4444
# Test
4545

46+
/test
4647
/log*
4748
/build_event_debug.sh

phira/src/scene.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,21 @@ pub fn render_release_to_refresh(ui: &mut Ui, cx: f32, off: f32) {
390390
.color(semi_white(p * 0.8))
391391
.draw();
392392
}
393+
394+
#[cfg(test)]
395+
mod tests {
396+
use std::ops::DerefMut;
397+
398+
use fs::load_info;
399+
400+
use super::*;
401+
402+
#[tokio::test]
403+
async fn test_parse_chart() -> Result<()> {
404+
// Put the chart in phira(workspace, not crate)/test which is ignored by git
405+
let mut fs = fs_from_path("../../../test")?;
406+
let info = load_info(fs.as_mut()).await?;
407+
let _chart = prpr::scene::GameScene::load_chart(fs.deref_mut(), &info).await?;
408+
Ok(())
409+
}
410+
}

prpr/locales/en-US/parser.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ incline-events-parse-failed = Failed to parse incline events
1010
paint-events-parse-failed = Failed to parse paint events
1111
text-events-parse-failed = Failed to parse text events
1212
color-events-parse-failed = Failed to parse color events
13+
gif-events-parse-failed = Failed to parse gif events
1314
1415
illustration-load-failed = Failed to load illustration at { $path }
16+
gif-load-failed = Failed to load gif at { $path }
1517
1618
judge-line-location-name = In judge line #{ $jlid } ({ $name })
19+
hitsound-missing = Hitsound `{ $name }` is missing
1720
1821
# pgr
1922
event-not-contiguous = Events should be contiguous

prpr/locales/zh-CN/parser.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ incline-events-parse-failed = incline 事件解析失败
1010
paint-events-parse-failed = paint 事件解析失败
1111
text-events-parse-failed = text 事件解析失败
1212
color-events-parse-failed = color 事件解析失败
13+
gif-events-parse-failed = gif 事件解析失败
1314
1415
illustration-load-failed = 位于 { $path } 的插图加载失败
16+
gif-load-failed = 位于 { $path } 的 gif 加载失败
1517
1618
judge-line-location-name = #{ $jlid } ({ $name }) 判定线中
19+
hitsound-missing = 缺少打击音 `{ $name }`
1720
1821
# pgr
1922
event-not-contiguous = 事件应当连续

prpr/src/bin.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ use crate::{
1515
Anim, AnimVector, BezierTween, BpmList, Chart, ChartExtra, ChartSettings, ClampedTween, CtrlObject, JudgeLine, JudgeLineCache, JudgeLineKind,
1616
Keyframe, Note, NoteKind, Object, StaticTween, Tweenable, UIElement,
1717
},
18-
judge::JudgeStatus,
18+
judge::{HitSound, JudgeStatus},
1919
parse::process_lines,
2020
};
2121
use anyhow::{bail, Result};
2222
use byteorder::{LittleEndian as LE, ReadBytesExt, WriteBytesExt};
2323
use macroquad::{prelude::Color, texture::Texture2D};
2424
use std::{
2525
cell::RefCell,
26+
collections::HashMap,
2627
io::{Read, Write},
2728
ops::Deref,
2829
rc::Rc,
@@ -315,18 +316,22 @@ impl BinaryData for CtrlObject {
315316

316317
impl BinaryData for Note {
317318
fn read_binary<R: Read>(r: &mut BinaryReader<R>) -> Result<Self> {
318-
Ok(Self {
319-
object: r.read()?,
320-
kind: match r.read::<u8>()? {
321-
0 => NoteKind::Click,
322-
1 => NoteKind::Hold {
323-
end_time: r.read()?,
324-
end_height: r.read()?,
325-
},
326-
2 => NoteKind::Flick,
327-
3 => NoteKind::Drag,
328-
_ => bail!("invalid note kind"),
319+
let object = r.read()?;
320+
let kind = match r.read::<u8>()? {
321+
0 => NoteKind::Click,
322+
1 => NoteKind::Hold {
323+
end_time: r.read()?,
324+
end_height: r.read()?,
329325
},
326+
2 => NoteKind::Flick,
327+
3 => NoteKind::Drag,
328+
_ => bail!("invalid note kind"),
329+
};
330+
let hitsound = HitSound::default_from_kind(&kind);
331+
Ok(Self {
332+
object,
333+
kind,
334+
hitsound,
330335
time: r.time()?,
331336
height: r.read()?,
332337
speed: if r.read()? { r.read::<f32>()? } else { 1. },
@@ -374,6 +379,7 @@ impl BinaryData for JudgeLine {
374379
1 => JudgeLineKind::Texture(Texture2D::empty().into(), r.read()?),
375380
2 => JudgeLineKind::Text(r.read()?),
376381
3 => JudgeLineKind::Paint(r.read()?, RefCell::default()),
382+
4 => unimplemented!(),
377383
_ => bail!("invalid judge line kind"),
378384
};
379385
let height = r.read()?;
@@ -423,6 +429,9 @@ impl BinaryData for JudgeLine {
423429
w.write_val(3_u8)?;
424430
w.write(events)?;
425431
}
432+
JudgeLineKind::TextureGif(..) => {
433+
bail!("gif texture binary not supported");
434+
}
426435
}
427436
w.write(&self.height)?;
428437
w.array(&self.notes)?;
@@ -461,7 +470,7 @@ impl BinaryData for Chart {
461470
let mut lines = r.array()?;
462471
process_lines(&mut lines);
463472
let settings = r.read()?;
464-
Ok(Chart::new(offset, lines, BpmList::new(vec![(0., 60.)]), settings, ChartExtra::default()))
473+
Ok(Chart::new(offset, lines, BpmList::new(vec![(0., 60.)]), settings, ChartExtra::default(), HashMap::new()))
465474
}
466475

467476
fn write_binary<W: Write>(&self, w: &mut BinaryWriter<W>) -> Result<()> {

prpr/src/core.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ mod anim;
2525
pub use anim::{Anim, AnimFloat, AnimVector, Keyframe};
2626

2727
mod chart;
28-
pub use chart::{Chart, ChartExtra, ChartSettings};
28+
pub use chart::{Chart, ChartExtra, ChartSettings, HitSoundMap};
2929

3030
mod effect;
3131
pub use effect::{Effect, Uniform};
3232

3333
mod line;
34-
pub use line::{JudgeLine, JudgeLineCache, JudgeLineKind, UIElement};
34+
pub use line::{GifFrames, JudgeLine, JudgeLineCache, JudgeLineKind, UIElement};
3535

3636
mod note;
3737
use macroquad::prelude::set_pc_assets_folder;
38-
pub use note::{BadNote, Note, NoteKind, RenderConfig};
38+
pub use note::{BadNote, HitSound, Note, NoteKind, RenderConfig};
3939

4040
mod object;
4141
pub use object::{CtrlObject, Object};
@@ -44,7 +44,7 @@ mod render;
4444
pub use render::{copy_fbo, internal_id, MSRenderTarget};
4545

4646
mod resource;
47-
pub use resource::{NoteStyle, ParticleEmitter, ResPackInfo, Resource, ResourcePack, DPI_VALUE};
47+
pub use resource::{NoteStyle, ParticleEmitter, ResPackInfo, Resource, ResourcePack, BUFFER_SIZE, DPI_VALUE};
4848

4949
mod smooth;
5050
pub use smooth::Smooth;

prpr/src/core/chart.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use super::{BpmList, Effect, JudgeLine, JudgeLineKind, Matrix, Resource, UIEleme
22
use crate::{fs::FileSystem, judge::JudgeStatus, ui::Ui};
33
use anyhow::{Context, Result};
44
use macroquad::prelude::*;
5-
use std::cell::RefCell;
5+
use sasa::AudioClip;
6+
use std::{cell::RefCell, collections::HashMap};
67
use tracing::warn;
78

89
#[derive(Default)]
@@ -19,6 +20,8 @@ pub struct ChartSettings {
1920
pub hold_partial_cover: bool,
2021
}
2122

23+
pub type HitSoundMap = HashMap<String, AudioClip>;
24+
2225
pub struct Chart {
2326
pub offset: f32,
2427
pub lines: Vec<JudgeLine>,
@@ -33,10 +36,12 @@ pub struct Chart {
3336
pub order: Vec<usize>,
3437
/// TODO: docs from RPE
3538
pub attach_ui: [Option<usize>; 7],
39+
40+
pub hitsounds: HitSoundMap,
3641
}
3742

3843
impl Chart {
39-
pub fn new(offset: f32, lines: Vec<JudgeLine>, bpm_list: BpmList, settings: ChartSettings, extra: ChartExtra) -> Self {
44+
pub fn new(offset: f32, lines: Vec<JudgeLine>, bpm_list: BpmList, settings: ChartSettings, extra: ChartExtra, hitsounds: HitSoundMap) -> Self {
4045
let mut attach_ui = [None; 7];
4146
let mut order = (0..lines.len())
4247
.filter(|it| {
@@ -58,6 +63,8 @@ impl Chart {
5863

5964
order,
6065
attach_ui,
66+
67+
hitsounds,
6168
}
6269
}
6370

prpr/src/core/line.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,46 @@ impl UIElement {
3939
}
4040
}
4141

42+
pub struct GifFrames {
43+
/// time of each frame in milliseconds
44+
frames: Vec<(u128, SafeTexture)>,
45+
/// milliseconds
46+
total_time: u128,
47+
}
48+
49+
impl GifFrames {
50+
pub fn new(frames: Vec<(u128, SafeTexture)>) -> Self {
51+
let total_time = frames.iter().map(|(time, _)| *time).sum();
52+
Self { frames, total_time }
53+
}
54+
55+
pub fn get_time_frame(&self, time: u128) -> &SafeTexture {
56+
let mut time = time % self.total_time;
57+
for (t, frame) in &self.frames {
58+
if time < *t {
59+
return frame;
60+
}
61+
time -= t;
62+
}
63+
&self.frames.last().unwrap().1
64+
}
65+
66+
pub fn get_prog_frame(&self, prog: f32) -> &SafeTexture {
67+
let time = (prog * self.total_time as f32) as u128;
68+
self.get_time_frame(time)
69+
}
70+
71+
pub fn total_time(&self) -> u128 {
72+
self.total_time
73+
}
74+
}
75+
4276
#[derive(Default)]
4377
pub enum JudgeLineKind {
4478
#[default]
4579
Normal,
4680
Texture(SafeTexture, String),
81+
TextureGif(Anim<f32>, GifFrames, String),
4782
Text(Anim<String>),
4883
Paint(Anim<f32>, RefCell<(Option<RenderPass>, bool)>),
4984
}
@@ -141,6 +176,9 @@ impl JudgeLine {
141176
JudgeLineKind::Paint(anim, ..) => {
142177
anim.set_time(res.time);
143178
}
179+
JudgeLineKind::TextureGif(anim, ..) => {
180+
anim.set_time(res.time);
181+
}
144182
_ => {}
145183
}
146184
self.color.set_time(res.time);
@@ -215,6 +253,24 @@ impl JudgeLine {
215253
},
216254
);
217255
}
256+
JudgeLineKind::TextureGif(anim, frames, _) => {
257+
let t = anim.now_opt().unwrap_or(0.0);
258+
let frame = frames.get_prog_frame(t);
259+
let mut color = color.unwrap_or(WHITE);
260+
color.a = alpha.max(0.0);
261+
let hf = vec2(frame.width(), frame.height());
262+
draw_texture_ex(
263+
**frame,
264+
-hf.x / 2.,
265+
-hf.y / 2.,
266+
color,
267+
DrawTextureParams {
268+
dest_size: Some(hf),
269+
flip_y: true,
270+
..Default::default()
271+
},
272+
);
273+
}
218274
JudgeLineKind::Text(anim) => {
219275
let mut color = color.unwrap_or(WHITE);
220276
color.a = alpha.max(0.0);

prpr/src/core/note.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use super::{chart::ChartSettings, BpmList, CtrlObject, JudgeLine, Matrix, Object, Point, Resource};
2-
use crate::{judge::JudgeStatus, parse::RPE_HEIGHT};
2+
pub use crate::{
3+
judge::{HitSound, JudgeStatus},
4+
parse::RPE_HEIGHT,
5+
};
36
use macroquad::prelude::*;
47

58
const HOLD_PARTICLE_INTERVAL: f32 = 0.15;
@@ -28,6 +31,7 @@ impl NoteKind {
2831
pub struct Note {
2932
pub object: Object,
3033
pub kind: NoteKind,
34+
pub hitsound: HitSound,
3135
pub time: f32,
3236
pub height: f32,
3337
pub speed: f32,

prpr/src/core/resource.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@ use macroquad::prelude::*;
1111
use miniquad::{gl::GLuint, Texture, TextureWrap};
1212
use sasa::{AudioClip, AudioManager, Sfx};
1313
use serde::Deserialize;
14-
use std::{cell::RefCell, collections::BTreeMap, ops::DerefMut, path::Path, sync::atomic::AtomicU32};
14+
use std::{
15+
cell::RefCell,
16+
collections::{BTreeMap, HashMap},
17+
ops::DerefMut,
18+
path::Path,
19+
sync::atomic::AtomicU32,
20+
};
1521

1622
pub const MAX_SIZE: usize = 64; // needs tweaking
1723
pub static DPI_VALUE: AtomicU32 = AtomicU32::new(250);
24+
pub const BUFFER_SIZE: usize = 1024;
1825

1926
#[inline]
2027
fn default_scale() -> f32 {
@@ -333,6 +340,8 @@ impl NoteBuffer {
333340
}
334341
}
335342

343+
pub type SfxMap = HashMap<String, Sfx>;
344+
336345
pub struct Resource {
337346
pub config: Config,
338347
pub info: ChartInfo,
@@ -367,6 +376,8 @@ pub struct Resource {
367376
pub sfx_drag: Sfx,
368377
pub sfx_flick: Sfx,
369378

379+
pub extra_sfxs: SfxMap,
380+
370381
pub chart_target: Option<MSRenderTarget>,
371382
pub no_effect: bool,
372383

@@ -424,7 +435,7 @@ impl Resource {
424435
let mut audio = create_audio_manger(&config)?;
425436
let music = AudioClip::new(fs.load_file(&info.music).await?)?;
426437
let track_length = music.length();
427-
let buffer_size = Some(1024);
438+
let buffer_size = Some(BUFFER_SIZE);
428439
let sfx_click = audio.create_sfx(res_pack.sfx_click.clone(), buffer_size)?;
429440
let sfx_drag = audio.create_sfx(res_pack.sfx_drag.clone(), buffer_size)?;
430441
let sfx_flick = audio.create_sfx(res_pack.sfx_flick.clone(), buffer_size)?;
@@ -471,6 +482,7 @@ impl Resource {
471482
sfx_click,
472483
sfx_drag,
473484
sfx_flick,
485+
extra_sfxs: SfxMap::new(),
474486

475487
chart_target: None,
476488
no_effect,
@@ -481,6 +493,10 @@ impl Resource {
481493
})
482494
}
483495

496+
pub fn create_sfx(&mut self, clip: AudioClip) -> Result<Sfx> {
497+
self.audio.create_sfx(clip, Some(BUFFER_SIZE))
498+
}
499+
484500
pub fn emit_at_origin(&mut self, rotation: f32, color: Color) {
485501
if !self.config.particle {
486502
return;

0 commit comments

Comments
 (0)