Online protocol improvements (#1393)
* Chartkey generation * Simfile filehash generation * Read filehash on NSCRSG. Add FLU packets and friendlist vectors. Add getserverversion method. Send chartkey, filehash and rate on start request. * Use filehash to find the selected song if it is not empty. * Friendlist update broadcast. * Send note row size if it's bigger than 1 * Used for chartkey generation * Define the ReportScore function with numNotes when WITHOUT_NETWORKING is defined
This commit is contained in:
@@ -21,6 +21,7 @@ bool NetworkSyncManager::Connect( const RString& addy, unsigned short port ) { r
|
||||
RString NetworkSyncManager::GetServerName() { return RString(); }
|
||||
void NetworkSyncManager::ReportNSSOnOff( int i ) { }
|
||||
void NetworkSyncManager::ReportScore( int playerID, int step, int score, int combo, float offset ) { }
|
||||
void NetworkSyncManager::ReportScore(int playerID, int step, int score, int combo, float offset, int numNotes) { }
|
||||
void NetworkSyncManager::ReportSongOver() { }
|
||||
void NetworkSyncManager::ReportStyle() {}
|
||||
void NetworkSyncManager::StartRequest( short position ) { }
|
||||
@@ -55,6 +56,7 @@ AutoScreenMessage( SM_AddToChat );
|
||||
AutoScreenMessage( SM_ChangeSong );
|
||||
AutoScreenMessage( SM_GotEval );
|
||||
AutoScreenMessage( SM_UsersUpdate );
|
||||
AutoScreenMessage( SM_FriendsUpdate );
|
||||
AutoScreenMessage( SM_SMOnlinePack );
|
||||
|
||||
int NetworkSyncManager::GetSMOnlineSalt()
|
||||
@@ -240,6 +242,53 @@ RString NetworkSyncManager::GetServerName()
|
||||
return m_ServerName;
|
||||
}
|
||||
|
||||
//Same as the one below except for ctr = uint8_t(STATSMAN->m_CurStageStats.m_player[playerID].GetGrade() * 16 + numNotes);
|
||||
//Im keeping the old one because it's used for single tap notes
|
||||
void NetworkSyncManager::ReportScore(int playerID, int step, int score, int combo, float offset, int numNotes)
|
||||
{
|
||||
if (!useSMserver) //Make sure that we are using the network
|
||||
return;
|
||||
|
||||
LOG->Trace("Player ID %i combo = %i", playerID, combo);
|
||||
m_packet.ClearPacket();
|
||||
|
||||
m_packet.Write1(NSCGSU);
|
||||
step = TranslateStepType(step);
|
||||
uint8_t ctr = (uint8_t)(playerID * 16 + step - (SMOST_HITMINE - 1));
|
||||
m_packet.Write1(ctr);
|
||||
|
||||
ctr = uint8_t(STATSMAN->m_CurStageStats.m_player[playerID].GetGrade() * 16 + numNotes);
|
||||
|
||||
if (STATSMAN->m_CurStageStats.m_player[playerID].m_bFailed)
|
||||
ctr = uint8_t(112); //Code for failed (failed constant seems not to work)
|
||||
|
||||
m_packet.Write1(ctr);
|
||||
m_packet.Write4(score);
|
||||
m_packet.Write2((uint16_t)combo);
|
||||
m_packet.Write2((uint16_t)m_playerLife[playerID]);
|
||||
|
||||
// Offset Info
|
||||
// Note: if a 0 is sent, then disregard data.
|
||||
|
||||
// ASSUMED: No step will be more than 16 seconds off center.
|
||||
// If this assumption is false, read 16 seconds in either direction.
|
||||
int iOffset = int((offset + 16.384)*2000.0f);
|
||||
|
||||
if (iOffset>65535)
|
||||
iOffset = 65535;
|
||||
if (iOffset<1)
|
||||
iOffset = 1;
|
||||
|
||||
// Report 0 if hold, or miss (don't forget mines should report)
|
||||
if (step == SMOST_HITMINE || step > SMOST_W1)
|
||||
iOffset = 0;
|
||||
|
||||
m_packet.Write2((uint16_t)iOffset);
|
||||
|
||||
NetPlayerClient->SendPack((char*)m_packet.Data, m_packet.Position);
|
||||
|
||||
}
|
||||
|
||||
void NetworkSyncManager::ReportScore(int playerID, int step, int score, int combo, float offset)
|
||||
{
|
||||
if( !useSMserver ) //Make sure that we are using the network
|
||||
@@ -390,6 +439,31 @@ void NetworkSyncManager::StartRequest( short position )
|
||||
for (int i=0; i<2-players; ++i)
|
||||
m_packet.WriteNT(""); //Write a NULL if no player
|
||||
|
||||
//Send song hash/chartkey
|
||||
if (m_ServerVersion >= 129) {
|
||||
tSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
|
||||
if (tSteps != NULL && GAMESTATE->IsPlayerEnabled(PLAYER_1)) {
|
||||
m_packet.WriteNT(tSteps->GetChartKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_packet.WriteNT("");
|
||||
}
|
||||
|
||||
tSteps = GAMESTATE->m_pCurSteps[PLAYER_2];
|
||||
if (tSteps != NULL && GAMESTATE->IsPlayerEnabled(PLAYER_2)) {
|
||||
m_packet.WriteNT(tSteps->GetChartKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_packet.WriteNT("");
|
||||
}
|
||||
|
||||
int rate = (int)(GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * 100);
|
||||
m_packet.Write1(rate);
|
||||
m_packet.WriteNT(GAMESTATE->m_pCurSong->GetFileHash());
|
||||
}
|
||||
|
||||
//This needs to be reset before ScreenEvaluation could possibly be called
|
||||
m_EvalPlayerData.clear();
|
||||
|
||||
@@ -607,6 +681,12 @@ void NetworkSyncManager::ProcessInput()
|
||||
m_sMainTitle = m_packet.ReadNT();
|
||||
m_sArtist = m_packet.ReadNT();
|
||||
m_sSubTitle = m_packet.ReadNT();
|
||||
//Read songhash
|
||||
if (m_ServerVersion >= 129) {
|
||||
m_sFileHash = m_packet.ReadNT();
|
||||
} else {
|
||||
m_sFileHash = "" ;
|
||||
}
|
||||
SCREENMAN->SendMessageToTopScreen( SM_ChangeSong );
|
||||
}
|
||||
break;
|
||||
@@ -668,6 +748,20 @@ void NetworkSyncManager::ProcessInput()
|
||||
m_packet.ClearPacket();
|
||||
}
|
||||
break;
|
||||
case FLU:
|
||||
{
|
||||
int PlayersInThisPacket = m_packet.Read1();
|
||||
fl_PlayerNames.clear();
|
||||
fl_PlayerStates.clear();
|
||||
for (int i = 0; i<PlayersInThisPacket; ++i)
|
||||
{
|
||||
int PStatus = m_packet.Read1();
|
||||
fl_PlayerStates.push_back(PStatus);
|
||||
fl_PlayerNames.push_back(m_packet.ReadNT());
|
||||
}
|
||||
SCREENMAN->SendMessageToTopScreen(SM_FriendsUpdate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
m_packet.ClearPacket();
|
||||
}
|
||||
@@ -698,6 +792,10 @@ void NetworkSyncManager::ReportPlayerOptions()
|
||||
NetPlayerClient->SendPack((char*)&m_packet.Data, m_packet.Position);
|
||||
}
|
||||
|
||||
int NetworkSyncManager::GetServerVersion()
|
||||
{
|
||||
return m_ServerVersion;
|
||||
}
|
||||
void NetworkSyncManager::SelectUserSong()
|
||||
{
|
||||
m_packet.ClearPacket();
|
||||
@@ -706,6 +804,10 @@ void NetworkSyncManager::SelectUserSong()
|
||||
m_packet.WriteNT( m_sMainTitle );
|
||||
m_packet.WriteNT( m_sArtist );
|
||||
m_packet.WriteNT( m_sSubTitle );
|
||||
//Send songhash
|
||||
if (m_ServerVersion >= 129) {
|
||||
m_packet.WriteNT(GAMESTATE->m_pCurSong->GetFileHash());
|
||||
}
|
||||
NetPlayerClient->SendPack( (char*)&m_packet.Data, m_packet.Position );
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
class LoadingWindow;
|
||||
|
||||
const int NETPROTOCOLVERSION=3;
|
||||
const int NETPROTOCOLVERSION=4;
|
||||
const int NETMAXBUFFERSIZE=1020; //1024 - 4 bytes for EzSockets
|
||||
const int NETNUMTAPSCORES=8;
|
||||
|
||||
@@ -29,6 +29,8 @@ enum NSCommand
|
||||
NSCSMOnline, // 12 [SMLC_SMO]
|
||||
NSCFormatted, // 13 [SMLC_RESERVED1]
|
||||
NSCAttack, // 14 [SMLC_RESERVED2]
|
||||
XML, // 15 [SMLC_RESERVED3]
|
||||
FLU, // 15 [SMLC_FriendListUpdate]
|
||||
NUM_NS_COMMANDS
|
||||
};
|
||||
|
||||
@@ -114,6 +116,7 @@ public:
|
||||
|
||||
// If "useSMserver" then send score to server
|
||||
void ReportScore( int playerID, int step, int score, int combo, float offset );
|
||||
void ReportScore(int playerID, int step, int score, int combo, float offset, int numNotes);
|
||||
void ReportSongOver();
|
||||
void ReportStyle(); // Report style, players, and names
|
||||
void ReportNSSOnOff( int i ); // Report song selection screen on/off
|
||||
@@ -145,6 +148,10 @@ public:
|
||||
vector<int> m_ActivePlayer;
|
||||
vector<RString> m_PlayerNames;
|
||||
|
||||
//friendlist
|
||||
std::vector<RString> fl_PlayerNames;
|
||||
std::vector<int> fl_PlayerStates;
|
||||
|
||||
// Used for ScreenNetEvaluation
|
||||
vector<EndOfGame_PlayerData> m_EvalPlayerData;
|
||||
|
||||
@@ -163,9 +170,12 @@ public:
|
||||
RString m_sMainTitle;
|
||||
RString m_sArtist;
|
||||
RString m_sSubTitle;
|
||||
RString m_sFileHash;
|
||||
int m_iSelectMode;
|
||||
void SelectUserSong();
|
||||
|
||||
int GetServerVersion();
|
||||
|
||||
RString m_sChatText;
|
||||
|
||||
// FIXME: This should NOT be public. PERIOD. It probably shouldn't be a member at all.
|
||||
|
||||
@@ -269,6 +269,12 @@ int NoteData::GetNumTracksWithTapOrHoldHead( int row ) const
|
||||
return iNum;
|
||||
}
|
||||
|
||||
void NoteData::LogNonEmptyRows() {
|
||||
NonEmptyRowVector.clear();
|
||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS(*this, row)
|
||||
NonEmptyRowVector.push_back(row);
|
||||
}
|
||||
|
||||
int NoteData::GetFirstTrackWithTap( int row ) const
|
||||
{
|
||||
for( int t=0; t<GetNumTracks(); t++ )
|
||||
|
||||
@@ -157,9 +157,16 @@ private:
|
||||
void RemoveATIFromList(all_tracks_iterator* iter) const;
|
||||
void RemoveATIFromList(all_tracks_const_iterator* iter) const;
|
||||
|
||||
// Mina stuf (Used for chartkey hashing)
|
||||
std::vector<int> NonEmptyRowVector;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
|
||||
// Mina stuf (Used for chartkey hashing)
|
||||
void LogNonEmptyRows();
|
||||
std::vector<int>& GetNonEmptyRowVector() { return NonEmptyRowVector; };
|
||||
|
||||
int GetNumTracks() const { return m_TapNotes.size(); }
|
||||
void SetNumTracks( int iNewNumTracks );
|
||||
bool IsComposite() const;
|
||||
|
||||
@@ -605,7 +605,7 @@ void ScoreKeeperNormal::HandleTapRowScore( const NoteData &nd, int iRow )
|
||||
float offset = NoteDataWithScoring::LastTapNoteWithResult( nd, iRow ).result.fTapNoteOffset;
|
||||
NSMAN->ReportScore( pn, scoreOfLastTap,
|
||||
m_pPlayerStageStats->m_iScore,
|
||||
m_pPlayerStageStats->m_iCurCombo, offset );
|
||||
m_pPlayerStageStats->m_iCurCombo, offset, m_iNumNotesHitThisRow);
|
||||
Message msg( "ScoreChanged" );
|
||||
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
|
||||
msg.SetParam( "MultiPlayer", m_pPlayerState->m_mp );
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
AutoScreenMessage( SM_AddToChat );
|
||||
AutoScreenMessage( SM_UsersUpdate );
|
||||
AutoScreenMessage( SM_FriendsUpdate );
|
||||
AutoScreenMessage( SM_SMOnlinePack );
|
||||
|
||||
REGISTER_SCREEN_CLASS( ScreenNetSelectBase );
|
||||
@@ -135,6 +136,10 @@ void ScreenNetSelectBase::HandleScreenMessage( const ScreenMessage SM )
|
||||
{
|
||||
UpdateUsers();
|
||||
}
|
||||
else if (SM == SM_FriendsUpdate)
|
||||
{
|
||||
MESSAGEMAN->Broadcast("FriendsUpdate");
|
||||
}
|
||||
|
||||
ScreenWithMenuElements::HandleScreenMessage( SM );
|
||||
}
|
||||
|
||||
@@ -181,14 +181,37 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM )
|
||||
|
||||
vector <Song *> AllSongs = SONGMAN->GetAllSongs();
|
||||
unsigned i;
|
||||
for( i=0; i < AllSongs.size(); i++ )
|
||||
bool found = false;
|
||||
if (NSMAN->GetServerVersion() >= 129)
|
||||
{
|
||||
m_cSong = AllSongs[i];
|
||||
if( ( !m_cSong->GetTranslitArtist().CompareNoCase( NSMAN->m_sArtist ) ) &&
|
||||
( !m_cSong->GetTranslitMainTitle().CompareNoCase( NSMAN->m_sMainTitle ) ) &&
|
||||
( !m_cSong->GetTranslitSubTitle().CompareNoCase( NSMAN->m_sSubTitle ) ) )
|
||||
break;
|
||||
//Dont earch by filehash if none was sent
|
||||
if(!NSMAN->m_sFileHash.empty())
|
||||
for (i = 0; i < AllSongs.size(); i++)
|
||||
{
|
||||
m_cSong = AllSongs[i];
|
||||
if (NSMAN->m_sArtist == m_cSong->GetTranslitArtist() &&
|
||||
NSMAN->m_sMainTitle == m_cSong->GetTranslitMainTitle() &&
|
||||
NSMAN->m_sSubTitle == m_cSong->GetTranslitSubTitle() &&
|
||||
NSMAN->m_sFileHash == m_cSong->GetFileHash())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//If we couldnt find it using file hash search for it without using it, if using SMSERVER < 129 it will go here
|
||||
if(!found)
|
||||
for (i = 0; i < AllSongs.size(); i++)
|
||||
{
|
||||
m_cSong = AllSongs[i];
|
||||
if (NSMAN->m_sArtist == m_cSong->GetTranslitArtist() &&
|
||||
NSMAN->m_sMainTitle == m_cSong->GetTranslitMainTitle() &&
|
||||
NSMAN->m_sSubTitle == m_cSong->GetTranslitSubTitle())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool haveSong = i != AllSongs.size();
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <set>
|
||||
#include <float.h>
|
||||
|
||||
//-Nick12 Used for song file hashing
|
||||
#include <CryptManager.h>
|
||||
|
||||
/**
|
||||
* @brief The internal version of the cache for StepMania.
|
||||
@@ -1592,6 +1594,32 @@ vector<RString> Song::GetFGChanges1ToVectorString() const
|
||||
return this->GetChangesToVectorString(this->GetForegroundChanges());
|
||||
}
|
||||
|
||||
RString Song::GetFileHash()
|
||||
{
|
||||
if (m_sFileHash.empty()) {
|
||||
RString sPath = SetExtension(GetSongFilePath(), "sm");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "dwi");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "sma");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "bms");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "ksf");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "json");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "jso");
|
||||
if (!IsAFile(sPath))
|
||||
sPath = SetExtension(GetSongFilePath(), "ssc");
|
||||
if (IsAFile(sPath))
|
||||
m_sFileHash = BinaryToHex(CRYPTMAN->GetSHA1ForFile(sPath));
|
||||
else
|
||||
m_sFileHash = "";
|
||||
}
|
||||
return m_sFileHash;
|
||||
}
|
||||
|
||||
vector<RString> Song::GetInstrumentTracksToVectorString() const
|
||||
{
|
||||
vector<RString> ret;
|
||||
|
||||
@@ -188,6 +188,9 @@ public:
|
||||
/** @brief The transliterated artist of the Song, if it exists. */
|
||||
RString m_sArtistTranslit;
|
||||
|
||||
RString m_sFileHash;
|
||||
RString GetFileHash();
|
||||
|
||||
/* If PREFSMAN->m_bShowNative is off, these are the same as GetTranslit*
|
||||
* below. Otherwise, they return the main titles. */
|
||||
RString GetDisplayMainTitle() const;
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
/* register DisplayBPM with StringConversion */
|
||||
#include "EnumHelper.h"
|
||||
|
||||
// For hashing hart keys - Mina
|
||||
#include "CryptManager.h"
|
||||
|
||||
static const char *DisplayBPMNames[] =
|
||||
{
|
||||
"Actual",
|
||||
@@ -614,6 +617,77 @@ void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] )
|
||||
m_bAreCachedRadarValuesJustLoaded = true;
|
||||
}
|
||||
|
||||
RString Steps::GenerateChartKey()
|
||||
{
|
||||
ChartKey = this->GenerateChartKey(*m_pNoteData, this->GetTimingData());
|
||||
return ChartKey;
|
||||
}
|
||||
RString Steps::GetChartKey()
|
||||
{
|
||||
if (ChartKey.empty()) {
|
||||
this->Decompress();
|
||||
ChartKey = this->GenerateChartKey(*m_pNoteData, this->GetTimingData());
|
||||
this->Compress();
|
||||
}
|
||||
return ChartKey;
|
||||
}
|
||||
RString Steps::GenerateChartKey(NoteData &nd, TimingData *td)
|
||||
{
|
||||
RString k = "";
|
||||
RString o = "";
|
||||
float bpm;
|
||||
nd.LogNonEmptyRows();
|
||||
std::vector<int>& nerv = nd.GetNonEmptyRowVector();
|
||||
|
||||
|
||||
RString firstHalf = "";
|
||||
RString secondHalf = "";
|
||||
|
||||
#pragma omp parallel sections
|
||||
{
|
||||
#pragma omp section
|
||||
{
|
||||
for (size_t r = 0; r < nerv.size() / 2; r++) {
|
||||
int row = nerv[r];
|
||||
for (int t = 0; t < nd.GetNumTracks(); ++t) {
|
||||
const TapNote &tn = nd.GetTapNote(t, row);
|
||||
std::ostringstream os;
|
||||
os << tn.type;
|
||||
firstHalf.append(os.str());
|
||||
}
|
||||
bpm = td->GetBPMAtRow(row);
|
||||
std::ostringstream os;
|
||||
os << static_cast<int>(bpm + 0.374643f);
|
||||
firstHalf.append(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp section
|
||||
{
|
||||
for (size_t r = nerv.size() / 2; r < nerv.size(); r++) {
|
||||
int row = nerv[r];
|
||||
for (int t = 0; t < nd.GetNumTracks(); ++t) {
|
||||
const TapNote &tn = nd.GetTapNote(t, row);
|
||||
std::ostringstream os;
|
||||
os << tn.type;
|
||||
secondHalf.append(os.str());
|
||||
}
|
||||
bpm = td->GetBPMAtRow(row);
|
||||
std::ostringstream os;
|
||||
os << static_cast<int>(bpm + 0.374643f);
|
||||
firstHalf.append(os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
k = firstHalf + secondHalf;
|
||||
|
||||
//ChartKeyRecord = k;
|
||||
o.append("X"); // I was thinking of using "C" to indicate chart.. however.. X is cooler... - Mina
|
||||
o.append(BinaryToHex(CryptManager::GetSHA1ForString(k)));
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
/** @brief Allow Lua to have access to the Steps. */
|
||||
|
||||
@@ -124,6 +124,14 @@ public:
|
||||
void SetChartStyle( RString sChartStyle );
|
||||
static bool MakeValidEditDescription( RString &sPreferredDescription ); // return true if was modified
|
||||
|
||||
/* This is a reimplementation of the lua version of the script to generate chart keys, except this time
|
||||
using the notedata stored in game memory immediately after reading it than parsing it using lua. - Mina */
|
||||
RString GenerateChartKey(NoteData &nd, TimingData *td);
|
||||
RString GenerateChartKey();
|
||||
RString ChartKey;
|
||||
RString GetChartKey();
|
||||
void SetChartKey(const RString &k) { ChartKey = k; }
|
||||
|
||||
void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; }
|
||||
void SetMeter( int meter );
|
||||
void SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] );
|
||||
|
||||
Reference in New Issue
Block a user