AStringVector cFile::GetFolderContents(const AString & a_Folder) { AStringVector AllFiles; #ifdef _WIN32 // If the folder name doesn't contain the terminating slash / backslash, add it: AString FileFilter = a_Folder; if ( !FileFilter.empty() && (FileFilter[FileFilter.length() - 1] != '\\') && (FileFilter[FileFilter.length() - 1] != '/') ) { FileFilter.push_back('\\'); } // Find all files / folders: FileFilter.append("*.*"); HANDLE hFind; WIN32_FIND_DATAA FindFileData; if ((hFind = FindFirstFileA(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) { do { AllFiles.push_back(FindFileData.cFileName); } while (FindNextFileA(hFind, &FindFileData)); FindClose(hFind); } #else // _WIN32 DIR * dp; AString Folder = a_Folder; if (Folder.empty()) { Folder = "."; } if ((dp = opendir(Folder.c_str())) == nullptr) { LOGERROR("Error (%i) opening directory \"%s\"\n", errno, Folder.c_str()); } else { struct dirent *dirp; while ((dirp = readdir(dp)) != nullptr) { AllFiles.push_back(dirp->d_name); } closedir(dp); } #endif // else _WIN32 return AllFiles; }
AStringVector cPluginManager::GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings) { // Check if the Plugins section exists. if (!a_Settings.KeyExists("Plugins")) { InsertDefaultPlugins(a_Settings); } // Get the list of plugins to load: AStringVector res; auto Values = a_Settings.GetValues("Plugins"); for (auto NameValue : Values) { AString ValueName = NameValue.first; if (ValueName.compare("Plugin") == 0) { AString PluginFile = NameValue.second; if (!PluginFile.empty()) { res.push_back(PluginFile); } } } // for i - ini values return res; }
AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames, bool a_UseOnlyCached) { // Convert all playernames to lowercase: AStringVector PlayerNames; for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { PlayerNames.push_back(StrToLower(*itr)); } // for itr - a_PlayerNames[] // Request the cache to populate any names not yet contained: if (!a_UseOnlyCached) { CacheNamesToUUIDs(PlayerNames); } // Retrieve from cache: size_t idx = 0; AStringVector res; res.resize(PlayerNames.size()); cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = PlayerNames.begin(), end = PlayerNames.end(); itr != end; ++itr, ++idx) { cProfileMap::const_iterator itrN = m_NameToUUID.find(*itr); if (itrN != m_NameToUUID.end()) { res[idx] = itrN->second.m_UUID; } } // for itr - PlayerNames[] return res; }
void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player) { for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) { if (NoCaseCompare(itr->first.substr(0, a_Text.length()), a_Text) != 0) { // Command name doesn't match continue; } if ((a_Player != NULL) && !a_Player->HasPermission(itr->second.m_Permission)) { // Player doesn't have permission for the command continue; } a_Results.push_back(itr->first); } }
void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { // Create a list of names to query, by removing those that are already cached: AStringVector NamesToQuery; NamesToQuery.reserve(a_PlayerNames.size()); { cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) { NamesToQuery.push_back(*itr); } } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) QueryNamesToUUIDs(NamesToQuery); }
void cPluginManager::RefreshPluginList(void) { // Get a list of currently available folders: AString PluginsPath = GetPluginsPath() + "/"; AStringVector Contents = cFile::GetFolderContents(PluginsPath.c_str()); AStringVector Folders; for (auto & item: Contents) { if ((item == ".") || (item == "..") || (!cFile::IsFolder(PluginsPath + item))) { // We only want folders, and don't want "." or ".." continue; } Folders.push_back(item); } // for item - Contents[] // Set all plugins with invalid folders as psNotFound: for (auto & plugin: m_Plugins) { if (std::find(Folders.cbegin(), Folders.cend(), plugin->GetFolderName()) == Folders.end()) { plugin->m_Status = psNotFound; } } // for plugin - m_Plugins[] // Add all newly discovered plugins: for (auto & folder: Folders) { bool hasFound = false; for (auto & plugin: m_Plugins) { if (plugin->GetFolderName() == folder) { hasFound = true; break; } } // for plugin - m_Plugins[] if (!hasFound) { m_Plugins.push_back(std::make_shared<cPluginLua>(folder)); } } // for folder - Folders[] }
void cMojangAPI::Update(void) { Int64 LimitDateTime = time(nullptr) - MAX_AGE; // Re-query all playernames that are stale: AStringVector PlayerNames; { cCSLock Lock(m_CSNameToUUID); for (const auto & NameToUUID : m_NameToUUID) { if (NameToUUID.second.m_DateTime < LimitDateTime) { PlayerNames.push_back(NameToUUID.first); } } // for itr - m_NameToUUID[] } if (!PlayerNames.empty()) { LOG("cMojangAPI: Updating name-to-uuid cache for %u names", static_cast<unsigned>(PlayerNames.size())); QueryNamesToUUIDs(PlayerNames); } // Re-query all profiles that are stale: std::vector<cUUID> ProfileUUIDs; { cCSLock Lock(m_CSUUIDToProfile); for (auto & UUIDToProfile : m_UUIDToProfile) { if (UUIDToProfile.second.m_DateTime < LimitDateTime) { ProfileUUIDs.push_back(UUIDToProfile.first); } } // for itr - m_UUIDToProfile[] } if (!ProfileUUIDs.empty()) { LOG("cMojangAPI: Updating uuid-to-profile cache for %u uuids", static_cast<unsigned>(ProfileUUIDs.size())); for (const auto & UUID : ProfileUUIDs) { QueryUUIDToProfile(UUID); } } }
AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached) { // Convert the playername to lowercase: AString lcPlayerName = StrToLower(a_PlayerName); // Request the cache to query the name if not yet cached: if (!a_UseOnlyCached) { AStringVector PlayerNames; PlayerNames.push_back(lcPlayerName); CacheNamesToUUIDs(PlayerNames); } // Retrieve from cache: cCSLock Lock(m_CSNameToUUID); cProfileMap::const_iterator itr = m_NameToUUID.find(lcPlayerName); if (itr == m_NameToUUID.end()) { // No UUID found return ""; } return itr->second.m_PlayerName; }
void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player) { for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) { if (NoCaseCompare(itr->first.substr(0, a_Text.length()), a_Text) != 0) { // Command name doesn't match continue; } if ((a_Player != nullptr) && !a_Player->HasPermission(itr->second.m_Permission)) { // Player doesn't have permission for the command continue; } /* Client expects to only get back the last part of a space separated command. Find the position of the beginning of the last part: Position of last space + 1 for space separated commands string::npos + 1 = 0 for commands that are not separated Then skip all commands that have too many subcommands. When the client asks for suggestions for "/time s" the server must skip all commands that consist of more than 2 words just as "/time set day". Or in other words, the position of the last space (separator) in the strings must be equal or string::npos for both. */ size_t LastSpaceInText = a_Text.find_last_of(' ') + 1; size_t LastSpaceInSuggestion = itr->first.find_last_of(' ') + 1; if (LastSpaceInText != LastSpaceInSuggestion) { // Suggestion has more subcommands than a_Text continue; } a_Results.push_back(itr->first.substr(LastSpaceInSuggestion)); } }
bool cHTTPServer::Start(cCallbacks & a_Callbacks, const AStringVector & a_Ports) { m_Callbacks = &a_Callbacks; // Open up requested ports: AStringVector ports; for (auto port : a_Ports) { UInt16 PortNum; if (!StringToInteger(port, PortNum)) { LOGWARNING("WebServer: Invalid port value: \"%s\". Ignoring.", port.c_str()); continue; } auto Handle = cNetwork::Listen(PortNum, std::make_shared<cHTTPServerListenCallbacks>(*this, PortNum)); if (Handle->IsListening()) { m_ServerHandles.push_back(Handle); ports.push_back(port); } } // for port - a_Ports[] // Inform the admin about the ports opened: AString reportPorts; for (const auto & port: ports) { if (!reportPorts.empty()) { reportPorts.append(", "); } reportPorts.append(port); } LOGINFO("WebAdmin is running on port(s) %s", reportPorts.c_str()); // Report success if at least one port opened successfully: return !m_ServerHandles.empty(); }
void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { // Create a list of names to query, by removing those that are already cached: AStringVector NamesToQuery; NamesToQuery.reserve(a_PlayerNames.size()); { cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) { NamesToQuery.push_back(*itr); } } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) while (!NamesToQuery.empty()) { // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); } // for itr - a_PlayerNames[] NamesToQuery.erase(NamesToQuery.begin(), itr); Json::FastWriter Writer; AString RequestBody = Writer.write(root); // Create the HTTP request: AString Request; Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_NameToUUIDServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Type: application/json\r\n"; Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); Request += "\r\n"; Request += RequestBody; // Get the response from the server: AString Response; if (!SecureRequest(m_NameToUUIDServer, Request, Response)) { continue; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; if (!reader.parse(Response, root, false) || !root.isArray()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Store the returned results into cache: size_t JsonCount = root.size(); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } // cCSLock (m_CSNameToUUID) // Also cache the UUIDToName: { cCSLock Lock(m_CSUUIDToName); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_UUIDToName[JsonUUID] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } } // while (!NamesToQuery.empty()) }
bool cPluginLua::Load(void) { cCSLock Lock(m_CriticalSection); if (!m_LuaState.IsValid()) { m_LuaState.Create(); m_LuaState.RegisterAPILibs(); // Inject the identification global variables into the state: lua_pushlightuserdata(m_LuaState, this); lua_setglobal(m_LuaState, LUA_PLUGIN_INSTANCE_VAR_NAME); lua_pushstring(m_LuaState, GetName().c_str()); lua_setglobal(m_LuaState, LUA_PLUGIN_NAME_VAR_NAME); // Add the plugin's folder to the package.path and package.cpath variables (#693): m_LuaState.AddPackagePath("path", FILE_IO_PREFIX + GetLocalFolder() + "/?.lua"); #ifdef _WIN32 m_LuaState.AddPackagePath("cpath", GetLocalFolder() + "\\?.dll"); #else m_LuaState.AddPackagePath("cpath", FILE_IO_PREFIX + GetLocalFolder() + "/?.so"); #endif tolua_pushusertype(m_LuaState, this, "cPluginLua"); lua_setglobal(m_LuaState, "g_Plugin"); } std::string PluginPath = FILE_IO_PREFIX + GetLocalFolder() + "/"; // List all Lua files for this plugin. Info.lua has a special handling - make it the last to load: AStringVector Files = cFile::GetFolderContents(PluginPath.c_str()); AStringVector LuaFiles; bool HasInfoLua = false; for (AStringVector::const_iterator itr = Files.begin(), end = Files.end(); itr != end; ++itr) { if (itr->rfind(".lua") != AString::npos) { if (*itr == "Info.lua") { HasInfoLua = true; } else { LuaFiles.push_back(*itr); } } } std::sort(LuaFiles.begin(), LuaFiles.end()); // Warn if there are no Lua files in the plugin folder: if (LuaFiles.empty()) { SetLoadError("No lua files found, plugin is probably missing."); LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str()); Close(); return false; } // Load all files in the list, including the Info.lua as last, if it exists: for (AStringVector::const_iterator itr = LuaFiles.begin(), end = LuaFiles.end(); itr != end; ++itr) { AString Path = PluginPath + *itr; if (!m_LuaState.LoadFile(Path)) { SetLoadError(Printf("Failed to load file %s.", itr->c_str())); Close(); return false; } } // for itr - Files[] if (HasInfoLua) { AString Path = PluginPath + "Info.lua"; if (!m_LuaState.LoadFile(Path)) { SetLoadError("Failed to load file Info.lua."); m_Status = cPluginManager::psError; Close(); return false; } } // Call the Initialize function: bool res = false; if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res)) { SetLoadError("Cannot call the Initialize() function."); LOGWARNING("Error in plugin %s: Cannot call the Initialize() function. Plugin is temporarily disabled.", GetName().c_str()); Close(); return false; } if (!res) { SetLoadError("The Initialize() function failed."); LOGINFO("Plugin %s: Initialize() call failed, plugin is temporarily disabled.", GetName().c_str()); Close(); return false; } m_Status = cPluginManager::psLoaded; return true; }
AStringVector cNetwork::EnumLocalIPAddresses(void) { AStringVector res; #ifdef _WIN32 // Query the OS for all adapters' addresses: char buffer[64 KiB]; // A buffer backing the address list PIP_ADAPTER_ADDRESSES pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer); ULONG outBufLen = sizeof(buffer); DWORD dwRetVal = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, nullptr, pAddresses, &outBufLen ); if (dwRetVal != ERROR_SUCCESS) { LOG("GetAdaptersAddresses() failed: %u", dwRetVal); return res; } // Enumerate all active adapters for (auto pCurrAddresses = pAddresses; pCurrAddresses != nullptr; pCurrAddresses = pCurrAddresses->Next) { if (pCurrAddresses->OperStatus != IfOperStatusUp) { // Adapter not active, skip it: continue; } // Collect all IP addresses on this adapter: for (auto pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next) { auto Address = PrintAddress(pUnicast->Address); if (!Address.empty()) { res.push_back(Address); } } // for pUnicast } // for pCurrAddresses #else // _WIN32 struct ifaddrs * ifAddrStruct = nullptr; getifaddrs(&ifAddrStruct); for (auto ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr == nullptr) { continue; } auto Address = PrintAddress(ifa); if (!Address.empty()) { res.emplace_back(Address); } } if (ifAddrStruct != nullptr) { freeifaddrs(ifAddrStruct); } #endif // else _WIN32 return res; }
Bool CExcelExporterDlg::ExportExcel(IllusionExcelFile& sExcel, const AString& sSheetName) { int iRow = sExcel.GetRowCount(); int iCol = sExcel.GetColumnCount(); //第一行: 数据类型(int, float, uchar[n]) //第二行: 字段名 //第三行: 字段注释 HawkAssert(iRow >= 3 && iCol > 0); if (iRow >= 3 && iCol > 0) { CString sVariable; AStringVector vTypes; AString sSheet = sSheetName; HawkAssert(sSheet.size()); if (!sSheet.size()) return false; //计算导出的数据格式 for (int i=1;i<=iCol;i++) { if (!sExcel.GetCellString(1, i).GetLength() || !sExcel.GetCellString(2, i).GetLength()) return false; AString sTypeName = sExcel.GetCellString(1, i).GetBuffer(0); AString sVarName = sExcel.GetCellString(2, i).GetBuffer(0); AString sVarDesc = sExcel.GetCellString(3, i).GetBuffer(0); vTypes.push_back(sTypeName); if (sTypeName != "int" && sTypeName != "float" && sTypeName.find("uchar") == AString::npos) return false; //字符数组转换-> unsigned char ***[n] if ( sTypeName.find("uchar") != AString::npos) { int iCap = HawkStringUtil::StringToInt<AString>(sTypeName.c_str() + strlen("uchar[")); sVariable.Format("%s\t//%s\r\n\tunsigned char %s[%d];\r\n", CString(sVariable).GetBuffer(0), sVarDesc.c_str(), sVarName.c_str(), iCap); } else { sVariable.Format("%s\t//%s\r\n\t%s %s;\r\n", CString(sVariable).GetBuffer(0), sVarDesc.c_str(), sTypeName.c_str(), sVarName.c_str()); } } //保存原始名字 AString sSheetName = sSheet; HawkStringUtil::UpCase<AString>(sSheet); //格式化导出模式文件 CString sStructFmt; sStructFmt.Format(STRUCT_FORMAT, sSheet.c_str(), sSheet.c_str(), sSheetName.c_str(), sVariable.GetBuffer(0)); OutputDebugString(sStructFmt.GetBuffer(0)); //存储模式文件 HawkDiskFile struct_file; char szExportFile[PAGE_SIZE] = {0}; sprintf(szExportFile, "Pattern/C++/%s.h", sSheetName.c_str()); _chmod(szExportFile, _S_IREAD | _S_IWRITE); if (struct_file.Open(szExportFile, HawkFile::OPEN_WRITE)) { struct_file.Write(sStructFmt.GetBuffer(0), sStructFmt.GetLength()); struct_file.Close(); } else { return false; } //二进制excel数据 OctetsStream xOS; //记录项数目 Int32 iCount = iRow - 3; xOS.Push<Int32>(iCount); for (int i=4; i<=iRow; i++) { for (int j=1;j<=iCol;j++) { AString sCellText = sExcel.GetCellString(i, j).GetBuffer(0); if (vTypes[j-1] == "int") { if (!sCellText.size()) sCellText = "0"; Int32 iVal = HawkStringUtil::StringToInt<AString>(sCellText); xOS.Push<Int32>(iVal); } else if (vTypes[j-1] == "float") { if (!sCellText.size()) sCellText = "0"; Float fVal = HawkStringUtil::StringToFloat<AString>(sCellText); xOS.Push<Float>(fVal); } else if (vTypes[j-1].find("uchar") != AString::npos) { UString sVal = HawkStringUtil::ToUtf8(sCellText); int iCap = HawkStringUtil::StringToInt<AString>(vTypes[j-1].c_str() + strlen("uchar[")); UChar* pBuf = new UChar[iCap]; memset(pBuf, 0, iCap); memcpy(pBuf, sVal.c_str(), sVal.size()); xOS.Push(pBuf, iCap); HAWK_DELETE_ARRAY(pBuf); } } } //数据压缩 UInt32 iSrcSize = xOS.Size(); ULong lComSize = HawkZip::GetRequiredSize(iSrcSize); Char* pComBuf = new Char[lComSize]; memset(pComBuf, 0, lComSize); HawkScope::DataArrayPtr scope(pComBuf); if (!HawkZip::Compress(pComBuf, lComSize, xOS.Begin(), iSrcSize)) return false; //压缩后做位反运算 for (ULong i=0;i<lComSize;i++) pComBuf[i] = (~pComBuf[i]); //压缩后的CRC校验 UInt32 iCrc = HawkStringUtil::CalcHash(pComBuf, lComSize); HawkDiskFile bin_file; sprintf(szExportFile, "BinCfg/%s.bin", sSheetName.c_str()); _chmod(szExportFile, _S_IREAD | _S_IWRITE); if (bin_file.Open(szExportFile, HawkFile::OPEN_WRITE)) { bin_file.Write(&iSrcSize, sizeof(iSrcSize)); bin_file.Write(&iCrc, sizeof(iCrc)); bin_file.Write(pComBuf, lComSize, true); bin_file.Close(); } else { return false; } return true; } return false; }