mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #5246
5246: Use std::vector instead of sorted_array, remove base/tl/sorted_array.h r=def- a=heinrich5991 This replaces all usages of `sorted_array` with `std::vector`. This requires the following general changes: - `add_unsorted` is replaced with `push_back`. - `add` is replaced with `push_back` and subsequent `sort` or `stable_sort` must be ensured. - In some cases, immediately sorting the entire list after adding an item was unavoidable. Previously items were added at the correct position, which was O(N) because all items after the inserted one had to be moved in any case. - `sort_range` is replaced with `sort` or `stable_sort`. - `size` returns a `size_t` instead of `int`, so to fix sign comparison warnings, casts are added where necessary or types of loop variables are changed to `size_t` where possible. For-each loops are also used where possible / where required by clang-tidy. - `find_binary` is replaced with `std::equal_range`. This can only find items of the same type, so some wrappers, that only have the relevant fields set, need to be created for searching. In terms of behavior, this should not change anything, except maybe `CLocalizationDatabase` for the better. As far as I understand it, at lot of the code there was not doing anything. It assumes that binary search can return a range of multiple entries, but the equality/comparison function is based on hash and context hash. This means that any item in this range will match the given hash and context hash already, so all of the following checks are redundant. I changed this to first do a lookup with the hash and context hash and if that fails do another lookup with the default context hash. I have also already replaced `base/tl/array.h` with `std::vector`, removing all of `base/tl` except `threading.h`. I'll make a separate PR later because this caused a lot more changes especially in the editor that I first want to test and review myself. Naming of `array`/`sorted_array`/`std::vector` variables was rather inconsistent (sometimes prefix `a` or `l` is used), so ~~I chose to not use any prefix for all new `std::vector`s~~ heinrich5991 left them as-is. ## Checklist - [X] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
commit
7348bf4d56
|
@ -1690,7 +1690,6 @@ set_src(BASE GLOB_RECURSE src/base
|
|||
tl/allocator.h
|
||||
tl/array.h
|
||||
tl/range.h
|
||||
tl/sorted_array.h
|
||||
tl/threading.h
|
||||
unicode/confusables.cpp
|
||||
unicode/confusables.h
|
||||
|
@ -2504,7 +2503,6 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST)
|
|||
secure_random.cpp
|
||||
serverbrowser.cpp
|
||||
serverinfo.cpp
|
||||
sorted_array.cpp
|
||||
str.cpp
|
||||
strip_path_and_extension.cpp
|
||||
teehistorian.cpp
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#ifndef BASE_TL_SORTED_ARRAY_H
|
||||
#define BASE_TL_SORTED_ARRAY_H
|
||||
|
||||
#include "base/tl/algorithm.h"
|
||||
#include "base/tl/array.h"
|
||||
|
||||
template<class T, class ALLOCATOR = allocator_default<T>>
|
||||
class sorted_array : public array<T, ALLOCATOR>
|
||||
{
|
||||
typedef array<T, ALLOCATOR> parent;
|
||||
|
||||
// insert and size is not allowed
|
||||
int insert(const T &item, typename parent::range r)
|
||||
{
|
||||
dbg_break();
|
||||
return 0;
|
||||
}
|
||||
int set_size(int new_size)
|
||||
{
|
||||
dbg_break();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef plain_range_sorted<T> range;
|
||||
|
||||
int add(const T &item)
|
||||
{
|
||||
return parent::insert(item, partition_binary(all(), item));
|
||||
}
|
||||
|
||||
int add_unsorted(const T &item)
|
||||
{
|
||||
return parent::add(item);
|
||||
}
|
||||
|
||||
void sort_range()
|
||||
{
|
||||
if(parent::size() > 0)
|
||||
sort(all());
|
||||
}
|
||||
|
||||
/*
|
||||
Function: all
|
||||
Returns a sorted range that contains the whole array.
|
||||
*/
|
||||
range all() { return range(parent::list, parent::list + parent::num_elements); }
|
||||
range all() const { return range(parent::list, parent::list + parent::num_elements); }
|
||||
};
|
||||
|
||||
#endif // TL_FILE_SORTED_ARRAY_HPP
|
|
@ -112,7 +112,7 @@ void CUuidManager::RegisterName(int ID, const char *pName)
|
|||
CNameIndexed NameIndexed;
|
||||
NameIndexed.m_Uuid = Name.m_Uuid;
|
||||
NameIndexed.m_ID = GetIndex(ID);
|
||||
m_aNamesSorted.add(NameIndexed);
|
||||
m_aNamesSorted.insert(std::lower_bound(m_aNamesSorted.begin(), m_aNamesSorted.end(), NameIndexed), NameIndexed);
|
||||
}
|
||||
|
||||
CUuid CUuidManager::GetUuid(int ID) const
|
||||
|
@ -127,10 +127,13 @@ const char *CUuidManager::GetName(int ID) const
|
|||
|
||||
int CUuidManager::LookupUuid(CUuid Uuid) const
|
||||
{
|
||||
sorted_array<CNameIndexed>::range Pos = ::find_binary(m_aNamesSorted.all(), Uuid);
|
||||
if(!Pos.empty())
|
||||
CNameIndexed Needle;
|
||||
Needle.m_Uuid = Uuid;
|
||||
Needle.m_ID = 0;
|
||||
auto Range = std::equal_range(m_aNamesSorted.begin(), m_aNamesSorted.end(), Needle);
|
||||
if(std::distance(Range.first, Range.second) == 1)
|
||||
{
|
||||
return GetID(Pos.front().m_ID);
|
||||
return GetID(Range.first->m_ID);
|
||||
}
|
||||
return UUID_UNKNOWN;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define ENGINE_SHARED_UUID_MANAGER_H
|
||||
|
||||
#include <base/tl/array.h>
|
||||
#include <base/tl/sorted_array.h>
|
||||
#include <vector>
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -42,8 +42,7 @@ struct CNameIndexed
|
|||
int m_ID;
|
||||
|
||||
bool operator<(const CNameIndexed &Other) const { return m_Uuid < Other.m_Uuid; }
|
||||
bool operator<(const CUuid &Other) const { return m_Uuid < Other; }
|
||||
bool operator==(const CUuid &Other) const { return m_Uuid == Other; }
|
||||
bool operator==(const CNameIndexed &Other) const { return m_Uuid == Other.m_Uuid; }
|
||||
};
|
||||
|
||||
class CPacker;
|
||||
|
@ -52,7 +51,7 @@ class CUnpacker;
|
|||
class CUuidManager
|
||||
{
|
||||
array<CName> m_aNames;
|
||||
sorted_array<CNameIndexed> m_aNamesSorted;
|
||||
std::vector<CNameIndexed> m_aNamesSorted;
|
||||
|
||||
public:
|
||||
void RegisterName(int ID, const char *pName);
|
||||
|
|
|
@ -34,7 +34,7 @@ CChat::CChat()
|
|||
|
||||
#define CHAT_COMMAND(name, params, flags, callback, userdata, help) RegisterCommand(name, params, flags, help);
|
||||
#include <game/ddracechat.h>
|
||||
m_Commands.sort_range();
|
||||
std::sort(m_Commands.begin(), m_Commands.end());
|
||||
|
||||
m_Mode = MODE_NONE;
|
||||
Reset();
|
||||
|
@ -42,7 +42,7 @@ CChat::CChat()
|
|||
|
||||
void CChat::RegisterCommand(const char *pName, const char *pParams, int flags, const char *pHelp)
|
||||
{
|
||||
m_Commands.add_unsorted(CCommand{pName, pParams});
|
||||
m_Commands.emplace_back(pName, pParams);
|
||||
}
|
||||
|
||||
void CChat::RebuildChat()
|
||||
|
@ -380,7 +380,7 @@ bool CChat::OnInput(IInput::CEvent Event)
|
|||
|
||||
auto &Command = m_Commands[Index];
|
||||
|
||||
if(str_startswith(Command.pName, pCommandStart))
|
||||
if(str_startswith(Command.m_pName, pCommandStart))
|
||||
{
|
||||
pCompletionCommand = &Command;
|
||||
m_CompletionChosen = Index + SearchType * NumCommands;
|
||||
|
@ -397,10 +397,10 @@ bool CChat::OnInput(IInput::CEvent Event)
|
|||
|
||||
// add the command
|
||||
str_append(aBuf, "/", sizeof(aBuf));
|
||||
str_append(aBuf, pCompletionCommand->pName, sizeof(aBuf));
|
||||
str_append(aBuf, pCompletionCommand->m_pName, sizeof(aBuf));
|
||||
|
||||
// add separator
|
||||
const char *pSeparator = pCompletionCommand->pParams[0] == '\0' ? "" : " ";
|
||||
const char *pSeparator = pCompletionCommand->m_pParams[0] == '\0' ? "" : " ";
|
||||
str_append(aBuf, pSeparator, sizeof(aBuf));
|
||||
if(*pSeparator)
|
||||
str_append(aBuf, pSeparator, sizeof(aBuf));
|
||||
|
@ -408,7 +408,7 @@ bool CChat::OnInput(IInput::CEvent Event)
|
|||
// add part after the name
|
||||
str_append(aBuf, m_Input.GetString() + m_PlaceholderOffset + m_PlaceholderLength, sizeof(aBuf));
|
||||
|
||||
m_PlaceholderLength = str_length(pSeparator) + str_length(pCompletionCommand->pName) + 1;
|
||||
m_PlaceholderLength = str_length(pSeparator) + str_length(pCompletionCommand->m_pName) + 1;
|
||||
m_OldChatStringLength = m_Input.GetLength();
|
||||
m_Input.Set(aBuf); // TODO: Use Add instead
|
||||
m_Input.SetCursorOffset(m_PlaceholderOffset + m_PlaceholderLength);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#ifndef GAME_CLIENT_COMPONENTS_CHAT_H
|
||||
#define GAME_CLIENT_COMPONENTS_CHAT_H
|
||||
#include <vector>
|
||||
|
||||
#include <engine/shared/config.h>
|
||||
#include <engine/shared/ringbuffer.h>
|
||||
|
||||
|
@ -91,15 +93,21 @@ class CChat : public CComponent
|
|||
|
||||
struct CCommand
|
||||
{
|
||||
const char *pName;
|
||||
const char *pParams;
|
||||
const char *m_pName;
|
||||
const char *m_pParams;
|
||||
|
||||
bool operator<(const CCommand &Other) const { return str_comp(pName, Other.pName) < 0; }
|
||||
bool operator<=(const CCommand &Other) const { return str_comp(pName, Other.pName) <= 0; }
|
||||
bool operator==(const CCommand &Other) const { return str_comp(pName, Other.pName) == 0; }
|
||||
CCommand() {}
|
||||
CCommand(const char *pName, const char *pParams) :
|
||||
m_pName(pName), m_pParams(pParams)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const CCommand &Other) const { return str_comp(m_pName, Other.m_pName) < 0; }
|
||||
bool operator<=(const CCommand &Other) const { return str_comp(m_pName, Other.m_pName) <= 0; }
|
||||
bool operator==(const CCommand &Other) const { return str_comp(m_pName, Other.m_pName) == 0; }
|
||||
};
|
||||
|
||||
sorted_array<CCommand> m_Commands;
|
||||
std::vector<CCommand> m_Commands;
|
||||
bool m_ReverseTAB;
|
||||
|
||||
struct CHistoryEntry
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include <base/logger.h>
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <base/math.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
|
|
@ -81,15 +81,15 @@ void CCountryFlags::LoadCountryflagsIndexfile()
|
|||
str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf);
|
||||
}
|
||||
m_aCountryFlags.add_unsorted(CountryFlag);
|
||||
m_aCountryFlags.push_back(CountryFlag);
|
||||
}
|
||||
io_close(File);
|
||||
m_aCountryFlags.sort_range();
|
||||
std::sort(m_aCountryFlags.begin(), m_aCountryFlags.end());
|
||||
|
||||
// find index of default item
|
||||
int DefaultIndex = 0, Index = 0;
|
||||
for(sorted_array<CCountryFlag>::range r = m_aCountryFlags.all(); !r.empty(); r.pop_front(), ++Index)
|
||||
if(r.front().m_CountryCode == -1)
|
||||
size_t DefaultIndex = 0;
|
||||
for(size_t Index = 0; Index < m_aCountryFlags.size(); ++Index)
|
||||
if(m_aCountryFlags[Index].m_CountryCode == -1)
|
||||
{
|
||||
DefaultIndex = Index;
|
||||
break;
|
||||
|
@ -97,11 +97,11 @@ void CCountryFlags::LoadCountryflagsIndexfile()
|
|||
|
||||
// init LUT
|
||||
if(DefaultIndex != 0)
|
||||
for(int &CodeIndexLUT : m_CodeIndexLUT)
|
||||
for(size_t &CodeIndexLUT : m_CodeIndexLUT)
|
||||
CodeIndexLUT = DefaultIndex;
|
||||
else
|
||||
mem_zero(m_CodeIndexLUT, sizeof(m_CodeIndexLUT));
|
||||
for(int i = 0; i < m_aCountryFlags.size(); ++i)
|
||||
for(size_t i = 0; i < m_aCountryFlags.size(); ++i)
|
||||
m_CodeIndexLUT[maximum(0, (m_aCountryFlags[i].m_CountryCode - CODE_LB) % CODE_RANGE)] = i;
|
||||
}
|
||||
|
||||
|
@ -110,13 +110,13 @@ void CCountryFlags::OnInit()
|
|||
// load country flags
|
||||
m_aCountryFlags.clear();
|
||||
LoadCountryflagsIndexfile();
|
||||
if(!m_aCountryFlags.size())
|
||||
if(m_aCountryFlags.empty())
|
||||
{
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "countryflags", "failed to load country flags. folder='countryflags/'");
|
||||
CCountryFlag DummyEntry;
|
||||
DummyEntry.m_CountryCode = -1;
|
||||
mem_zero(DummyEntry.m_aCountryCodeString, sizeof(DummyEntry.m_aCountryCodeString));
|
||||
m_aCountryFlags.add(DummyEntry);
|
||||
m_aCountryFlags.push_back(DummyEntry);
|
||||
}
|
||||
|
||||
m_FlagsQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
||||
|
@ -126,7 +126,7 @@ void CCountryFlags::OnInit()
|
|||
Graphics()->QuadContainerUpload(m_FlagsQuadContainerIndex);
|
||||
}
|
||||
|
||||
int CCountryFlags::Num() const
|
||||
size_t CCountryFlags::Num() const
|
||||
{
|
||||
return m_aCountryFlags.size();
|
||||
}
|
||||
|
@ -136,9 +136,9 @@ const CCountryFlags::CCountryFlag *CCountryFlags::GetByCountryCode(int CountryCo
|
|||
return GetByIndex(m_CodeIndexLUT[maximum(0, (CountryCode - CODE_LB) % CODE_RANGE)]);
|
||||
}
|
||||
|
||||
const CCountryFlags::CCountryFlag *CCountryFlags::GetByIndex(int Index) const
|
||||
const CCountryFlags::CCountryFlag *CCountryFlags::GetByIndex(size_t Index) const
|
||||
{
|
||||
return &m_aCountryFlags[maximum(0, Index % m_aCountryFlags.size())];
|
||||
return &m_aCountryFlags[Index % m_aCountryFlags.size()];
|
||||
}
|
||||
|
||||
void CCountryFlags::Render(int CountryCode, const ColorRGBA *pColor, float x, float y, float w, float h)
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#ifndef GAME_CLIENT_COMPONENTS_COUNTRYFLAGS_H
|
||||
#define GAME_CLIENT_COMPONENTS_COUNTRYFLAGS_H
|
||||
#include <base/tl/sorted_array.h>
|
||||
#include <base/vmath.h>
|
||||
#include <game/client/component.h>
|
||||
#include <vector>
|
||||
|
||||
class CCountryFlags : public CComponent
|
||||
{
|
||||
|
@ -21,9 +21,9 @@ public:
|
|||
virtual int Sizeof() const override { return sizeof(*this); }
|
||||
void OnInit() override;
|
||||
|
||||
int Num() const;
|
||||
size_t Num() const;
|
||||
const CCountryFlag *GetByCountryCode(int CountryCode) const;
|
||||
const CCountryFlag *GetByIndex(int Index) const;
|
||||
const CCountryFlag *GetByIndex(size_t Index) const;
|
||||
void Render(int CountryCode, const ColorRGBA *pColor, float x, float y, float w, float h);
|
||||
|
||||
private:
|
||||
|
@ -33,8 +33,8 @@ private:
|
|||
CODE_UB = 999,
|
||||
CODE_RANGE = CODE_UB - CODE_LB + 1,
|
||||
};
|
||||
sorted_array<CCountryFlag> m_aCountryFlags;
|
||||
int m_CodeIndexLUT[CODE_RANGE];
|
||||
std::vector<CCountryFlag> m_aCountryFlags;
|
||||
size_t m_CodeIndexLUT[CODE_RANGE];
|
||||
|
||||
int m_FlagsQuadContainerIndex;
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <engine/demo.h>
|
||||
#include <engine/engine.h>
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include <base/tl/array.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <base/math.h>
|
||||
|
@ -1873,13 +1871,13 @@ int CMenus::Render()
|
|||
int OldSelected = -1;
|
||||
UiDoListboxStart(&s_ScrollValue, &Box, 50.0f, Localize("Country / Region"), "", m_pClient->m_CountryFlags.Num(), 6, OldSelected, s_ScrollValue);
|
||||
|
||||
for(int i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
||||
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
||||
{
|
||||
const CCountryFlags::CCountryFlag *pEntry = m_pClient->m_CountryFlags.GetByIndex(i);
|
||||
if(pEntry->m_CountryCode == CurSelection)
|
||||
OldSelected = i;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i);
|
||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
CUIRect Label;
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
#ifndef GAME_CLIENT_COMPONENTS_MENUS_H
|
||||
#define GAME_CLIENT_COMPONENTS_MENUS_H
|
||||
|
||||
#include <base/tl/sorted_array.h>
|
||||
#include <base/vmath.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
#include <engine/demo.h>
|
||||
#include <engine/friends.h>
|
||||
#include <engine/shared/config.h>
|
||||
|
@ -252,11 +253,11 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
sorted_array<SCustomEntities> m_EntitiesList;
|
||||
sorted_array<SCustomGame> m_GameList;
|
||||
sorted_array<SCustomEmoticon> m_EmoticonList;
|
||||
sorted_array<SCustomParticle> m_ParticlesList;
|
||||
sorted_array<SCustomHud> m_HudList;
|
||||
std::vector<SCustomEntities> m_EntitiesList;
|
||||
std::vector<SCustomGame> m_GameList;
|
||||
std::vector<SCustomEmoticon> m_EmoticonList;
|
||||
std::vector<SCustomParticle> m_ParticlesList;
|
||||
std::vector<SCustomHud> m_HudList;
|
||||
|
||||
bool m_IsInit = false;
|
||||
|
||||
|
@ -428,7 +429,6 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
//sorted_array<CDemoItem> m_lDemos;
|
||||
char m_aCurrentDemoFolder[256];
|
||||
char m_aCurrentDemoFile[64];
|
||||
int m_DemolistSelectedIndex;
|
||||
|
@ -448,6 +448,12 @@ protected:
|
|||
const CFriendInfo *m_pFriendInfo;
|
||||
int m_NumFound;
|
||||
|
||||
CFriendItem() {}
|
||||
CFriendItem(const CFriendInfo *pFriendInfo) :
|
||||
m_pFriendInfo(pFriendInfo), m_NumFound(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const CFriendItem &Other) const
|
||||
{
|
||||
if(m_NumFound && !Other.m_NumFound)
|
||||
|
@ -465,7 +471,7 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
sorted_array<CFriendItem> m_lFriends;
|
||||
std::vector<CFriendItem> m_lFriends;
|
||||
int m_FriendlistSelectedIndex;
|
||||
|
||||
void FriendlistOnUpdate();
|
||||
|
@ -616,7 +622,7 @@ public:
|
|||
|
||||
// DDRace
|
||||
int DoButton_CheckBox_DontCare(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
|
||||
sorted_array<CDemoItem> m_lDemos;
|
||||
std::vector<CDemoItem> m_lDemos;
|
||||
void DemolistPopulate();
|
||||
bool m_Dummy;
|
||||
|
||||
|
@ -641,7 +647,7 @@ public:
|
|||
bool HasFile() const { return m_aFilename[0]; }
|
||||
};
|
||||
|
||||
sorted_array<CGhostItem> m_lGhosts;
|
||||
std::vector<CGhostItem> m_lGhosts;
|
||||
|
||||
std::chrono::nanoseconds m_GhostPopulateStartTime{0};
|
||||
|
||||
|
|
|
@ -221,8 +221,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
m_SelectedIndex = -1;
|
||||
|
||||
// reset friend counter
|
||||
for(int i = 0; i < m_lFriends.size(); m_lFriends[i++].m_NumFound = 0)
|
||||
;
|
||||
for(auto &Friend : m_lFriends)
|
||||
Friend.m_NumFound = 0;
|
||||
|
||||
auto RenderBrowserIcons = [this](CUIElement::SUIElementRect &UIRect, CUIRect *pRect, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor, const char *pText, ETextAlignment TextAlign, bool SmallFont = false) {
|
||||
float FontSize = 14.0f * UI()->Scale();
|
||||
|
@ -269,13 +269,13 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
{
|
||||
unsigned NameHash = str_quickhash(pItem->m_aClients[j].m_aName);
|
||||
unsigned ClanHash = str_quickhash(pItem->m_aClients[j].m_aClan);
|
||||
for(int f = 0; f < m_lFriends.size(); ++f)
|
||||
for(auto &Friend : m_lFriends)
|
||||
{
|
||||
if(((g_Config.m_ClFriendsIgnoreClan && m_lFriends[f].m_pFriendInfo->m_aName[0]) || (ClanHash == m_lFriends[f].m_pFriendInfo->m_ClanHash && !str_comp(m_lFriends[f].m_pFriendInfo->m_aClan, pItem->m_aClients[j].m_aClan))) &&
|
||||
(!m_lFriends[f].m_pFriendInfo->m_aName[0] || (NameHash == m_lFriends[f].m_pFriendInfo->m_NameHash && !str_comp(m_lFriends[f].m_pFriendInfo->m_aName, pItem->m_aClients[j].m_aName))))
|
||||
if(((g_Config.m_ClFriendsIgnoreClan && Friend.m_pFriendInfo->m_aName[0]) || (ClanHash == Friend.m_pFriendInfo->m_ClanHash && !str_comp(Friend.m_pFriendInfo->m_aClan, pItem->m_aClients[j].m_aClan))) &&
|
||||
(!Friend.m_pFriendInfo->m_aName[0] || (NameHash == Friend.m_pFriendInfo->m_NameHash && !str_comp(Friend.m_pFriendInfo->m_aName, pItem->m_aClients[j].m_aName))))
|
||||
{
|
||||
m_lFriends[f].m_NumFound++;
|
||||
if(m_lFriends[f].m_pFriendInfo->m_aName[0])
|
||||
Friend.m_NumFound++;
|
||||
if(Friend.m_pFriendInfo->m_aName[0])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1250,13 +1250,8 @@ void CMenus::FriendlistOnUpdate()
|
|||
{
|
||||
m_lFriends.clear();
|
||||
for(int i = 0; i < m_pClient->Friends()->NumFriends(); ++i)
|
||||
{
|
||||
CFriendItem Item;
|
||||
Item.m_pFriendInfo = m_pClient->Friends()->GetFriend(i);
|
||||
Item.m_NumFound = 0;
|
||||
m_lFriends.add_unsorted(Item);
|
||||
}
|
||||
m_lFriends.sort_range();
|
||||
m_lFriends.emplace_back(m_pClient->Friends()->GetFriend(i));
|
||||
std::sort(m_lFriends.begin(), m_lFriends.end());
|
||||
}
|
||||
|
||||
void CMenus::RenderServerbrowserFriends(CUIRect View)
|
||||
|
@ -1286,14 +1281,14 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
|||
|
||||
// friends list(remove friend)
|
||||
static float s_ScrollValue = 0;
|
||||
if(m_FriendlistSelectedIndex >= m_lFriends.size())
|
||||
if(m_FriendlistSelectedIndex >= (int)m_lFriends.size())
|
||||
m_FriendlistSelectedIndex = m_lFriends.size() - 1;
|
||||
UiDoListboxStart(&m_lFriends, &List, 30.0f, "", "", m_lFriends.size(), 1, m_FriendlistSelectedIndex, s_ScrollValue);
|
||||
|
||||
m_lFriends.sort_range();
|
||||
for(int i = 0; i < m_lFriends.size(); ++i)
|
||||
std::sort(m_lFriends.begin(), m_lFriends.end());
|
||||
for(auto &Friend : m_lFriends)
|
||||
{
|
||||
CListboxItem Item = UiDoListboxNextItem(&m_lFriends[i], false, false);
|
||||
CListboxItem Item = UiDoListboxNextItem(&Friend.m_NumFound, false, false);
|
||||
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
|
@ -1304,14 +1299,14 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
|||
|
||||
Item.m_Rect.VMargin(2.5f, &Item.m_Rect);
|
||||
Item.m_Rect.HSplitTop(12.0f, &Item.m_Rect, &Button);
|
||||
UI()->DoLabelScaled(&Item.m_Rect, m_lFriends[i].m_pFriendInfo->m_aName, FontSize, TEXTALIGN_LEFT);
|
||||
UI()->DoLabelScaled(&Button, m_lFriends[i].m_pFriendInfo->m_aClan, FontSize, TEXTALIGN_LEFT);
|
||||
UI()->DoLabelScaled(&Item.m_Rect, Friend.m_pFriendInfo->m_aName, FontSize, TEXTALIGN_LEFT);
|
||||
UI()->DoLabelScaled(&Button, Friend.m_pFriendInfo->m_aClan, FontSize, TEXTALIGN_LEFT);
|
||||
|
||||
RenderTools()->DrawUIRect(&OnState, m_lFriends[i].m_NumFound ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.25f) : ColorRGBA(1.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_R, 4.0f);
|
||||
RenderTools()->DrawUIRect(&OnState, Friend.m_NumFound ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.25f) : ColorRGBA(1.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_R, 4.0f);
|
||||
OnState.HMargin((OnState.h - FontSize) / 3, &OnState);
|
||||
OnState.VMargin(5.0f, &OnState);
|
||||
char aBuf[64];
|
||||
str_format(aBuf, sizeof(aBuf), "%i", m_lFriends[i].m_NumFound);
|
||||
str_format(aBuf, sizeof(aBuf), "%i", Friend.m_NumFound);
|
||||
UI()->DoLabelScaled(&OnState, aBuf, FontSize + 2, TEXTALIGN_RIGHT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -767,7 +767,7 @@ int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int Stora
|
|||
}
|
||||
Item.m_IsDir = IsDir != 0;
|
||||
Item.m_StorageType = StorageType;
|
||||
pSelf->m_lDemos.add_unsorted(Item);
|
||||
pSelf->m_lDemos.push_back(Item);
|
||||
|
||||
if(tw::time_get() - pSelf->m_DemoPopulateStartTime > 500ms)
|
||||
{
|
||||
|
@ -788,7 +788,7 @@ void CMenus::DemolistPopulate()
|
|||
if(g_Config.m_BrDemoFetchInfo)
|
||||
FetchAllHeaders();
|
||||
|
||||
m_lDemos.sort_range();
|
||||
std::stable_sort(m_lDemos.begin(), m_lDemos.end());
|
||||
}
|
||||
|
||||
void CMenus::DemolistOnUpdate(bool Reset)
|
||||
|
@ -800,11 +800,11 @@ void CMenus::DemolistOnUpdate(bool Reset)
|
|||
bool Found = false;
|
||||
int SelectedIndex = -1;
|
||||
// search for selected index
|
||||
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
|
||||
for(auto &Item : m_lDemos)
|
||||
{
|
||||
SelectedIndex++;
|
||||
|
||||
if(str_comp(g_Config.m_UiDemoSelected, r.front().m_aName) == 0)
|
||||
if(str_comp(g_Config.m_UiDemoSelected, Item.m_aName) == 0)
|
||||
{
|
||||
Found = true;
|
||||
break;
|
||||
|
@ -815,8 +815,8 @@ void CMenus::DemolistOnUpdate(bool Reset)
|
|||
m_DemolistSelectedIndex = SelectedIndex;
|
||||
}
|
||||
|
||||
m_DemolistSelectedIndex = Reset ? m_lDemos.size() > 0 ? 0 : -1 :
|
||||
m_DemolistSelectedIndex >= m_lDemos.size() ? m_lDemos.size() - 1 : m_DemolistSelectedIndex;
|
||||
m_DemolistSelectedIndex = Reset ? !m_lDemos.empty() ? 0 : -1 :
|
||||
m_DemolistSelectedIndex >= (int)m_lDemos.size() ? m_lDemos.size() - 1 : m_DemolistSelectedIndex;
|
||||
m_DemolistSelectedIsDir = m_DemolistSelectedIndex < 0 ? false : m_lDemos[m_DemolistSelectedIndex].m_IsDir;
|
||||
}
|
||||
|
||||
|
@ -834,11 +834,11 @@ bool CMenus::FetchHeader(CDemoItem &Item)
|
|||
|
||||
void CMenus::FetchAllHeaders()
|
||||
{
|
||||
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
|
||||
for(auto &Item : m_lDemos)
|
||||
{
|
||||
FetchHeader(r.front());
|
||||
FetchHeader(Item);
|
||||
}
|
||||
m_lDemos.sort_range();
|
||||
std::stable_sort(m_lDemos.begin(), m_lDemos.end());
|
||||
}
|
||||
|
||||
void CMenus::RenderDemoList(CUIRect MainView)
|
||||
|
@ -1070,7 +1070,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
}
|
||||
|
||||
// Don't rescan in order to keep fetched headers, just resort
|
||||
m_lDemos.sort_range();
|
||||
std::stable_sort(m_lDemos.begin(), m_lDemos.end());
|
||||
DemolistOnUpdate(false);
|
||||
}
|
||||
}
|
||||
|
@ -1095,13 +1095,13 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
|
||||
CUIRect OriginalView = ListBox;
|
||||
int Num = (int)(ListBox.h / s_aCols[0].m_Rect.h) + 1;
|
||||
int ScrollNum = maximum(m_lDemos.size() - Num + 1, 0);
|
||||
int ScrollNum = maximum<int>(m_lDemos.size() - Num + 1, 0);
|
||||
ListBox.y -= s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h;
|
||||
|
||||
int ItemIndex = -1;
|
||||
bool DoubleClicked = false;
|
||||
|
||||
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
|
||||
for(auto &Item : m_lDemos)
|
||||
{
|
||||
ItemIndex++;
|
||||
|
||||
|
@ -1126,10 +1126,10 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
RenderTools()->DrawUIRect(&Rect, ColorRGBA(1, 1, 1, 0.25f), CUI::CORNER_ALL, 4.0f);
|
||||
}
|
||||
|
||||
if(UI()->DoButtonLogic(r.front().m_aName, Selected, &Row))
|
||||
if(UI()->DoButtonLogic(Item.m_aName, Selected, &Row))
|
||||
{
|
||||
DoubleClicked |= ItemIndex == m_DoubleClickIndex;
|
||||
str_copy(g_Config.m_UiDemoSelected, r.front().m_aName, sizeof(g_Config.m_UiDemoSelected));
|
||||
str_copy(g_Config.m_UiDemoSelected, Item.m_aName, sizeof(g_Config.m_UiDemoSelected));
|
||||
DemolistOnUpdate(false);
|
||||
m_DoubleClickIndex = ItemIndex;
|
||||
}
|
||||
|
@ -1152,7 +1152,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
|
||||
if(ID == COL_ICON)
|
||||
{
|
||||
DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir ? SPRITE_FILE_FOLDER : SPRITE_FILE_DEMO1, &Button);
|
||||
DoButton_Icon(IMAGE_FILEICONS, Item.m_IsDir ? SPRITE_FILE_FOLDER : SPRITE_FILE_DEMO1, &Button);
|
||||
}
|
||||
else if(ID == COL_DEMONAME)
|
||||
{
|
||||
|
@ -1160,27 +1160,27 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 12.0f * UI()->Scale()) / 2.f, 12.0f * UI()->Scale(), TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||
Cursor.m_LineWidth = Button.w;
|
||||
|
||||
TextRender()->TextEx(&Cursor, r.front().m_aName, -1);
|
||||
TextRender()->TextEx(&Cursor, Item.m_aName, -1);
|
||||
}
|
||||
else if(ID == COL_MARKERS && !r.front().m_IsDir && r.front().m_InfosLoaded)
|
||||
else if(ID == COL_MARKERS && !Item.m_IsDir && Item.m_InfosLoaded)
|
||||
{
|
||||
char aBuf[3];
|
||||
str_format(aBuf, sizeof(aBuf), "%d", r.front().NumMarkers());
|
||||
str_format(aBuf, sizeof(aBuf), "%d", Item.NumMarkers());
|
||||
Button.VMargin(4.0f, &Button);
|
||||
UI()->DoLabelScaled(&Button, aBuf, 12.0f, TEXTALIGN_RIGHT);
|
||||
}
|
||||
else if(ID == COL_LENGTH && !r.front().m_IsDir && r.front().m_InfosLoaded)
|
||||
else if(ID == COL_LENGTH && !Item.m_IsDir && Item.m_InfosLoaded)
|
||||
{
|
||||
int Length = r.front().Length();
|
||||
int Length = Item.Length();
|
||||
char aBuf[32];
|
||||
str_time((int64_t)Length * 100, TIME_HOURS, aBuf, sizeof(aBuf));
|
||||
Button.VMargin(4.0f, &Button);
|
||||
UI()->DoLabelScaled(&Button, aBuf, 12.0f, TEXTALIGN_RIGHT);
|
||||
}
|
||||
else if(ID == COL_DATE && !r.front().m_IsDir)
|
||||
else if(ID == COL_DATE && !Item.m_IsDir)
|
||||
{
|
||||
char aBuf[64];
|
||||
str_timestamp_ex(r.front().m_Date, aBuf, sizeof(aBuf), FORMAT_SPACE);
|
||||
str_timestamp_ex(Item.m_Date, aBuf, sizeof(aBuf), FORMAT_SPACE);
|
||||
Button.VSplitRight(24.0f, &Button, 0);
|
||||
UI()->DoLabelScaled(&Button, aBuf, 12.0f, TEXTALIGN_RIGHT);
|
||||
}
|
||||
|
|
|
@ -918,7 +918,7 @@ int CMenus::GhostlistFetchCallback(const char *pName, int IsDir, int StorageType
|
|||
str_copy(Item.m_aPlayer, Info.m_aOwner, sizeof(Item.m_aPlayer));
|
||||
Item.m_Time = Info.m_Time;
|
||||
if(Item.m_Time > 0)
|
||||
pSelf->m_lGhosts.add(Item);
|
||||
pSelf->m_lGhosts.push_back(Item);
|
||||
|
||||
if(tw::time_get() - pSelf->m_GhostPopulateStartTime > 500ms)
|
||||
{
|
||||
|
@ -930,16 +930,15 @@ int CMenus::GhostlistFetchCallback(const char *pName, int IsDir, int StorageType
|
|||
|
||||
void CMenus::GhostlistPopulate()
|
||||
{
|
||||
CGhostItem *pOwnGhost = 0;
|
||||
m_lGhosts.clear();
|
||||
m_GhostPopulateStartTime = tw::time_get();
|
||||
Storage()->ListDirectory(IStorage::TYPE_ALL, m_pClient->m_Ghost.GetGhostDir(), GhostlistFetchCallback, this);
|
||||
std::sort(m_lGhosts.begin(), m_lGhosts.end());
|
||||
|
||||
for(int i = 0; i < m_lGhosts.size(); i++)
|
||||
{
|
||||
if(str_comp(m_lGhosts[i].m_aPlayer, Client()->PlayerName()) == 0 && (!pOwnGhost || m_lGhosts[i] < *pOwnGhost))
|
||||
pOwnGhost = &m_lGhosts[i];
|
||||
}
|
||||
CGhostItem *pOwnGhost = 0;
|
||||
for(auto &Ghost : m_lGhosts)
|
||||
if(str_comp(Ghost.m_aPlayer, Client()->PlayerName()) == 0 && (!pOwnGhost || Ghost < *pOwnGhost))
|
||||
pOwnGhost = &Ghost;
|
||||
|
||||
if(pOwnGhost)
|
||||
{
|
||||
|
@ -950,16 +949,16 @@ void CMenus::GhostlistPopulate()
|
|||
|
||||
CMenus::CGhostItem *CMenus::GetOwnGhost()
|
||||
{
|
||||
for(int i = 0; i < m_lGhosts.size(); i++)
|
||||
if(m_lGhosts[i].m_Own)
|
||||
return &m_lGhosts[i];
|
||||
return 0;
|
||||
for(auto &Ghost : m_lGhosts)
|
||||
if(Ghost.m_Own)
|
||||
return &Ghost;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CMenus::UpdateOwnGhost(CGhostItem Item)
|
||||
{
|
||||
int Own = -1;
|
||||
for(int i = 0; i < m_lGhosts.size(); i++)
|
||||
for(size_t i = 0; i < m_lGhosts.size(); i++)
|
||||
if(m_lGhosts[i].m_Own)
|
||||
Own = i;
|
||||
|
||||
|
@ -972,14 +971,14 @@ void CMenus::UpdateOwnGhost(CGhostItem Item)
|
|||
}
|
||||
|
||||
Item.m_Own = true;
|
||||
m_lGhosts.add(Item);
|
||||
m_lGhosts.insert(std::lower_bound(m_lGhosts.begin(), m_lGhosts.end(), Item), 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);
|
||||
m_lGhosts.erase(m_lGhosts.begin() + Index);
|
||||
}
|
||||
|
||||
void CMenus::RenderGhost(CUIRect MainView)
|
||||
|
@ -1158,7 +1157,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
|||
GhostlistPopulate();
|
||||
}
|
||||
|
||||
if(s_SelectedIndex == -1 || s_SelectedIndex >= m_lGhosts.size())
|
||||
if(s_SelectedIndex == -1 || s_SelectedIndex >= (int)m_lGhosts.size())
|
||||
return;
|
||||
|
||||
CGhostItem *pGhost = &m_lGhosts[s_SelectedIndex];
|
||||
|
|
|
@ -408,13 +408,13 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
|
|||
int OldSelected = -1;
|
||||
UiDoListboxStart(&s_ScrollValue, &MainView, 50.0f, Localize("Country / Region"), "", m_pClient->m_CountryFlags.Num(), 6, OldSelected, s_ScrollValue);
|
||||
|
||||
for(int i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
||||
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
||||
{
|
||||
const CCountryFlags::CCountryFlag *pEntry = m_pClient->m_CountryFlags.GetByIndex(i);
|
||||
if(pEntry->m_CountryCode == *pCountry)
|
||||
OldSelected = i;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i, s_ListBoxUsed);
|
||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i, s_ListBoxUsed);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
Item.m_Rect.Margin(5.0f, &Item.m_Rect);
|
||||
|
@ -673,12 +673,12 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
// skin selector
|
||||
MainView.HSplitTop(20.0f, 0, &MainView);
|
||||
MainView.HSplitTop(230.0f - RenderEyesBelow * 25.0f, &SkinList, &MainView);
|
||||
static sorted_array<CUISkin> s_paSkinList;
|
||||
static std::vector<CUISkin> s_vSkinList;
|
||||
static int s_SkinCount = 0;
|
||||
static float s_ScrollValue = 0.0f;
|
||||
if(s_InitSkinlist || m_pClient->m_Skins.Num() != s_SkinCount)
|
||||
{
|
||||
s_paSkinList.clear();
|
||||
s_vSkinList.clear();
|
||||
for(int i = 0; i < m_pClient->m_Skins.Num(); ++i)
|
||||
{
|
||||
const CSkin *s = m_pClient->m_Skins.Get(i);
|
||||
|
@ -698,22 +698,23 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
if(s == 0)
|
||||
continue;
|
||||
|
||||
s_paSkinList.add(CUISkin(s));
|
||||
s_vSkinList.emplace_back(s);
|
||||
}
|
||||
std::sort(s_vSkinList.begin(), s_vSkinList.end());
|
||||
s_InitSkinlist = false;
|
||||
s_SkinCount = m_pClient->m_Skins.Num();
|
||||
}
|
||||
|
||||
int OldSelected = -1;
|
||||
UiDoListboxStart(&s_InitSkinlist, &SkinList, 50.0f, Localize("Skins"), "", s_paSkinList.size(), 4, OldSelected, s_ScrollValue);
|
||||
for(int i = 0; i < s_paSkinList.size(); ++i)
|
||||
UiDoListboxStart(&s_InitSkinlist, &SkinList, 50.0f, Localize("Skins"), "", s_vSkinList.size(), 4, OldSelected, s_ScrollValue);
|
||||
for(size_t i = 0; i < s_vSkinList.size(); ++i)
|
||||
{
|
||||
const CSkin *s = s_paSkinList[i].m_pSkin;
|
||||
const CSkin *s = s_vSkinList[i].m_pSkin;
|
||||
|
||||
if(str_comp(s->m_aName, pSkinName) == 0)
|
||||
OldSelected = i;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(s_paSkinList[i].m_pSkin, OldSelected == i);
|
||||
CListboxItem Item = UiDoListboxNextItem(s, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
CTeeRenderInfo Info = OwnSkinInfo;
|
||||
|
@ -728,10 +729,9 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
RenderTools()->RenderTee(pIdleState, &Info, Emote, vec2(1.0f, 0.0f), TeeRenderPos);
|
||||
|
||||
Item.m_Rect.VSplitLeft(60.0f, 0, &Item.m_Rect);
|
||||
str_format(aBuf, sizeof(aBuf), "%s", s->m_aName);
|
||||
SLabelProperties Props;
|
||||
Props.m_MaxWidth = Item.m_Rect.w;
|
||||
UI()->DoLabelScaled(&Item.m_Rect, aBuf, 12.0f, TEXTALIGN_LEFT, Props);
|
||||
UI()->DoLabelScaled(&Item.m_Rect, s->m_aName, 12.0f, TEXTALIGN_LEFT, Props);
|
||||
if(g_Config.m_Debug)
|
||||
{
|
||||
ColorRGBA BloodColor = *UseCustomColor ? color_cast<ColorRGBA>(ColorHSLA(*ColorBody)) : s->m_BloodColor;
|
||||
|
@ -748,7 +748,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
||||
if(OldSelected != NewSelected)
|
||||
{
|
||||
mem_copy(pSkinName, s_paSkinList[NewSelected].m_pSkin->m_aName, sizeof(g_Config.m_ClPlayerSkin));
|
||||
mem_copy(pSkinName, s_vSkinList[NewSelected].m_pSkin->m_aName, sizeof(g_Config.m_ClPlayerSkin));
|
||||
SetNeedSendInfo();
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1704,7 @@ public:
|
|||
bool operator<(const CLanguage &Other) const { return m_Name < Other.m_Name; }
|
||||
};
|
||||
|
||||
void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<CLanguage> *pLanguages)
|
||||
void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, std::vector<CLanguage> &Languages)
|
||||
{
|
||||
IOHANDLE File = pStorage->OpenFile("languages/index.txt", IOFLAG_READ | IOFLAG_SKIP_BOM, IStorage::TYPE_ALL);
|
||||
if(!File)
|
||||
|
@ -1759,7 +1759,7 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<
|
|||
|
||||
char aFileName[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFileName, sizeof(aFileName), "languages/%s.txt", aOrigin);
|
||||
pLanguages->add(CLanguage(aReplacement, aFileName, str_toint(pLine + 3)));
|
||||
Languages.emplace_back(aReplacement, aFileName, str_toint(pLine + 3));
|
||||
}
|
||||
io_close(File);
|
||||
}
|
||||
|
@ -1768,14 +1768,15 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
|
|||
{
|
||||
static int s_LanguageList = 0;
|
||||
static int s_SelectedLanguage = 0;
|
||||
static sorted_array<CLanguage> s_Languages;
|
||||
static std::vector<CLanguage> s_Languages;
|
||||
static float s_ScrollValue = 0;
|
||||
|
||||
if(s_Languages.size() == 0)
|
||||
if(s_Languages.empty())
|
||||
{
|
||||
s_Languages.add(CLanguage("English", "", 826));
|
||||
LoadLanguageIndexfile(Storage(), Console(), &s_Languages);
|
||||
for(int i = 0; i < s_Languages.size(); i++)
|
||||
s_Languages.emplace_back("English", "", 826);
|
||||
LoadLanguageIndexfile(Storage(), Console(), s_Languages);
|
||||
std::sort(s_Languages.begin(), s_Languages.end());
|
||||
for(size_t i = 0; i < s_Languages.size(); i++)
|
||||
if(str_comp(s_Languages[i].m_FileName.c_str(), g_Config.m_ClLanguagefile) == 0)
|
||||
{
|
||||
s_SelectedLanguage = i;
|
||||
|
@ -1787,10 +1788,9 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
|
|||
|
||||
UiDoListboxStart(&s_LanguageList, &MainView, 24.0f, Localize("Language"), "", s_Languages.size(), 1, s_SelectedLanguage, s_ScrollValue);
|
||||
|
||||
for(sorted_array<CLanguage>::range r = s_Languages.all(); !r.empty(); r.pop_front())
|
||||
for(auto &Language : s_Languages)
|
||||
{
|
||||
CListboxItem Item = UiDoListboxNextItem(&r.front());
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(&Language.m_Name);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
CUIRect Rect;
|
||||
|
@ -1798,9 +1798,9 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
|
|||
Rect.VMargin(6.0f, &Rect);
|
||||
Rect.HMargin(3.0f, &Rect);
|
||||
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
m_pClient->m_CountryFlags.Render(r.front().m_CountryCode, &Color, Rect.x, Rect.y, Rect.w, Rect.h);
|
||||
m_pClient->m_CountryFlags.Render(Language.m_CountryCode, &Color, Rect.x, Rect.y, Rect.w, Rect.h);
|
||||
Item.m_Rect.HSplitTop(2.0f, 0, &Item.m_Rect);
|
||||
UI()->DoLabelScaled(&Item.m_Rect, r.front().m_Name.c_str(), 16.0f, TEXTALIGN_LEFT);
|
||||
UI()->DoLabelScaled(&Item.m_Rect, Language.m_Name.c_str(), 16.0f, TEXTALIGN_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ int CMenus::EntitiesScan(const char *pName, int IsDir, int DirType, void *pUser)
|
|||
SCustomEntities EntitiesItem;
|
||||
str_copy(EntitiesItem.m_aName, pName, sizeof(EntitiesItem.m_aName));
|
||||
CMenus::LoadEntities(&EntitiesItem, pUser);
|
||||
pThis->m_EntitiesList.add(EntitiesItem);
|
||||
pThis->m_EntitiesList.push_back(EntitiesItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ int CMenus::EntitiesScan(const char *pName, int IsDir, int DirType, void *pUser)
|
|||
SCustomEntities EntitiesItem;
|
||||
str_copy(EntitiesItem.m_aName, aName, sizeof(EntitiesItem.m_aName));
|
||||
CMenus::LoadEntities(&EntitiesItem, pUser);
|
||||
pThis->m_EntitiesList.add(EntitiesItem);
|
||||
pThis->m_EntitiesList.push_back(EntitiesItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ static void LoadAsset(TName *pAssetItem, const char *pAssetName, IGraphics *pGra
|
|||
}
|
||||
|
||||
template<typename TName>
|
||||
static int AssetScan(const char *pName, int IsDir, int DirType, sorted_array<TName> &AssetList, const char *pAssetName, IGraphics *pGraphics, void *pUser)
|
||||
static int AssetScan(const char *pName, int IsDir, int DirType, std::vector<TName> &AssetList, const char *pAssetName, IGraphics *pGraphics, void *pUser)
|
||||
{
|
||||
auto *pRealUser = (SMenuAssetScanUser *)pUser;
|
||||
if(IsDir)
|
||||
|
@ -177,7 +177,7 @@ static int AssetScan(const char *pName, int IsDir, int DirType, sorted_array<TNa
|
|||
TName AssetItem;
|
||||
str_copy(AssetItem.m_aName, pName, sizeof(AssetItem.m_aName));
|
||||
LoadAsset(&AssetItem, pAssetName, pGraphics, pUser);
|
||||
AssetList.add(AssetItem);
|
||||
AssetList.push_back(AssetItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -192,7 +192,7 @@ static int AssetScan(const char *pName, int IsDir, int DirType, sorted_array<TNa
|
|||
TName AssetItem;
|
||||
str_copy(AssetItem.m_aName, aName, sizeof(AssetItem.m_aName));
|
||||
LoadAsset(&AssetItem, pAssetName, pGraphics, pUser);
|
||||
AssetList.add(AssetItem);
|
||||
AssetList.push_back(AssetItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,18 +233,18 @@ int CMenus::HudScan(const char *pName, int IsDir, int DirType, void *pUser)
|
|||
return AssetScan(pName, IsDir, DirType, pThis->m_HudList, "hud", pGraphics, pUser);
|
||||
}
|
||||
|
||||
static sorted_array<const CMenus::SCustomEntities *> s_SearchEntitiesList;
|
||||
static sorted_array<const CMenus::SCustomGame *> s_SearchGamesList;
|
||||
static sorted_array<const CMenus::SCustomEmoticon *> s_SearchEmoticonsList;
|
||||
static sorted_array<const CMenus::SCustomParticle *> s_SearchParticlesList;
|
||||
static sorted_array<const CMenus::SCustomHud *> s_SearchHudList;
|
||||
static std::vector<const CMenus::SCustomEntities *> s_SearchEntitiesList;
|
||||
static std::vector<const CMenus::SCustomGame *> s_SearchGamesList;
|
||||
static std::vector<const CMenus::SCustomEmoticon *> s_SearchEmoticonsList;
|
||||
static std::vector<const CMenus::SCustomParticle *> s_SearchParticlesList;
|
||||
static std::vector<const CMenus::SCustomHud *> s_SearchHudList;
|
||||
|
||||
static const int NumberOfAssetsTabs = 5;
|
||||
static bool s_InitCustomList[NumberOfAssetsTabs] = {
|
||||
true,
|
||||
};
|
||||
|
||||
static int s_CustomListSize[NumberOfAssetsTabs] = {
|
||||
static size_t s_CustomListSize[NumberOfAssetsTabs] = {
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -252,7 +252,7 @@ static char s_aFilterString[NumberOfAssetsTabs][50];
|
|||
|
||||
static int s_CurCustomTab = ASSETS_TAB_ENTITIES;
|
||||
|
||||
static const CMenus::SCustomItem *GetCustomItem(int CurTab, int Index)
|
||||
static const CMenus::SCustomItem *GetCustomItem(int CurTab, size_t Index)
|
||||
{
|
||||
if(CurTab == ASSETS_TAB_ENTITIES)
|
||||
return s_SearchEntitiesList[Index];
|
||||
|
@ -269,9 +269,9 @@ static const CMenus::SCustomItem *GetCustomItem(int CurTab, int Index)
|
|||
}
|
||||
|
||||
template<typename TName>
|
||||
void ClearAssetList(sorted_array<TName> &List, IGraphics *pGraphics)
|
||||
void ClearAssetList(std::vector<TName> &List, IGraphics *pGraphics)
|
||||
{
|
||||
for(int i = 0; i < List.size(); ++i)
|
||||
for(size_t i = 0; i < List.size(); ++i)
|
||||
{
|
||||
if(List[i].m_RenderTexture.IsValid())
|
||||
pGraphics->UnloadTexture(&(List[i].m_RenderTexture));
|
||||
|
@ -284,9 +284,9 @@ void CMenus::ClearCustomItems(int CurTab)
|
|||
{
|
||||
if(CurTab == ASSETS_TAB_ENTITIES)
|
||||
{
|
||||
for(int i = 0; i < m_EntitiesList.size(); ++i)
|
||||
for(auto &Entity : m_EntitiesList)
|
||||
{
|
||||
for(auto &Image : m_EntitiesList[i].m_aImages)
|
||||
for(auto &Image : Entity.m_aImages)
|
||||
{
|
||||
if(Image.m_Texture.IsValid())
|
||||
Graphics()->UnloadTexture(&Image.m_Texture);
|
||||
|
@ -330,24 +330,25 @@ void CMenus::ClearCustomItems(int CurTab)
|
|||
}
|
||||
|
||||
template<typename TName, typename TCaller>
|
||||
void InitAssetList(sorted_array<TName> &AssetList, const char *pAssetPath, const char *pAssetName, FS_LISTDIR_CALLBACK pfnCallback, IGraphics *pGraphics, IStorage *pStorage, TCaller Caller)
|
||||
void InitAssetList(std::vector<TName> &AssetList, const char *pAssetPath, const char *pAssetName, FS_LISTDIR_CALLBACK pfnCallback, IGraphics *pGraphics, IStorage *pStorage, TCaller Caller)
|
||||
{
|
||||
if(AssetList.size() == 0)
|
||||
if(AssetList.empty())
|
||||
{
|
||||
TName AssetItem;
|
||||
str_copy(AssetItem.m_aName, "default", sizeof(AssetItem.m_aName));
|
||||
LoadAsset(&AssetItem, pAssetName, pGraphics, Caller);
|
||||
AssetList.add(AssetItem);
|
||||
AssetList.push_back(AssetItem);
|
||||
|
||||
// load assets
|
||||
pStorage->ListDirectory(IStorage::TYPE_ALL, pAssetPath, pfnCallback, Caller);
|
||||
std::sort(AssetList.begin(), AssetList.end());
|
||||
}
|
||||
if(AssetList.size() != s_CustomListSize[s_CurCustomTab])
|
||||
s_InitCustomList[s_CurCustomTab] = true;
|
||||
}
|
||||
|
||||
template<typename TName>
|
||||
int InitSearchList(sorted_array<const TName *> &SearchList, sorted_array<TName> &AssetList)
|
||||
int InitSearchList(std::vector<const TName *> &SearchList, std::vector<TName> &AssetList)
|
||||
{
|
||||
SearchList.clear();
|
||||
int ListSize = AssetList.size();
|
||||
|
@ -359,7 +360,7 @@ int InitSearchList(sorted_array<const TName *> &SearchList, sorted_array<TName>
|
|||
if(s_aFilterString[s_CurCustomTab][0] != '\0' && !str_utf8_find_nocase(s->m_aName, s_aFilterString[s_CurCustomTab]))
|
||||
continue;
|
||||
|
||||
SearchList.add_unsorted(s);
|
||||
SearchList.push_back(s);
|
||||
}
|
||||
return AssetList.size();
|
||||
}
|
||||
|
@ -397,15 +398,16 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
};
|
||||
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
|
||||
{
|
||||
if(m_EntitiesList.size() == 0)
|
||||
if(m_EntitiesList.empty())
|
||||
{
|
||||
SCustomEntities EntitiesItem;
|
||||
str_copy(EntitiesItem.m_aName, "default", sizeof(EntitiesItem.m_aName));
|
||||
LoadEntities(&EntitiesItem, &User);
|
||||
m_EntitiesList.add(EntitiesItem);
|
||||
m_EntitiesList.push_back(EntitiesItem);
|
||||
|
||||
// load entities
|
||||
Storage()->ListDirectory(IStorage::TYPE_ALL, "assets/entities", EntitiesScan, &User);
|
||||
std::sort(m_EntitiesList.begin(), m_EntitiesList.end());
|
||||
}
|
||||
if(m_EntitiesList.size() != s_CustomListSize[s_CurCustomTab])
|
||||
s_InitCustomList[s_CurCustomTab] = true;
|
||||
|
@ -447,7 +449,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
if(s_aFilterString[s_CurCustomTab][0] != '\0' && !str_utf8_find_nocase(s->m_aName, s_aFilterString[s_CurCustomTab]))
|
||||
continue;
|
||||
|
||||
s_SearchEntitiesList.add_unsorted(s);
|
||||
s_SearchEntitiesList.push_back(s);
|
||||
}
|
||||
}
|
||||
else if(s_CurCustomTab == ASSETS_TAB_GAME)
|
||||
|
@ -475,7 +477,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
float TextureWidth = 150;
|
||||
float TextureHeight = 150;
|
||||
|
||||
int SearchListSize = 0;
|
||||
size_t SearchListSize = 0;
|
||||
|
||||
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
|
||||
{
|
||||
|
@ -501,7 +503,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
}
|
||||
|
||||
UiDoListboxStart(&s_InitCustomList[s_CurCustomTab], &CustomList, TextureHeight + 15.0f + 10.0f + Margin, "", "", SearchListSize, CustomList.w / (Margin + TextureWidth), OldSelected, s_ScrollValue, true);
|
||||
for(int i = 0; i < SearchListSize; ++i)
|
||||
for(size_t i = 0; i < SearchListSize; ++i)
|
||||
{
|
||||
const SCustomItem *s = GetCustomItem(s_CurCustomTab, i);
|
||||
if(s == NULL)
|
||||
|
@ -533,7 +535,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
OldSelected = i;
|
||||
}
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(s, OldSelected == i);
|
||||
CListboxItem Item = UiDoListboxNextItem(s, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
CUIRect ItemRect = Item.m_Rect;
|
||||
ItemRect.Margin(Margin / 2, &ItemRect);
|
||||
if(Item.m_Visible)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <engine/demo.h>
|
||||
#include <engine/engine.h>
|
||||
#include <engine/graphics.h>
|
||||
|
|
|
@ -295,7 +295,7 @@ int CSkins::LoadSkin(const char *pName, CImageInfo &Info)
|
|||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
||||
}
|
||||
|
||||
m_aSkins.add(Skin);
|
||||
m_aSkins.insert(std::lower_bound(m_aSkins.begin(), m_aSkins.end(), Skin), Skin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -324,24 +324,24 @@ void CSkins::OnInit()
|
|||
|
||||
void CSkins::Refresh(TSkinLoadedCBFunc &&SkinLoadedFunc)
|
||||
{
|
||||
for(int i = 0; i < m_aSkins.size(); ++i)
|
||||
for(auto &Skin : m_aSkins)
|
||||
{
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_OriginalSkin.m_Body);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_OriginalSkin.m_BodyOutline);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_OriginalSkin.m_Feet);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_OriginalSkin.m_FeetOutline);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_OriginalSkin.m_Hands);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_OriginalSkin.m_HandsOutline);
|
||||
for(auto &Eye : m_aSkins[i].m_OriginalSkin.m_Eyes)
|
||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_Body);
|
||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_BodyOutline);
|
||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_Feet);
|
||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_FeetOutline);
|
||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_Hands);
|
||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_HandsOutline);
|
||||
for(auto &Eye : Skin.m_OriginalSkin.m_Eyes)
|
||||
Graphics()->UnloadTexture(&Eye);
|
||||
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_ColorableSkin.m_Body);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_ColorableSkin.m_BodyOutline);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_ColorableSkin.m_Feet);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_ColorableSkin.m_FeetOutline);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_ColorableSkin.m_Hands);
|
||||
Graphics()->UnloadTexture(&m_aSkins[i].m_ColorableSkin.m_HandsOutline);
|
||||
for(auto &Eye : m_aSkins[i].m_ColorableSkin.m_Eyes)
|
||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_Body);
|
||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_BodyOutline);
|
||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_Feet);
|
||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_FeetOutline);
|
||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_Hands);
|
||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_HandsOutline);
|
||||
for(auto &Eye : Skin.m_ColorableSkin.m_Eyes)
|
||||
Graphics()->UnloadTexture(&Eye);
|
||||
}
|
||||
|
||||
|
@ -351,14 +351,14 @@ void CSkins::Refresh(TSkinLoadedCBFunc &&SkinLoadedFunc)
|
|||
SkinScanUser.m_pThis = this;
|
||||
SkinScanUser.m_SkinLoadedFunc = SkinLoadedFunc;
|
||||
Storage()->ListDirectory(IStorage::TYPE_ALL, "skins", SkinScan, &SkinScanUser);
|
||||
if(!m_aSkins.size())
|
||||
if(m_aSkins.empty())
|
||||
{
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load skins. folder='skins/'");
|
||||
CSkin DummySkin;
|
||||
DummySkin.m_IsVanilla = true;
|
||||
str_copy(DummySkin.m_aName, "dummy", sizeof(DummySkin.m_aName));
|
||||
DummySkin.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f);
|
||||
m_aSkins.add(DummySkin);
|
||||
m_aSkins.push_back(DummySkin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,9 +402,12 @@ int CSkins::Find(const char *pName)
|
|||
|
||||
int CSkins::FindImpl(const char *pName)
|
||||
{
|
||||
auto r = ::find_binary(m_aSkins.all(), pName);
|
||||
if(!r.empty())
|
||||
return &r.front() - m_aSkins.base_ptr();
|
||||
CSkin Needle;
|
||||
mem_zero(&Needle, sizeof(Needle));
|
||||
str_copy(Needle.m_aName, pName, sizeof(Needle.m_aName));
|
||||
auto Range = std::equal_range(m_aSkins.begin(), m_aSkins.end(), Needle);
|
||||
if(std::distance(Range.first, Range.second) == 1)
|
||||
return Range.first - m_aSkins.begin();
|
||||
|
||||
if(str_comp(pName, "default") == 0)
|
||||
return -1;
|
||||
|
@ -415,20 +418,23 @@ int CSkins::FindImpl(const char *pName)
|
|||
if(str_find(pName, "/") != 0)
|
||||
return -1;
|
||||
|
||||
auto d = ::find_binary(m_aDownloadSkins.all(), pName);
|
||||
if(!d.empty())
|
||||
CDownloadSkin DownloadNeedle;
|
||||
mem_zero(&DownloadNeedle, sizeof(DownloadNeedle));
|
||||
str_copy(DownloadNeedle.m_aName, pName, sizeof(DownloadNeedle.m_aName));
|
||||
const auto &[RangeBegin, RangeEnd] = std::equal_range(m_aDownloadSkins.begin(), m_aDownloadSkins.end(), DownloadNeedle);
|
||||
if(std::distance(RangeBegin, RangeEnd) == 1)
|
||||
{
|
||||
if(d.front().m_pTask && d.front().m_pTask->State() == HTTP_DONE)
|
||||
if(RangeBegin->m_pTask && RangeBegin->m_pTask->State() == HTTP_DONE)
|
||||
{
|
||||
char aPath[IO_MAX_PATH_LENGTH];
|
||||
str_format(aPath, sizeof(aPath), "downloadedskins/%s.png", d.front().m_aName);
|
||||
Storage()->RenameFile(d.front().m_aPath, aPath, IStorage::TYPE_SAVE);
|
||||
LoadSkin(d.front().m_aName, d.front().m_pTask->m_Info);
|
||||
d.front().m_pTask = nullptr;
|
||||
str_format(aPath, sizeof(aPath), "downloadedskins/%s.png", RangeBegin->m_aName);
|
||||
Storage()->RenameFile(RangeBegin->m_aPath, aPath, IStorage::TYPE_SAVE);
|
||||
LoadSkin(RangeBegin->m_aName, RangeBegin->m_pTask->m_Info);
|
||||
RangeBegin->m_pTask = nullptr;
|
||||
}
|
||||
if(d.front().m_pTask && (d.front().m_pTask->State() == HTTP_ERROR || d.front().m_pTask->State() == HTTP_ABORTED))
|
||||
if(RangeBegin->m_pTask && (RangeBegin->m_pTask->State() == HTTP_ERROR || RangeBegin->m_pTask->State() == HTTP_ABORTED))
|
||||
{
|
||||
d.front().m_pTask = nullptr;
|
||||
RangeBegin->m_pTask = nullptr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -444,6 +450,6 @@ int CSkins::FindImpl(const char *pName)
|
|||
str_format(Skin.m_aPath, sizeof(Skin.m_aPath), "downloadedskins/%s", IStorage::FormatTmpPath(aBuf, sizeof(aBuf), pName));
|
||||
Skin.m_pTask = std::make_shared<CGetPngFile>(this, aUrl, Storage(), Skin.m_aPath);
|
||||
m_pClient->Engine()->AddJob(Skin.m_pTask);
|
||||
m_aDownloadSkins.add(Skin);
|
||||
m_aDownloadSkins.insert(std::lower_bound(m_aDownloadSkins.begin(), m_aDownloadSkins.end(), Skin), Skin);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
#ifndef GAME_CLIENT_COMPONENTS_SKINS_H
|
||||
#define GAME_CLIENT_COMPONENTS_SKINS_H
|
||||
#include <base/color.h>
|
||||
#include <base/tl/sorted_array.h>
|
||||
#include <base/vmath.h>
|
||||
#include <engine/shared/http.h>
|
||||
#include <game/client/component.h>
|
||||
#include <game/client/skin.h>
|
||||
#include <vector>
|
||||
|
||||
class CSkins : public CComponent
|
||||
{
|
||||
|
@ -46,8 +46,8 @@ public:
|
|||
int Find(const char *pName);
|
||||
|
||||
private:
|
||||
sorted_array<CSkin> m_aSkins;
|
||||
sorted_array<CDownloadSkin> m_aDownloadSkins;
|
||||
std::vector<CSkin> m_aSkins;
|
||||
std::vector<CDownloadSkin> m_aDownloadSkins;
|
||||
char m_EventSkinPrefix[24];
|
||||
|
||||
bool LoadSkinPNG(CImageInfo &Info, const char *pName, const char *pPath, int DirType);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include <base/tl/array.h>
|
||||
|
||||
#include "sounds.h"
|
||||
#include <engine/engine.h>
|
||||
#include <engine/shared/config.h>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
#ifndef GAME_CLIENT_SKIN_H
|
||||
#define GAME_CLIENT_SKIN_H
|
||||
#include <base/color.h>
|
||||
#include <base/tl/sorted_array.h>
|
||||
#include <base/vmath.h>
|
||||
#include <engine/graphics.h>
|
||||
#include <limits>
|
||||
|
@ -132,9 +130,7 @@ struct CSkin
|
|||
SSkinMetrics m_Metrics;
|
||||
|
||||
bool operator<(const CSkin &Other) const { return str_comp(m_aName, Other.m_aName) < 0; }
|
||||
|
||||
bool operator<(const char *pOther) const { return str_comp(m_aName, pOther) < 0; }
|
||||
bool operator==(const char *pOther) const { return !str_comp(m_aName, pOther); }
|
||||
bool operator==(const CSkin &Other) const { return !str_comp(m_aName, Other.m_aName); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4331,7 +4331,7 @@ static int EditorListdirCallback(const char *pName, int IsDir, int StorageType,
|
|||
Item.m_IsDir = IsDir != 0;
|
||||
Item.m_IsLink = false;
|
||||
Item.m_StorageType = StorageType;
|
||||
pEditor->m_FileList.add(Item);
|
||||
pEditor->m_FileList.push_back(Item);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4462,7 +4462,7 @@ void CEditor::RenderFileDialog()
|
|||
m_FileDialogScrollValue = UIEx()->DoScrollbarV(&m_FileDialogScrollValue, &Scroll, m_FileDialogScrollValue);
|
||||
|
||||
int ScrollNum = 0;
|
||||
for(int i = 0; i < m_FileList.size(); i++)
|
||||
for(size_t i = 0; i < m_FileList.size(); i++)
|
||||
{
|
||||
m_FileList[i].m_IsVisible = false;
|
||||
if(!m_aFileDialogSearchText[0] || str_utf8_find_nocase(m_FileList[i].m_aName, m_aFileDialogSearchText))
|
||||
|
@ -4498,7 +4498,7 @@ void CEditor::RenderFileDialog()
|
|||
{
|
||||
if(Input()->GetEvent(i).m_Key == KEY_DOWN)
|
||||
{
|
||||
for(NewIndex = m_FilesSelectedIndex + 1; NewIndex < m_FileList.size(); NewIndex++)
|
||||
for(NewIndex = m_FilesSelectedIndex + 1; NewIndex < (int)m_FileList.size(); NewIndex++)
|
||||
{
|
||||
if(m_FileList[NewIndex].m_IsVisible)
|
||||
break;
|
||||
|
@ -4513,7 +4513,7 @@ void CEditor::RenderFileDialog()
|
|||
}
|
||||
}
|
||||
}
|
||||
if(NewIndex > -1 && NewIndex < m_FileList.size())
|
||||
if(NewIndex > -1 && NewIndex < (int)m_FileList.size())
|
||||
{
|
||||
//scroll
|
||||
float IndexY = View.y - m_FileDialogScrollValue * ScrollNum * 17.0f + NewIndex * 17.0f;
|
||||
|
@ -4710,10 +4710,11 @@ void CEditor::FilelistPopulate(int StorageType)
|
|||
Item.m_IsDir = true;
|
||||
Item.m_IsLink = true;
|
||||
Item.m_StorageType = IStorage::TYPE_SAVE;
|
||||
m_FileList.add(Item);
|
||||
m_FileList.push_back(Item);
|
||||
}
|
||||
Storage()->ListDirectory(StorageType, m_pFileDialogPath, EditorListdirCallback, this);
|
||||
m_FilesSelectedIndex = m_FileList.size() ? 0 : -1;
|
||||
std::sort(m_FileList.begin(), m_FileList.end());
|
||||
m_FilesSelectedIndex = m_FileList.empty() ? -1 : 0;
|
||||
m_PreviewImageIsLoaded = false;
|
||||
m_FileDialogActivate = false;
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <base/tl/algorithm.h>
|
||||
#include <base/tl/array.h>
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <game/client/render.h>
|
||||
#include <game/client/ui.h>
|
||||
|
@ -884,7 +883,7 @@ public:
|
|||
|
||||
bool operator<(const CFilelistItem &Other) const { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : str_comp_nocase(m_aFilename, Other.m_aFilename) < 0; }
|
||||
};
|
||||
sorted_array<CFilelistItem> m_FileList;
|
||||
std::vector<CFilelistItem> m_FileList;
|
||||
int m_FilesStartAt;
|
||||
int m_FilesCur;
|
||||
int m_FilesStopAt;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include <base/tl/array.h>
|
||||
|
||||
#include "editor.h"
|
||||
#include <engine/client.h>
|
||||
#include <engine/console.h>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include "localization.h"
|
||||
#include <base/tl/algorithm.h>
|
||||
|
||||
#include <engine/console.h>
|
||||
#include <engine/shared/linereader.h>
|
||||
|
@ -38,11 +37,7 @@ CLocalizationDatabase::CLocalizationDatabase()
|
|||
|
||||
void CLocalizationDatabase::AddString(const char *pOrgStr, const char *pNewStr, const char *pContext)
|
||||
{
|
||||
CString s;
|
||||
s.m_Hash = str_quickhash(pOrgStr);
|
||||
s.m_ContextHash = str_quickhash(pContext);
|
||||
s.m_pReplacement = m_StringsHeap.StoreString(*pNewStr ? pNewStr : pOrgStr);
|
||||
m_Strings.add(s);
|
||||
m_Strings.emplace_back(str_quickhash(pOrgStr), str_quickhash(pContext), m_StringsHeap.StoreString(*pNewStr ? pNewStr : pOrgStr));
|
||||
}
|
||||
|
||||
bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, IConsole *pConsole)
|
||||
|
@ -118,6 +113,7 @@ bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, ICon
|
|||
AddString(aOrigin, pReplacement, aContext);
|
||||
}
|
||||
io_close(IoHandle);
|
||||
std::sort(m_Strings.begin(), m_Strings.end());
|
||||
|
||||
m_CurrentVersion = ++m_VersionCounter;
|
||||
return true;
|
||||
|
@ -129,22 +125,21 @@ const char *CLocalizationDatabase::FindString(unsigned Hash, unsigned ContextHas
|
|||
String.m_Hash = Hash;
|
||||
String.m_ContextHash = ContextHash;
|
||||
String.m_pReplacement = 0x0;
|
||||
sorted_array<CString>::range r = ::find_binary(m_Strings.all(), String);
|
||||
if(r.empty())
|
||||
return 0;
|
||||
auto Range1 = std::equal_range(m_Strings.begin(), m_Strings.end(), String);
|
||||
if(std::distance(Range1.first, Range1.second) == 1)
|
||||
return Range1.first->m_pReplacement;
|
||||
|
||||
unsigned DefaultHash = str_quickhash("");
|
||||
unsigned DefaultIndex = 0;
|
||||
for(unsigned i = 0; i < r.size() && r.index(i).m_Hash == Hash; ++i)
|
||||
const unsigned DefaultHash = str_quickhash("");
|
||||
if(ContextHash != DefaultHash)
|
||||
{
|
||||
const CString &rStr = r.index(i);
|
||||
if(rStr.m_ContextHash == ContextHash)
|
||||
return rStr.m_pReplacement;
|
||||
else if(rStr.m_ContextHash == DefaultHash)
|
||||
DefaultIndex = i;
|
||||
// Do another lookup with the default context hash
|
||||
String.m_ContextHash = DefaultHash;
|
||||
auto Range2 = std::equal_range(m_Strings.begin(), m_Strings.end(), String);
|
||||
if(std::distance(Range2.first, Range2.second) == 1)
|
||||
return Range2.first->m_pReplacement;
|
||||
}
|
||||
|
||||
return r.index(DefaultIndex).m_pReplacement;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CLocalizationDatabase g_Localization;
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#ifndef GAME_LOCALIZATION_H
|
||||
#define GAME_LOCALIZATION_H
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <base/system.h> // GNUC_ATTRIBUTE
|
||||
#include <engine/shared/memheap.h>
|
||||
#include <vector>
|
||||
|
||||
class CLocalizationDatabase
|
||||
{
|
||||
|
@ -15,12 +16,18 @@ class CLocalizationDatabase
|
|||
unsigned m_ContextHash;
|
||||
const char *m_pReplacement;
|
||||
|
||||
CString() {}
|
||||
CString(unsigned Hash, unsigned ContextHash, const char *pReplacement) :
|
||||
m_Hash(Hash), m_ContextHash(ContextHash), m_pReplacement(pReplacement)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const CString &Other) const { return m_Hash < Other.m_Hash || (m_Hash == Other.m_Hash && m_ContextHash < Other.m_ContextHash); }
|
||||
bool operator<=(const CString &Other) const { return m_Hash < Other.m_Hash || (m_Hash == Other.m_Hash && m_ContextHash <= Other.m_ContextHash); }
|
||||
bool operator==(const CString &Other) const { return m_Hash == Other.m_Hash && m_ContextHash == Other.m_ContextHash; }
|
||||
};
|
||||
|
||||
sorted_array<CString> m_Strings;
|
||||
std::vector<CString> m_Strings;
|
||||
CHeap m_StringsHeap;
|
||||
int m_VersionCounter;
|
||||
int m_CurrentVersion;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#include <base/tl/sorted_array.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "base/system.h"
|
||||
#include "gamecontext.h"
|
||||
|
@ -3080,18 +3080,19 @@ void CGameContext::ConAddMapVotes(IConsole::IResult *pResult, void *pUserData)
|
|||
{
|
||||
CGameContext *pSelf = (CGameContext *)pUserData;
|
||||
|
||||
sorted_array<CMapNameItem> MapList;
|
||||
std::vector<CMapNameItem> MapList;
|
||||
pSelf->Storage()->ListDirectory(IStorage::TYPE_ALL, "maps", MapScan, &MapList);
|
||||
std::sort(MapList.begin(), MapList.end());
|
||||
|
||||
for(int i = 0; i < MapList.size(); i++)
|
||||
for(auto &Item : MapList)
|
||||
{
|
||||
char aDescription[64];
|
||||
str_format(aDescription, sizeof(aDescription), "Map: %s", MapList[i].m_aName);
|
||||
str_format(aDescription, sizeof(aDescription), "Map: %s", Item.m_aName);
|
||||
|
||||
char aCommand[IO_MAX_PATH_LENGTH * 2 + 10];
|
||||
char aMapEscaped[IO_MAX_PATH_LENGTH * 2];
|
||||
char *pDst = aMapEscaped;
|
||||
str_escape(&pDst, MapList[i].m_aName, aMapEscaped + sizeof(aMapEscaped));
|
||||
str_escape(&pDst, Item.m_aName, aMapEscaped + sizeof(aMapEscaped));
|
||||
str_format(aCommand, sizeof(aCommand), "change_map \"%s\"", aMapEscaped);
|
||||
|
||||
pSelf->AddVote(aDescription, aCommand);
|
||||
|
@ -3102,15 +3103,12 @@ void CGameContext::ConAddMapVotes(IConsole::IResult *pResult, void *pUserData)
|
|||
|
||||
int CGameContext::MapScan(const char *pName, int IsDir, int DirType, void *pUserData)
|
||||
{
|
||||
sorted_array<CMapNameItem> *pMapList = (sorted_array<CMapNameItem> *)pUserData;
|
||||
|
||||
if(IsDir || !str_endswith(pName, ".map"))
|
||||
return 0;
|
||||
|
||||
CMapNameItem Item;
|
||||
int Length = str_length(pName);
|
||||
str_truncate(Item.m_aName, sizeof(Item.m_aName), pName, Length - 4);
|
||||
pMapList->add(Item);
|
||||
str_truncate(Item.m_aName, sizeof(Item.m_aName), pName, str_length(pName) - str_length(".map"));
|
||||
static_cast<std::vector<CMapNameItem> *>(pUserData)->push_back(Item);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <base/tl/sorted_array.h>
|
||||
|
||||
TEST(SortedArray, SortEmptyRange)
|
||||
{
|
||||
sorted_array<int> x;
|
||||
x.sort_range();
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#include <base/logger.h>
|
||||
#include <base/system.h>
|
||||
#include <base/tl/array.h>
|
||||
#include <engine/shared/datafile.h>
|
||||
#include <engine/storage.h>
|
||||
#include <game/mapitems.h>
|
||||
|
|
Loading…
Reference in a new issue