mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 14:38:18 +00:00
Improved ghost file management
This commit is contained in:
parent
d09e825065
commit
5b3e9e4bbf
|
@ -184,7 +184,7 @@ public:
|
||||||
virtual bool RaceRecord_IsRecording() = 0;
|
virtual bool RaceRecord_IsRecording() = 0;
|
||||||
|
|
||||||
virtual void Ghost_GetPath(char *pBuf, int Size, int Time = -1) = 0;
|
virtual void Ghost_GetPath(char *pBuf, int Size, int Time = -1) = 0;
|
||||||
virtual void GhostRecorder_Start() = 0;
|
virtual void GhostRecorder_Start(int Time = -1) = 0;
|
||||||
virtual bool GhostLoader_Load(const char *pFilename) = 0;
|
virtual bool GhostLoader_Load(const char *pFilename) = 0;
|
||||||
virtual bool GhostLoader_GetGhostInfo(const char *pFilename, struct CGhostHeader *pGhostHeader) = 0;
|
virtual bool GhostLoader_GetGhostInfo(const char *pFilename, struct CGhostHeader *pGhostHeader) = 0;
|
||||||
|
|
||||||
|
|
|
@ -3661,10 +3661,10 @@ void CClient::Ghost_GetPath(char *pBuf, int Size, int Time)
|
||||||
str_format(pBuf, Size, "ghosts/%s_%s_%d.%03d_%08x.gho", m_aCurrentMap, aPlayerName, Time / 1000, Time % 1000, m_pMap->Crc());
|
str_format(pBuf, Size, "ghosts/%s_%s_%d.%03d_%08x.gho", m_aCurrentMap, aPlayerName, Time / 1000, Time % 1000, m_pMap->Crc());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::GhostRecorder_Start()
|
void CClient::GhostRecorder_Start(int Time)
|
||||||
{
|
{
|
||||||
char aFilename[128];
|
char aFilename[128];
|
||||||
Ghost_GetPath(aFilename, sizeof(aFilename));
|
Ghost_GetPath(aFilename, sizeof(aFilename), Time);
|
||||||
m_GhostRecorder.Start(Storage(), m_pConsole, aFilename, m_aCurrentMap, m_pMap->Crc(), g_Config.m_PlayerName);
|
m_GhostRecorder.Start(Storage(), m_pConsole, aFilename, m_aCurrentMap, m_pMap->Crc(), g_Config.m_PlayerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -392,7 +392,7 @@ public:
|
||||||
bool RaceRecord_IsRecording();
|
bool RaceRecord_IsRecording();
|
||||||
|
|
||||||
void Ghost_GetPath(char *pBuf, int Size, int Time = -1);
|
void Ghost_GetPath(char *pBuf, int Size, int Time = -1);
|
||||||
void GhostRecorder_Start();
|
void GhostRecorder_Start(int Time = -1);
|
||||||
bool GhostLoader_Load(const char *pFilename);
|
bool GhostLoader_Load(const char *pFilename);
|
||||||
bool GhostLoader_GetGhostInfo(const char *pFilename, struct CGhostHeader *pGhostHeader);
|
bool GhostLoader_GetGhostInfo(const char *pFilename, struct CGhostHeader *pGhostHeader);
|
||||||
|
|
||||||
|
|
|
@ -233,15 +233,7 @@ void CGhost::StopRecord(int Time)
|
||||||
|
|
||||||
char aFilename[128] = { 0 };
|
char aFilename[128] = { 0 };
|
||||||
if(RecordingToFile)
|
if(RecordingToFile)
|
||||||
{
|
|
||||||
// remove old ghost
|
|
||||||
if(pOwnGhost && pOwnGhost->HasFile())
|
|
||||||
Storage()->RemoveFile(pOwnGhost->m_aFilename, IStorage::TYPE_SAVE);
|
|
||||||
|
|
||||||
// save new ghost
|
|
||||||
Client()->Ghost_GetPath(aFilename, sizeof(aFilename), Time);
|
Client()->Ghost_GetPath(aFilename, sizeof(aFilename), Time);
|
||||||
Storage()->RenameFile(aTmpFilename, aFilename, IStorage::TYPE_SAVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create ghost item
|
// create ghost item
|
||||||
CMenus::CGhostItem Item;
|
CMenus::CGhostItem Item;
|
||||||
|
@ -249,14 +241,13 @@ void CGhost::StopRecord(int Time)
|
||||||
str_copy(Item.m_aPlayer, g_Config.m_PlayerName, sizeof(Item.m_aPlayer));
|
str_copy(Item.m_aPlayer, g_Config.m_PlayerName, sizeof(Item.m_aPlayer));
|
||||||
Item.m_Time = Time;
|
Item.m_Time = Time;
|
||||||
Item.m_Slot = Slot;
|
Item.m_Slot = Slot;
|
||||||
Item.m_Own = true;
|
|
||||||
|
// save new ghost file
|
||||||
|
if(Item.HasFile())
|
||||||
|
Storage()->RenameFile(aTmpFilename, aFilename, IStorage::TYPE_SAVE);
|
||||||
|
|
||||||
// add item to menu list
|
// add item to menu list
|
||||||
if(pOwnGhost)
|
m_pClient->m_pMenus->UpdateOwnGhost(Item);
|
||||||
*pOwnGhost = Item;
|
|
||||||
else
|
|
||||||
m_pClient->m_pMenus->m_lGhosts.add(Item);
|
|
||||||
m_pClient->m_pMenus->m_lGhosts.sort_range();
|
|
||||||
}
|
}
|
||||||
else if(RecordingToFile) // no new record
|
else if(RecordingToFile) // no new record
|
||||||
Storage()->RemoveFile(aTmpFilename, IStorage::TYPE_SAVE);
|
Storage()->RemoveFile(aTmpFilename, IStorage::TYPE_SAVE);
|
||||||
|
@ -364,6 +355,36 @@ void CGhost::Unload(int Slot)
|
||||||
m_aActiveGhosts[Slot].Reset();
|
m_aActiveGhosts[Slot].Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGhost::UnloadAll()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < MAX_ACTIVE_GHOSTS; i++)
|
||||||
|
Unload(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGhost::SaveGhost(CMenus::CGhostItem *pItem)
|
||||||
|
{
|
||||||
|
int Slot = pItem->m_Slot;
|
||||||
|
if(Slot < 0 || pItem->HasFile() || m_aActiveGhosts[Slot].Empty() || GhostRecorder()->IsRecording())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int NumTicks = m_aActiveGhosts[Slot].m_lPath.size();
|
||||||
|
Client()->GhostRecorder_Start(pItem->m_Time);
|
||||||
|
|
||||||
|
const CGameClient::CClientData *pClientData = &m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID];
|
||||||
|
CGhostSkin Skin;
|
||||||
|
StrToInts(&Skin.m_Skin0, 6, pClientData->m_aSkinName);
|
||||||
|
Skin.m_UseCustomColor = pClientData->m_UseCustomColor;
|
||||||
|
Skin.m_ColorBody = pClientData->m_ColorBody;
|
||||||
|
Skin.m_ColorFeet = pClientData->m_ColorFeet;
|
||||||
|
GhostRecorder()->WriteData(GHOSTDATA_TYPE_SKIN, (const char*)&Skin, sizeof(Skin));
|
||||||
|
|
||||||
|
for(int i = 0; i < NumTicks; i++)
|
||||||
|
GhostRecorder()->WriteData(GHOSTDATA_TYPE_CHARACTER, (const char*)&m_aActiveGhosts[Slot].m_lPath[i], sizeof(CGhostCharacter));
|
||||||
|
|
||||||
|
GhostRecorder()->Stop(NumTicks, pItem->m_Time);
|
||||||
|
Client()->Ghost_GetPath(pItem->m_aFilename, sizeof(pItem->m_aFilename), pItem->m_Time);
|
||||||
|
}
|
||||||
|
|
||||||
void CGhost::ConGPlay(IConsole::IResult *pResult, void *pUserData)
|
void CGhost::ConGPlay(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
((CGhost *)pUserData)->StartRender();
|
((CGhost *)pUserData)->StartRender();
|
||||||
|
@ -424,8 +445,7 @@ void CGhost::OnReset()
|
||||||
void CGhost::OnMapLoad()
|
void CGhost::OnMapLoad()
|
||||||
{
|
{
|
||||||
OnReset();
|
OnReset();
|
||||||
for(int i = 0; i < MAX_ACTIVE_GHOSTS; i++)
|
UnloadAll();
|
||||||
Unload(i);
|
|
||||||
m_pClient->m_pMenus->GhostlistPopulate();
|
m_pClient->m_pMenus->GhostlistPopulate();
|
||||||
m_IsSolo = true;
|
m_IsSolo = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,10 @@ public:
|
||||||
int Load(const char *pFilename);
|
int Load(const char *pFilename);
|
||||||
void Unload(int Slot);
|
void Unload(int Slot);
|
||||||
|
|
||||||
|
void UnloadAll();
|
||||||
|
|
||||||
|
void SaveGhost(CMenus::CGhostItem *pItem);
|
||||||
|
|
||||||
class IGhostLoader *GhostLoader() const { return m_pGhostLoader; }
|
class IGhostLoader *GhostLoader() const { return m_pGhostLoader; }
|
||||||
class IGhostRecorder *GhostRecorder() const { return m_pGhostRecorder; }
|
class IGhostRecorder *GhostRecorder() const { return m_pGhostRecorder; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -351,6 +351,8 @@ public:
|
||||||
|
|
||||||
void GhostlistPopulate();
|
void GhostlistPopulate();
|
||||||
CGhostItem *GetOwnGhost();
|
CGhostItem *GetOwnGhost();
|
||||||
|
void UpdateOwnGhost(CGhostItem Item);
|
||||||
|
void DeleteGhostItem(int Index);
|
||||||
|
|
||||||
void setPopup(int Popup) { m_Popup = Popup; }
|
void setPopup(int Popup) { m_Popup = Popup; }
|
||||||
|
|
||||||
|
|
|
@ -885,6 +885,32 @@ CMenus::CGhostItem *CMenus::GetOwnGhost()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMenus::UpdateOwnGhost(CGhostItem Item)
|
||||||
|
{
|
||||||
|
int Own = -1;
|
||||||
|
for(int i = 0; i < m_lGhosts.size(); i++)
|
||||||
|
if(m_lGhosts[i].m_Own)
|
||||||
|
Own = i;
|
||||||
|
|
||||||
|
if(Own != -1)
|
||||||
|
{
|
||||||
|
m_lGhosts[Own].m_Slot = -1;
|
||||||
|
m_lGhosts[Own].m_Own = false;
|
||||||
|
if(Item.HasFile() || !m_lGhosts[Own].HasFile())
|
||||||
|
DeleteGhostItem(Own);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item.m_Own = true;
|
||||||
|
m_lGhosts.add(Item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMenus::DeleteGhostItem(int Index)
|
||||||
|
{
|
||||||
|
if(m_lGhosts[Index].HasFile())
|
||||||
|
Storage()->RemoveFile(m_lGhosts[Index].m_aFilename, IStorage::TYPE_SAVE);
|
||||||
|
m_lGhosts.remove_index(Index);
|
||||||
|
}
|
||||||
|
|
||||||
void CMenus::RenderGhost(CUIRect MainView)
|
void CMenus::RenderGhost(CUIRect MainView)
|
||||||
{
|
{
|
||||||
// render background
|
// render background
|
||||||
|
@ -1045,11 +1071,11 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 rgb = vec3(1.0f, 1.0f, 1.0f);
|
||||||
if(pItem->m_Own)
|
if(pItem->m_Own)
|
||||||
{
|
rgb = HslToRgb(vec3(0.33f, 1.0f, 0.75f));
|
||||||
vec3 rgb = HslToRgb(vec3(0.33f, 1.0f, 0.75f));
|
|
||||||
TextRender()->TextColor(rgb.r, rgb.g, rgb.b, 1.0f);
|
TextRender()->TextColor(rgb.r, rgb.g, rgb.b, pItem->HasFile() ? 1.0f : 0.5f);
|
||||||
}
|
|
||||||
|
|
||||||
for(int c = 0; c < NumCols; c++)
|
for(int c = 0; c < NumCols; c++)
|
||||||
{
|
{
|
||||||
|
@ -1108,22 +1134,46 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
Status.Margin(5.0f, &Status);
|
Status.Margin(5.0f, &Status);
|
||||||
|
|
||||||
CUIRect Button;
|
CUIRect Button;
|
||||||
Status.VSplitRight(120.0f, &Status, &Button);
|
|
||||||
|
|
||||||
static int s_GhostButton = 0;
|
static int s_GhostButton = 0;
|
||||||
bool Delete = !pGhost->HasFile();
|
static int s_DeleteButton = 0;
|
||||||
const char *pText = pGhost->Active() ? (Delete ? Localize("Delete") : Localize("Deactivate")) : Localize("Activate");
|
static int s_SaveButton = 0;
|
||||||
|
|
||||||
if(DoButton_Menu(&s_GhostButton, pText, 0, &Button) || (NewSelected != -1 && Input()->MouseDoubleClick()))
|
if(pGhost->HasFile())
|
||||||
|
{
|
||||||
|
Status.VSplitRight(120.0f, &Status, &Button);
|
||||||
|
|
||||||
|
const char *pText = pGhost->Active() ? Localize("Deactivate") : Localize("Activate");
|
||||||
|
if(DoButton_Menu(&s_GhostButton, pText, 0, &Button) || (NewSelected != -1 && Input()->MouseDoubleClick()))
|
||||||
|
{
|
||||||
|
if(pGhost->Active())
|
||||||
|
{
|
||||||
|
m_pClient->m_pGhost->Unload(pGhost->m_Slot);
|
||||||
|
pGhost->m_Slot = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pGhost->m_Slot = m_pClient->m_pGhost->Load(pGhost->m_aFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status.VSplitRight(5.0f, &Status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status.VSplitRight(120.0f, &Status, &Button);
|
||||||
|
|
||||||
|
if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &Button))
|
||||||
{
|
{
|
||||||
if(pGhost->Active())
|
if(pGhost->Active())
|
||||||
{
|
|
||||||
m_pClient->m_pGhost->Unload(pGhost->m_Slot);
|
m_pClient->m_pGhost->Unload(pGhost->m_Slot);
|
||||||
pGhost->m_Slot = -1;
|
DeleteGhostItem(s_SelectedIndex);
|
||||||
if(Delete)
|
}
|
||||||
m_lGhosts.remove_index(s_SelectedIndex);
|
|
||||||
}
|
Status.VSplitRight(5.0f, &Status, 0);
|
||||||
else
|
|
||||||
pGhost->m_Slot = m_pClient->m_pGhost->Load(pGhost->m_aFilename);
|
bool Recording = m_pClient->m_pGhost->GhostRecorder()->IsRecording();
|
||||||
|
if(!pGhost->HasFile() && !Recording && pGhost->Active())
|
||||||
|
{
|
||||||
|
Status.VSplitRight(120.0f, &Status, &Button);
|
||||||
|
if(DoButton_Menu(&s_SaveButton, Localize("Save"), 0, &Button))
|
||||||
|
m_pClient->m_pGhost->SaveGhost(pGhost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue