Files
jak-project/game/overlord/jak2/srpc.cpp
T
Hat Kid 93afb02cf4 decomp3: spawn target, add merc and particle buckets and some temporary hacks (#3445)
This includes all the collision stuff needed to spawn `target`,
decompiles the sparticle code and adds some of the PC hacks needed for
merc to run (it doesn't work quite right and looks bad, likely due to a
combination of code copied from Jak 2 and the time of day hacks).

There are a bunch of temporary hacks (see commits) in place to prevent
the game from crashing quite as much, but it is still extremely prone to
doing so due to lots of missing functions/potentially bad decomp.

---------

Co-authored-by: water <awaterford111445@gmail.com>
2024-04-05 00:07:39 -04:00

629 lines
19 KiB
C++

#include "srpc.h"
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "game/common/loader_rpc_types.h"
#include "game/common/player_rpc_types.h"
#include "game/overlord/common/soundcommon.h"
#include "game/overlord/common/srpc.h"
#include "game/overlord/common/ssound.h"
#include "game/overlord/jak2/iso_api.h"
#include "game/overlord/jak2/spustreams.h"
#include "game/overlord/jak2/ssound.h"
#include "game/overlord/jak2/vag.h"
#include "game/runtime.h"
#include "game/sce/iop.h"
#include "game/sound/sndshim.h"
using namespace iop;
namespace jak2 {
// korean inserted
static const char* languages[] = {"ENG", "FRE", "GER", "SPA", "ITA", "JAP", "KOR", "UKE"};
static u32 gInfoEE = 0;
static u32 IopTicks = 0;
static SoundIopInfo info;
constexpr int kPlayerBufSize = 0x50 * 128;
static uint8_t gPlayerBuf[kPlayerBufSize];
constexpr int kLoaderBufSize = 0x50;
static uint8_t gLoaderBuf[kLoaderBufSize];
void srpc_init_globals() {}
void* RPC_Player(unsigned int /*fno*/, void* data, int size) {
if (!gSoundEnable) {
return nullptr;
}
// gFreeMem = QueryTotalFreeMemSize();
if (!PollSema(gSema)) {
if (gMusic) {
if (!gMusicPause && !LookupSound(666)) {
Sound* music = AllocateSound();
if (music != nullptr) {
gMusicFade = 0;
gMusicFadeDir = 1;
SetMusicVol();
music->sound_handle = snd_PlaySoundVolPanPMPB(gMusic, 0, 0x400, -1, 0, 0);
music->id = 666;
music->is_music = 1;
}
}
}
SignalSema(gSema);
}
SetMusicVol();
Sound* music = LookupSound(666);
if (music != nullptr) {
snd_SetSoundVolPan(music->sound_handle, 0x7FFFFFFF, 0);
}
constexpr int kMsgSize = 0x50;
static_assert(sizeof(SoundRpcCommand) == kMsgSize);
int n_messages = size / kMsgSize;
SoundRpcCommand* cmd = (SoundRpcCommand*)(data);
if (!gSoundEnable) {
return nullptr;
}
while (n_messages > 0) {
switch (cmd->j2command) {
case Jak2SoundCommand::play: {
if (!cmd->play.sound_id) {
break;
}
auto sound = LookupSound(cmd->play.sound_id);
if (sound != nullptr) {
// update
sound->params = cmd->play.parms;
sound->is_music = false;
SFXUserData data{};
s32 found = snd_GetSoundUserData(0, nullptr, -1, sound->name, &data);
if ((sound->params.mask & 0x40) == 0) {
s16 fo_min = 5;
if (found && data.data[0])
fo_min = data.data[0];
sound->params.fo_min = fo_min;
}
if ((sound->params.mask & 0x80) == 0) {
s16 fo_max = 30;
if (found && data.data[1])
fo_max = data.data[1];
sound->params.fo_max = fo_max;
}
if ((sound->params.mask & 0x100) == 0) {
s16 fo_curve = 2;
if (found && data.data[2])
fo_curve = data.data[2];
sound->params.fo_curve = fo_curve;
}
UpdateVolume(sound);
snd_SetSoundPitchModifier(sound->sound_handle, sound->params.pitch_mod);
if (sound->params.mask & 0x4) {
snd_SetSoundPitchBend(sound->sound_handle, sound->params.bend);
}
if (sound->params.mask & 0x800) {
snd_SetSoundReg(sound->sound_handle, 0, sound->params.reg[0]);
}
if (sound->params.mask & 0x1000) {
snd_SetSoundReg(sound->sound_handle, 1, sound->params.reg[1]);
}
if (sound->params.mask & 0x2000) {
snd_SetSoundReg(sound->sound_handle, 2, sound->params.reg[2]);
}
} else {
// new sound
sound = AllocateSound();
if (sound == nullptr) {
// no free sounds
break;
}
strcpy_toupper(sound->name, cmd->play.name);
// TODO update params struct
sound->params = cmd->play.parms;
sound->is_music = false;
sound->bank_entry = nullptr;
SFXUserData data{};
s32 found = snd_GetSoundUserData(0, nullptr, -1, sound->name, &data);
if ((sound->params.mask & 0x40) == 0) {
s16 fo_min = 5;
if (found && data.data[0])
fo_min = data.data[0];
sound->params.fo_min = fo_min;
}
if ((sound->params.mask & 0x80) == 0) {
s16 fo_max = 30;
if (found && data.data[1])
fo_max = data.data[1];
sound->params.fo_max = fo_max;
}
if ((sound->params.mask & 0x100) == 0) {
s16 fo_curve = 2;
if (found && data.data[2])
fo_curve = data.data[2];
sound->params.fo_curve = fo_curve;
}
// lg::warn("RPC: PLAY {} v:{}, p:{}", sound->name, GetVolume(sound), GetPan(sound));
s32 handle = snd_PlaySoundByNameVolPanPMPB(0, nullptr, sound->name, GetVolume(sound),
GetPan(sound), sound->params.pitch_mod,
sound->params.bend);
sound->sound_handle = handle;
if (handle != 0) {
sound->id = cmd->play.sound_id;
if (sound->params.mask & 0x800) {
snd_SetSoundReg(sound->sound_handle, 0, sound->params.reg[0]);
}
if (sound->params.mask & 0x1000) {
snd_SetSoundReg(sound->sound_handle, 1, sound->params.reg[1]);
}
if (sound->params.mask & 0x2000) {
snd_SetSoundReg(sound->sound_handle, 2, sound->params.reg[2]);
}
}
}
} break;
case Jak2SoundCommand::pause_sound: {
Sound* sound = LookupSound(cmd->sound_id.sound_id);
if (sound != nullptr) {
snd_PauseSound(sound->sound_handle);
} else {
auto* vs = FindVagStreamId(cmd->sound_id.sound_id);
if (vs) {
PauseVAG(vs, 1);
}
}
} break;
case Jak2SoundCommand::stop_sound: {
Sound* sound = LookupSound(cmd->sound_id.sound_id);
if (sound != nullptr) {
snd_StopSound(sound->sound_handle);
} else {
auto* vs = FindVagStreamId(cmd->sound_id.sound_id);
if (vs) {
StopVagStream(vs, 1);
}
}
} break;
case Jak2SoundCommand::continue_sound: {
Sound* sound = LookupSound(cmd->sound_id.sound_id);
if (sound != nullptr) {
snd_ContinueSound(sound->sound_handle);
} else {
auto* vs = FindVagStreamId(cmd->sound_id.sound_id);
if (vs) {
UnPauseVAG(vs, 1);
}
}
} break;
case Jak2SoundCommand::set_param: {
Sound* sound = LookupSound(cmd->sound_id.sound_id);
u32 mask = cmd->param.parms.mask;
if (sound != nullptr) {
if (mask & 1) {
if (mask & 0x10) {
sound->auto_time = cmd->param.auto_time;
sound->new_volume = cmd->param.parms.volume;
} else {
sound->params.volume = cmd->param.parms.volume;
}
}
if (mask & 0x20) {
sound->params.trans = cmd->param.parms.trans;
}
if (mask & 0x21) {
UpdateVolume(sound);
}
if (mask & 2) {
sound->params.pitch_mod = cmd->param.parms.pitch_mod;
if (mask & 0x10) {
snd_AutoPitch(sound->sound_handle, sound->params.pitch_mod, cmd->param.auto_time,
cmd->param.auto_from);
} else {
snd_SetSoundPitchModifier(sound->sound_handle, cmd->param.parms.pitch_mod);
}
}
if (mask & 4) {
sound->params.bend = cmd->param.parms.bend;
if (mask & 0x10) {
snd_AutoPitchBend(sound->sound_handle, sound->params.bend, cmd->param.auto_time,
cmd->param.auto_from);
} else {
snd_SetSoundPitchBend(sound->sound_handle, cmd->param.parms.bend);
}
}
if (mask & 0x400) {
sound->params.priority = cmd->param.parms.priority;
}
if (mask & 0x8) {
sound->params.group = cmd->param.parms.group;
}
if (mask & 0x40) {
sound->params.fo_min = cmd->param.parms.fo_min;
}
if (mask & 0x80) {
sound->params.fo_max = cmd->param.parms.fo_max;
}
if (mask & 0x100) {
sound->params.fo_curve = cmd->param.parms.fo_curve;
}
if (mask & 0x800) {
sound->params.reg[0] = cmd->param.parms.reg[0];
snd_SetSoundReg(sound->sound_handle, 0, cmd->param.parms.reg[0]);
}
if (mask & 0x1000) {
sound->params.reg[1] = cmd->param.parms.reg[1];
snd_SetSoundReg(sound->sound_handle, 1, cmd->param.parms.reg[1]);
}
if (mask & 0x2000) {
sound->params.reg[2] = cmd->param.parms.reg[2];
snd_SetSoundReg(sound->sound_handle, 2, cmd->param.parms.reg[2]);
}
} else {
auto* vs = FindVagStreamId(cmd->param.sound_id);
if (vs) {
if (mask & 0x2) {
SetVAGStreamPitch(cmd->param.sound_id, cmd->param.parms.pitch_mod);
}
if (mask & 0x20) {
vs->vec3 = cmd->param.parms.trans;
vs->unk_296 = 1;
}
if (mask & 0x40) {
vs->fo_min = cmd->param.parms.fo_min;
}
if (mask & 0x80) {
vs->fo_max = cmd->param.parms.fo_max;
}
if (mask & 0x100) {
vs->fo_curve = cmd->param.parms.fo_curve;
}
if (mask & 0x1) {
vs->vol_multiplier = cmd->param.parms.volume;
}
}
}
} break;
case Jak2SoundCommand::set_master_volume: {
u32 group = cmd->master_volume.group.group;
// FIXME array of set volumes
for (int i = 0; i < 32; i++) {
if (((group >> i) & 1) != 0) {
if (i == 1) {
// gMusicVol = cmd->master_volume.volume;
MasterVolume[1] = cmd->master_volume.volume;
} else if (i == 2) {
MasterVolume[2] = cmd->master_volume.volume;
SetDialogVolume(cmd->master_volume.volume);
} else {
MasterVolume[i] = cmd->master_volume.volume;
snd_SetMasterVolume(i, cmd->master_volume.volume);
SetAllVagsVol(i);
}
}
}
} break;
case Jak2SoundCommand::pause_group: {
snd_PauseAllSoundsInGroup(cmd->group.group);
if (cmd->group.group & 2) {
gMusicPause = 1;
}
if (cmd->group.group & 4) {
PauseVagStreams();
}
} break;
case Jak2SoundCommand::stop_group: {
KillSoundsInGroup(cmd->group.group);
if (cmd->group.group & 4) {
VagCmd local_178;
local_178.header.cmd_kind = 0x402;
local_178.header.mbx_to_reply = 0;
local_178.header.thread_id = 0;
local_178.vag_dir_entry = nullptr;
local_178.name[0] = '\0';
local_178.sound_handler = 0;
local_178.id = 0;
local_178.priority = 0;
StopVagStream(&local_178, 1);
}
} break;
case Jak2SoundCommand::continue_group: {
snd_ContinueAllSoundsInGroup(cmd->group.group);
if (cmd->group.group & 2) {
gMusicPause = 0;
}
if (cmd->group.group & 4) {
UnPauseVagStreams();
}
} break;
case Jak2SoundCommand::set_midi_reg: {
if (cmd->midi_reg.reg == 16) {
snd_SetGlobalExcite(cmd->midi_reg.value);
} else {
Sound* sound = LookupSound(666);
if (sound != nullptr) {
snd_SetMIDIRegister(sound->sound_handle, cmd->midi_reg.reg, cmd->midi_reg.value);
}
}
} break;
case Jak2SoundCommand::set_reverb: {
lg::warn("RPC_Player: unimplemented set_reverb");
// TODO reverb
} break;
case Jak2SoundCommand::set_ear_trans: {
SetEarTrans(&cmd->ear_trans_j2.ear_trans0, &cmd->ear_trans_j2.ear_trans1,
&cmd->ear_trans_j2.cam_trans, cmd->ear_trans_j2.cam_angle);
} break;
case Jak2SoundCommand::shutdown: {
gSoundEnable = 0;
} break;
case Jak2SoundCommand::set_fps: {
gFPS = cmd->fps.fps;
} break;
default:
ASSERT_MSG(false, fmt::format("Unhandled RPC Player command {}", int(cmd->j2command)));
}
n_messages--;
cmd++;
}
return nullptr;
}
void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
constexpr int kMsgSize = 0x50;
static_assert(sizeof(SoundRpcCommand) == kMsgSize);
int n_messages = size / kMsgSize;
SoundRpcCommand* cmd = (SoundRpcCommand*)(data);
if (!gSoundEnable) {
return nullptr;
}
while (n_messages > 0) {
switch (cmd->j2command) {
case Jak2SoundCommand::load_bank: {
if (LookupBank(cmd->load_bank.bank_name)) {
break;
}
auto bank = AllocateBankName(cmd->load_bank.bank_name);
if (bank == nullptr) {
break;
}
strncpy(bank->name.data(), cmd->load_bank.bank_name, 16);
bank->in_use = true;
bank->unk4 = 0;
LoadSoundBank(cmd->load_bank.bank_name, bank);
} break;
case Jak2SoundCommand::load_music: {
while (WaitSema(gSema))
;
if (gMusic) {
UnLoadMusic(&gMusic);
}
LoadMusic(cmd->load_bank.bank_name, &gMusic);
SignalSema(gSema);
} break;
case Jak2SoundCommand::unload_bank: {
auto bank = LookupBank(cmd->load_bank.bank_name);
if (!bank) {
break;
}
auto handle = bank->bank_handle;
if (!bank->unk4) {
bank->in_use = false;
}
bank->in_use = false;
snd_UnloadBank(handle);
snd_ResolveBankXREFS();
} break;
case Jak2SoundCommand::get_irx_version: {
cmd->irx_version.major = 4;
cmd->irx_version.minor = 0;
gInfoEE = cmd->irx_version.ee_addr;
return data;
} break;
case Jak2SoundCommand::set_language: {
gLanguage = languages[cmd->set_language.langauge_id];
} break;
case Jak2SoundCommand::list_sounds: {
// Not present in real jak2 overlord
PrintActiveSounds();
} break;
case Jak2SoundCommand::unload_music: {
while (WaitSema(gSema))
;
if (gMusic) {
UnLoadMusic(&gMusic);
}
SignalSema(gSema);
} break;
case Jak2SoundCommand::set_stereo_mode: {
s32 mode = cmd->stereo_mode.stereo_mode;
if (mode == 0) {
snd_SetPlayBackMode(1);
} else if (mode == 1) {
snd_SetPlayBackMode(2);
} else if (mode == 2) {
snd_SetPlayBackMode(0);
}
} break;
default:
ASSERT_MSG(false, fmt::format("Unhandled RPC Loader command {}", int(cmd->j2command)));
}
n_messages--;
cmd++;
}
return nullptr;
}
int VBlank_Handler(void*) {
bool bVar1;
int iVar2;
int iVar3;
uint8_t uVar4;
IopTicks = IopTicks + 1;
if (gSoundEnable == 0) {
return 1;
}
iWakeupThread(StreamThread);
if (gMusicFadeDir < 0) {
gMusicFade = gMusicFade + -0x200;
if (-1 < gMusicFade)
goto LAB_00008d9c;
gMusicFade = 0;
} else {
if ((gMusicFadeDir < 1) || (gMusicFade = gMusicFade + 0x400, gMusicFade < 0x10001))
goto LAB_00008d9c;
gMusicFade = 0x10000;
}
gMusicFadeDir = 0;
LAB_00008d9c:
if (gInfoEE != 0) {
gFrameNum = gFrameNum + 1;
// instant dma
// if (dmaid != 0) {
// iVar2 = sceSifDmaStat();
// if (-1 < iVar2) {
// return 1;
// }
// dmaid = 0;
// }
for (int i = 0; i < 4; i++) {
u32 status_bits = 0;
u32 pos;
for (int j = 0; j < 24; j++) {
if (VagCmds[i].status_bytes[j]) {
status_bits |= (1 << j);
}
}
if (VagCmds[i].unk_232) {
status_bits |= (1 << 24);
}
if (VagCmds[i].byte6 && VagCmds[i].sb_paused == 0) {
VagCmds[i].unk_192 += CalculateVAGPitch(0x400, VagCmds[i].unk_256_pitch2) / gFPS;
}
if (VagCmds[i].sb_playing == 0 && VagCmds[i].byte5) {
pos = 0;
} else {
pos = VagCmds[i].unk_200;
}
info.stream_status[i] = status_bits;
info.stream_position[i] = pos;
// printf("positions: %d\n", pos);
info.stream_id[i] = VagCmds[i].id;
}
info.iop_ticks = IsoThreadCounter;
info.frame = gFrameNum;
info.freemem = 100 /*gFreeMem*/;
info.freemem2 = QueryTotalFreeMemSize();
info.nocd = 0 /*gNoCD*/;
info.dirtycd = 0 /*gDirtyCD*/;
info.diskspeed[0] = 0 /*gDiskSpeed*/;
info.diskspeed[1] = 0 /*DAT_00013488*/;
info.lastspeed = 0 /*gLastSpeed*/;
info.dupseg = 0 /*gDupSeg*/;
iVar2 = 1;
do {
iVar3 = snd_GetVoiceStatus(iVar2);
uVar4 = '\0';
if (iVar3 == 1) {
uVar4 = 0xff;
}
info.chinfo[iVar2] = uVar4;
bVar1 = iVar2 < 0x30;
iVar2 = iVar2 + 1;
} while (bVar1);
LookupSound(0x29a); // lol idk
/*
local_38 = &info;
local_30 = 0x250;
local_2c = 0;
local_34 = gInfoEE;
dmaid = sceSifSetDma(&local_38,1);
*/
sceSifDmaData dma;
dma.data = &info;
dma.addr = (void*)(uintptr_t)gInfoEE;
dma.size = 0x250;
dma.mode = 0;
/*dmaid =*/sceSifSetDma(&dma, 1);
}
return 1;
}
u32 Thread_Player() {
sceSifQueueData dq;
sceSifServeData serve;
// set up RPC
CpuDisableIntr();
sceSifInitRpc(0);
sceSifSetRpcQueue(&dq, GetThreadId());
sceSifRegisterRpc(&serve, PLAYER_RPC_ID[g_game_version], RPC_Player, gPlayerBuf, kPlayerBufSize,
nullptr, nullptr, &dq);
CpuEnableIntr();
sceSifRpcLoop(&dq);
return 0;
}
u32 Thread_Loader() {
sceSifQueueData dq;
sceSifServeData serve;
// set up RPC
CpuDisableIntr();
sceSifInitRpc(0);
sceSifSetRpcQueue(&dq, GetThreadId());
sceSifRegisterRpc(&serve, LOADER_RPC_ID[g_game_version], RPC_Loader, gLoaderBuf, kLoaderBufSize,
nullptr, nullptr, &dq);
CpuEnableIntr();
sceSifRpcLoop(&dq);
return 0;
}
void SetVagStreamName(VagCmd* param_1, int param_2, int param_3) {
// undefined4 local_18 [2];
if (param_3 == 1) {
// CpuSuspendIntr(local_18);
}
if (param_2 == 0) {
info.stream_name[param_1->idx_in_cmd_arr].dat[0] = '\0';
} else {
strncpy(info.stream_name[param_1->idx_in_cmd_arr].dat, param_1->name, 0x30);
}
if (param_3 == 1) {
// CpuResumeIntr(local_18[0]);
}
}
void SetVagName(int param_1, char* param_2, int param_3) {
// CpuSuspendIntr(local_18);
if (param_3 == 0) {
info.stream_name[param_1].dat[0] = '\0';
} else {
strncpy(info.stream_name[param_1].dat, param_2, 0x30);
}
// CpuResumeIntr(local_18[0]);
}
} // namespace jak2