1
0
mirror of synced 2024-11-30 16:54:30 +01:00

Better Pop'n Music Peace support

This commit is contained in:
cracrayol 2021-09-04 18:21:27 +02:00
parent c64efa5860
commit 1f5b0368ca
6 changed files with 184 additions and 9 deletions

View File

@ -219,7 +219,7 @@ This should be given the same config file as "api", "frontend" and "services".
Development version of an eAmusement protocol server using flask and the protocol
libraries also used in "bemanishark" and "trafficgen". Currently it lets most modern
BEMANI games boot and supports full profile and events for Beatmania IIDX 20-26,
Pop'n Music 19-24, Jubeat Saucer, Saucer Fulfill, Prop, Qubell and Clan, Sound Voltex
Pop'n Music 19-25, Jubeat Saucer, Saucer Fulfill, Prop, Qubell and Clan, Sound Voltex
1, 2, 3 Season 1/2 and 4, Dance Dance Revolution X2, X3, 2013, 2014 and Ace, MÚSECA 1,
MÚSECA 1+1/2, MÚSECA Plus, Reflec Beat, Limelight, Colette, groovin'!! Upper, Volzza
1 and Volzza 2, Metal Gear Arcade, and finally The\*BishiBashi.
@ -251,7 +251,7 @@ this will run through and attempt to verify simple operation of that service. No
guarantees are made on the accuracy of the emulation though I've strived to be
correct. In some cases, I will verify the response, and in other cases I will
simply verify that certain things exist so as not to crash a real client. This
currently generates traffic emulating Beatmania IIDX 20-26, Pop'n Music 19-24, Jubeat
currently generates traffic emulating Beatmania IIDX 20-26, Pop'n Music 19-25, Jubeat
Saucer, Fulfill, Prop, Qubell and Clan, Sound Voltex 1, 2, 3 Season 1/2 and 4, Dance
Dance Revolution X2, X3, 2013, 2014 and Ace, The\*BishiBashi, MÚSECA 1 and MÚSECA 1+1/2,
Reflec Beat, Reflec Beat Limelight, Reflec Beat Colette, groovin'!! Upper, Volzza 1 and
@ -398,7 +398,7 @@ do that.
### Pop'n Music
For Pop'n Music, get the game DLL from the version of the game you want to import and
run a command like so. This network supports versions 19-24 so you will want to run this
run a command like so. This network supports versions 19-25 so you will want to run this
command once for every version, giving the correct DLL file:
```

View File

@ -1,13 +1,74 @@
# vim: set fileencoding=utf-8
from typing import Dict
from bemani.backend.popn.base import PopnMusicBase
from bemani.backend.popn.usaneko import PopnMusicUsaNeko
from bemani.common import VersionConstants
class PopnMusicPeace(PopnMusicBase):
class PopnMusicPeace(PopnMusicUsaNeko):
name = "Pop'n Music peace"
version = VersionConstants.POPN_MUSIC_PEACE
# Biggest ID in the music DB
GAME_MAX_MUSIC_ID = 1877
def previous_version(self) -> PopnMusicBase:
return PopnMusicUsaNeko(self.data, self.config, self.model)
def get_phases(self) -> Dict[int, int]:
# Event phases
# TODO: Hook event mode settings up to the front end.
return {
# Default song phase availability (0-23)
0: 23,
# Unknown event (0-2)
1: 2,
# Unknown event (0-2)
2: 2,
# Unknown event (0-4)
3: 4,
# Unknown event (0-1)
4: 1,
# Enable Net Taisen, including win/loss display on song select (0-1)
5: 1,
# Enable NAVI-kun shunkyoku toujou, allows song 1608 to be unlocked (0-1)
6: 1,
# Unknown event (0-1)
7: 1,
# Unknown event (0-2)
8: 2,
# Daily Mission (0-2)
9: 2,
# NAVI-kun Song phase availability (0-30)
10: 30,
# Unknown event (0-1)
11: 1,
# Unknown event (0-2)
12: 2,
# Enable Pop'n Peace preview song (0-1)
13: 1,
# Unknown event (0-39)
14: 39,
# Unknown event (0-2)
15: 2,
# Unknown event (0-3)
16: 3,
# Unknown event (0-8)
17: 8,
# Unknown event (0-1)
28: 1,
# Unknown event (0-1)
19: 1,
# Unknown event (0-13)
20: 13,
# Pop'n event archive song phase availability (0-20)
21: 20,
# Unknown event (0-2)
22: 2,
# Unknown event (0-1)
23: 1,
# Unknown event (0-1)
24: 1,
}

View File

@ -126,10 +126,10 @@ class PopnMusicUsaNeko(PopnMusicBase):
self.update_machine_name(request.child_value('pcb_setting/name'))
return Node.void('pcb24')
def __construct_common_info(self, root: Node) -> None:
def get_phases(self) -> Dict[int, int]:
# Event phases
# TODO: Hook event mode settings up to the front end.
phases = {
return {
# Default song phase availability (0-11)
0: 11,
# Unknown event (0-2)
@ -160,11 +160,12 @@ class PopnMusicUsaNeko(PopnMusicBase):
13: 1,
}
for phaseid in phases:
def __construct_common_info(self, root: Node) -> None:
for phaseid in self.get_phases():
phase = Node.void('phase')
root.add_child(phase)
phase.add_child(Node.s16('event_id', phaseid))
phase.add_child(Node.s16('phase', phases[phaseid]))
phase.add_child(Node.s16('phase', self.get_phases()[phaseid]))
# Gather course informatino and course ranking for users.
course_infos, achievements, profiles = Parallel.execute([

View File

@ -371,6 +371,7 @@ class ImportPopn(ImportBase):
'22': VersionConstants.POPN_MUSIC_LAPISTORIA,
'23': VersionConstants.POPN_MUSIC_ECLALE,
'24': VersionConstants.POPN_MUSIC_USANEKO,
'25': VersionConstants.POPN_MUSIC_PEACE,
}.get(version, -1)
if actual_version == VersionConstants.POPN_MUSIC_TUNE_STREET:
@ -382,7 +383,7 @@ class ImportPopn(ImportBase):
# Newer pop'n has charts for easy, normal, hyper, another
self.charts = [0, 1, 2, 3]
else:
raise Exception("Unsupported Pop'n Music version, expected one of the following: 19, 20, 21, 22, 23, 24!")
raise Exception("Unsupported Pop'n Music version, expected one of the following: 19, 20, 21, 22, 23, 24, 25!")
super().__init__(config, GameConstants.POPN_MUSIC, actual_version, no_combine, update)
@ -957,6 +958,104 @@ class ImportPopn(ImportBase):
'I'
)
# Decoding function for chart masks
def available_charts(mask: int) -> Tuple[bool, bool, bool, bool, bool, bool]:
return (
mask & 0x0080000 > 0, # Easy chart bit
True, # Always a normal chart
mask & 0x1000000 > 0, # Hyper chart bit
mask & 0x2000000 > 0, # Ex chart bit
True, # Always a battle normal chart
mask & 0x4000000 > 0, # Battle hyper chart bit
)
elif self.version == VersionConstants.POPN_MUSIC_PEACE:
# Based on M39:J:A:A:2020092800
# Normal offset for music DB, size
offset = 0x2C7C78
step = 172
length = 1877
# Offset and step of file DB
file_offset = 0x2B8010
file_step = 32
# Standard lookups
genre_offset = 0
title_offset = 1
artist_offset = 2
comment_offset = 3
english_title_offset = 4
english_artist_offset = 5
extended_genre_offset = -1
charts_offset = 8
folder_offset = 9
# Offsets for normal chart difficulties
easy_offset = 12
normal_offset = 13
hyper_offset = 14
ex_offset = 15
# Offsets for battle chart difficulties
battle_normal_offset = 16
battle_hyper_offset = 17
# Offsets into which offset to seek to for file lookups
easy_file_offset = 18
normal_file_offset = 19
hyper_file_offset = 20
ex_file_offset = 21
battle_normal_file_offset = 22
battle_hyper_file_offset = 23
packedfmt = (
'<'
'I' # Genre
'I' # Title
'I' # Artist
'I' # Comment
'I' # English Title
'I' # English Artist
'H' # ??
'H' # ??
'I' # Available charts mask
'I' # Folder
'I' # Event unlocks?
'I' # Event unlocks?
'B' # Easy difficulty
'B' # Normal difficulty
'B' # Hyper difficulty
'B' # EX difficulty
'B' # Battle normal difficulty
'B' # Battle hyper difficulty
'xx' # Unknown pointer
'H' # Easy chart pointer
'H' # Normal chart pointer
'H' # Hyper chart pointer
'H' # EX chart pointer
'H' # Battle normal pointer
'H' # Battle hyper pointer
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
)
# Offsets into file DB for finding file and folder.
file_folder_offset = 0
file_name_offset = 1
filefmt = (
'<'
'I' # Folder
'I' # Filename
'I'
'I'
'I'
'I'
'I'
'I'
)
# Decoding function for chart masks
def available_charts(mask: int) -> Tuple[bool, bool, bool, bool, bool, bool]:
return (

View File

@ -94,6 +94,12 @@ def get_client(proto: ClientProtocol, pcbid: str, game: str, config: Dict[str, A
pcbid,
config,
)
if game == 'pnm-peace':
return PopnMusicUsaNekoClient(
proto,
pcbid,
config,
)
if game == 'jubeat-saucer':
return JubeatSaucerClient(
proto,
@ -322,6 +328,12 @@ def mainloop(address: str, port: int, configfile: str, action: str, game: str, c
'old_profile_model': "M39:J:B:A",
'avs': "2.15.8 r6631",
},
'pnm-peace': {
'name': "Pop'n Music peace",
'model': "M39:J:B:A:2020092800",
'old_profile_model': "M39:J:B:A",
'avs': "2.15.8 r6631",
},
'jubeat-saucer': {
'name': "Jubeat Saucer",
'model': "L44:J:A:A:2014012802",
@ -534,6 +546,7 @@ def main() -> None:
'pnm-22': 'pnm-lapistoria',
'pnm-23': 'pnm-eclale',
'pnm-24': 'pnm-usaneko',
'pnm-25': 'pnm-peace',
'iidx-20': 'iidx-tricoro',
'iidx-21': 'iidx-spada',
'iidx-22': 'iidx-pendual',

View File

@ -12,6 +12,7 @@ set -e
./read --series pnm --version 22 "$@"
./read --series pnm --version 23 "$@"
./read --series pnm --version 24 "$@"
./read --series pnm --version 25 "$@"
# Init Jubeat
./read --series jubeat --version saucer "$@"