void Expect(const unsigned char *pOutput, int OutputSize) { static CUuid TEEHISTORIAN_UUID = CalculateUuid("*****@*****.**"); static const char PREFIX1[] = "{\"comment\":\"[email protected]\",\"version\":\"2\",\"game_uuid\":\"a1eb7182-796e-3b3e-941d-38ca71b2a4a8\",\"server_version\":\"DDNet test\",\"start_time\":\""; static const char PREFIX2[] = "\",\"server_name\":\"server name\",\"server_port\":\"8303\",\"game_type\":\"game type\",\"map_name\":\"Kobra 3 Solo\",\"map_size\":\"903514\",\"map_sha256\":\"0123456789012345678901234567890123456789012345678901234567890123\",\"map_crc\":\"eceaf25c\",\"config\":{},\"tuning\":{},\"uuids\":["; static const char PREFIX3[] = "]}"; char aTimeBuf[64]; str_timestamp_ex(m_GameInfo.m_StartTime, aTimeBuf, sizeof(aTimeBuf), "%Y-%m-%dT%H:%M:%S%z"); CPacker Buffer; Buffer.Reset(); Buffer.AddRaw(&TEEHISTORIAN_UUID, sizeof(TEEHISTORIAN_UUID)); Buffer.AddRaw(PREFIX1, str_length(PREFIX1)); Buffer.AddRaw(aTimeBuf, str_length(aTimeBuf)); Buffer.AddRaw(PREFIX2, str_length(PREFIX2)); for(int i = 0; i < m_UuidManager.NumUuids(); i++) { char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%s\"%s\"", i == 0 ? "" : ",", m_UuidManager.GetName(OFFSET_UUID + i)); Buffer.AddRaw(aBuf, str_length(aBuf)); } Buffer.AddRaw(PREFIX3, str_length(PREFIX3)); Buffer.AddRaw("", 1); Buffer.AddRaw(pOutput, OutputSize); ASSERT_FALSE(Buffer.Error()); ExpectFull(Buffer.Data(), Buffer.Size()); }
void sqlstr::getTimeStamp(char* dest, unsigned int size) { std::time_t rawtime; std::time(&rawtime); str_timestamp_ex(rawtime, dest, size, "%Y-%m-%d %H:%M:%S"); }
void CMenus::RenderDemoList(CUIRect MainView) { CALLSTACK_ADD(); static int s_Inited = 0; if(!s_Inited) { DemolistPopulate(); DemolistOnUpdate(true); s_Inited = 1; } char aFooterLabel[128] = {0}; if(m_DemolistSelectedIndex >= 0) { CDemoItem *Item = &m_lDemos[m_DemolistSelectedIndex]; if(str_comp(Item->m_aFilename, "..") == 0) str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel)); else if(m_DemolistSelectedIsDir) str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel)); else { if(!Item->m_InfosLoaded) { char aBuffer[512]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item->m_aFilename); Item->m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item->m_StorageType, &Item->m_Info); Item->m_InfosLoaded = true; } if(!Item->m_Valid) str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel)); else str_copy(aFooterLabel, Localize("Demo details"), sizeof(aFooterLabel)); } } // render background RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); MainView.Margin(10.0f, &MainView); CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect, RenameRect, ListBox; MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar); ButtonBar.HSplitTop(5.0f, 0, &ButtonBar); ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect); ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &RenameRect, &ButtonBar); MainView.HSplitBottom(140.0f, &ListBox, &MainView); // render demo info MainView.VMargin(5.0f, &MainView); MainView.HSplitBottom(5.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); if(!m_DemolistSelectedIsDir && m_DemolistSelectedIndex >= 0 && m_lDemos[m_DemolistSelectedIndex].m_Valid) { CUIRect Left, Right, Labels; MainView.Margin(20.0f, &MainView); MainView.VSplitMid(&Labels, &MainView); // left side Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Created:"), 14.0f, -1); char aTimestamp[256]; str_timestamp_ex(m_lDemos[m_DemolistSelectedIndex].m_Date, aTimestamp, sizeof(aTimestamp), "%Y-%m-%d %H:%M:%S"); UI()->DoLabelScaled(&Right, aTimestamp, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Type:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aType, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Length:"), 14.0f, -1); int Length = ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[0]<<24)&0xFF000000) | ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[1]<<16)&0xFF0000) | ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[2]<<8)&0xFF00) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[3]&0xFF); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%d:%02d", Length/60, Length%60); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Version:"), 14.0f, -1); str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].m_Info.m_Version); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); // right side Labels = MainView; Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Map:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapName, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(20.0f, 0, &Left); Left.VSplitLeft(130.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Size:"), 14.0f, -1); unsigned Size = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[3]); if(Size > 1024*1024) str_format(aBuf, sizeof(aBuf), Localize("%.2f MiB"), float(Size)/(1024*1024)); else str_format(aBuf, sizeof(aBuf), Localize("%.2f KiB"), float(Size)/1024); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(20.0f, 0, &Left); Left.VSplitLeft(130.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1); unsigned Crc = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[3]); str_format(aBuf, sizeof(aBuf), "%08x", Crc); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Netversion:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aNetversion, 14.0f, -1); } // demo list CUIRect Headers; ListBox.HSplitTop(ms_ListheaderHeight, &Headers, &ListBox); struct CColumn { int m_ID; int m_Sort; CLocConstString m_Caption; int m_Direction; float m_Width; int m_Flags; CUIRect m_Rect; CUIRect m_Spacer; }; enum { COL_ICON=0, COL_DEMONAME, COL_DATE, SORT_DEMONAME=0, SORT_DATE, }; static CColumn s_aCols[] = { {COL_ICON, -1, " ", -1, 14.0f, 0, 0, 0}, {COL_DEMONAME, SORT_DEMONAME, "Demo", 0, 0.0f, 0, 0, 0}, {COL_DATE, SORT_DATE, "Date", 1, 300.0f, 0, 0, 0}, }; RenderTools()->DrawUIRect(&Headers, vec4(0.0f,0,0,0.15f), 0, 0); int NumCols = sizeof(s_aCols)/sizeof(CColumn); // do layout for(int i = 0; i < NumCols; i++) { if(s_aCols[i].m_Direction == -1) { Headers.VSplitLeft(s_aCols[i].m_Width, &s_aCols[i].m_Rect, &Headers); if(i+1 < NumCols) { //Cols[i].flags |= SPACER; Headers.VSplitLeft(2, &s_aCols[i].m_Spacer, &Headers); } } } for(int i = NumCols-1; i >= 0; i--) { if(s_aCols[i].m_Direction == 1) { Headers.VSplitRight(s_aCols[i].m_Width, &Headers, &s_aCols[i].m_Rect); Headers.VSplitRight(2, &Headers, &s_aCols[i].m_Spacer); } } for(int i = 0; i < NumCols; i++) { if(s_aCols[i].m_Direction == 0) s_aCols[i].m_Rect = Headers; } // do headers for(int i = 0; i < NumCols; i++) { CPointerContainer Container(s_aCols[i].m_Caption); if(DoButton_GridHeader(&Container, s_aCols[i].m_Caption, g_Config.m_BrDemoSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect)) { if(s_aCols[i].m_Sort != -1) { if(g_Config.m_BrDemoSort == s_aCols[i].m_Sort) g_Config.m_BrDemoSortOrder ^= 1; else g_Config.m_BrDemoSortOrder = 0; g_Config.m_BrDemoSort = s_aCols[i].m_Sort; } DemolistPopulate(); DemolistOnUpdate(false); } } // scrollbar CUIRect Scroll; #if defined(__ANDROID__) ListBox.VSplitRight(50, &ListBox, &Scroll); #else ListBox.VSplitRight(15, &ListBox, &Scroll); #endif int Num = (int)(ListBox.h/s_aCols[0].m_Rect.h) + 1; static CButtonContainer s_ScrollBar; static float s_ScrollValue = 0; Scroll.HMargin(5.0f, &Scroll); s_ScrollValue = DoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); int ScrollNum = m_lDemos.size()-Num+1; if(ScrollNum > 0) { if(m_ScrollOffset) { s_ScrollValue = (float)(m_ScrollOffset)/ScrollNum; m_ScrollOffset = 0; } if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&ListBox) && m_pClient->m_pGameConsole->IsClosed()) s_ScrollValue -= 3.0f/ScrollNum; if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&ListBox) && m_pClient->m_pGameConsole->IsClosed()) s_ScrollValue += 3.0f/ScrollNum; } else ScrollNum = 0; if(m_DemolistSelectedIndex > -1) { for(int i = 0; i < m_NumInputEvents; i++) { int NewIndex = -1; if(m_aInputEvents[i].m_Flags&IInput::FLAG_PRESS) { if(m_aInputEvents[i].m_Key == KEY_DOWN) NewIndex = m_DemolistSelectedIndex + 1; if(m_aInputEvents[i].m_Key == KEY_UP) NewIndex = m_DemolistSelectedIndex - 1; } if(NewIndex > -1 && NewIndex < m_lDemos.size()) { //scroll float IndexY = ListBox.y - s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h + NewIndex*s_aCols[0].m_Rect.h; int Scroll = ListBox.y > IndexY ? -1 : ListBox.y+ListBox.h < IndexY+s_aCols[0].m_Rect.h ? 1 : 0; if(Scroll) { if(Scroll < 0) { int NumScrolls = (ListBox.y-IndexY+s_aCols[0].m_Rect.h-1.0f)/s_aCols[0].m_Rect.h; s_ScrollValue -= (1.0f/ScrollNum)*NumScrolls; } else { int NumScrolls = (IndexY+s_aCols[0].m_Rect.h-(ListBox.y+ListBox.h)+s_aCols[0].m_Rect.h-1.0f)/s_aCols[0].m_Rect.h; s_ScrollValue += (1.0f/ScrollNum)*NumScrolls; } } m_DemolistSelectedIndex = NewIndex; str_copy(g_Config.m_UiDemoSelected, m_lDemos[NewIndex].m_aName, sizeof(g_Config.m_UiDemoSelected)); DemolistOnUpdate(false); } } } if(s_ScrollValue < 0) s_ScrollValue = 0; if(s_ScrollValue > 1) s_ScrollValue = 1; // set clipping UI()->ClipEnable(&ListBox); CUIRect OriginalView = ListBox; ListBox.y -= s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h; int NewSelected = -1; #if defined(__ANDROID__) int DoubleClicked = 0; #endif int ItemIndex = -1; for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front()) { ItemIndex++; CUIRect Row; CUIRect SelectHitBox; ListBox.HSplitTop(ms_ListheaderHeight, &Row, &ListBox); SelectHitBox = Row; int Selected = ItemIndex == m_DemolistSelectedIndex; // make sure that only those in view can be selected if(Row.y+Row.h > OriginalView.y && Row.y < OriginalView.y+OriginalView.h) { if(Selected) { CUIRect r = Row; r.Margin(1.5f, &r); RenderTools()->DrawUIRect(&r, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f); } // clip the selection if(SelectHitBox.y < OriginalView.y) // top { SelectHitBox.h -= OriginalView.y-SelectHitBox.y; SelectHitBox.y = OriginalView.y; } else if(SelectHitBox.y+SelectHitBox.h > OriginalView.y+OriginalView.h) // bottom SelectHitBox.h = OriginalView.y+OriginalView.h-SelectHitBox.y; if(UI()->DoButtonLogic(r.front().m_aName /* TODO: */, "", Selected, &SelectHitBox)) { NewSelected = ItemIndex; str_copy(g_Config.m_UiDemoSelected, r.front().m_aName, sizeof(g_Config.m_UiDemoSelected)); DemolistOnUpdate(false); #if defined(__ANDROID__) if(NewSelected == m_DoubleClickIndex) DoubleClicked = 1; #endif m_DoubleClickIndex = NewSelected; } } else { // don't render invisible items continue; } for(int c = 0; c < NumCols; c++) { CUIRect Button; Button.x = s_aCols[c].m_Rect.x; Button.y = Row.y; Button.h = Row.h; Button.w = s_aCols[c].m_Rect.w; int ID = s_aCols[c].m_ID; if (ID == COL_ICON) { DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &Button); } else if(ID == COL_DEMONAME) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; TextRender()->TextEx(&Cursor, r.front().m_aName, -1); } else if (ID == COL_DATE && !r.front().m_IsDir) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; char aBuf[256]; str_timestamp_ex(r.front().m_Date, aBuf, sizeof(aBuf), "%Y-%m-%d %H:%M:%S"); TextRender()->TextEx(&Cursor, aBuf, -1); } } } UI()->ClipDisable(); bool Activated = false; #if defined(__ANDROID__) if (m_EnterPressed || (DoubleClicked && UI()->HotItem() == m_lDemos[m_DemolistSelectedIndex].m_aName)) #else if (m_EnterPressed || (Input()->MouseDoubleClick() && UI()->HotItem() == m_lDemos[m_DemolistSelectedIndex].m_aName)) #endif { UI()->SetActiveItem(0); Activated = true; } static CButtonContainer s_RefreshButton; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect) || Input()->KeyPress(KEY_F5) || (Input()->KeyPress(KEY_R) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL)))) { DemolistPopulate(); DemolistOnUpdate(false); } static CButtonContainer s_PlayButton; if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated) { if(m_DemolistSelectedIndex >= 0) { if(m_DemolistSelectedIsDir) // folder { if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { char aTemp[256]; str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename); m_DemolistStorageType = m_lDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); DemolistOnUpdate(true); } else // file { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok")); else { UI()->SetActiveItem(0); return; } } } } if(!m_DemolistSelectedIsDir) { static CButtonContainer s_DeleteButton; if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_DELETE_DEMO; return; } } static CButtonContainer s_RenameButton; if(DoButton_Menu(&s_RenameButton, Localize("Rename"), 0, &RenameRect)) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_RENAME_DEMO; str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile)); return; } } } }