├── .editorconfig ├── .git_commit_template.txt ├── .gitattributes ├── .github └── workflows │ └── core-build.yml ├── .gitignore ├── LICENSE ├── README.md ├── conf ├── breakingnews.conf.dist └── conf.sh.dist ├── icon.png ├── include.sh ├── setup_git_commit_template.sh └── src ├── BreakingNews.cpp ├── BreakingNews.h └── MP_loader.cpp /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 4 5 | tab_width = 4 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | max_line_length = 80 9 | -------------------------------------------------------------------------------- /.git_commit_template.txt: -------------------------------------------------------------------------------- 1 | ### TITLE 2 | ## Type(Scope/Subscope): Commit ultra short explanation 3 | ## |---- Write below the examples with a maximum of 50 characters ----| 4 | ## Example 1: fix(DB/SAI): Missing spell to NPC Hogger 5 | ## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros 6 | ## Example 3: feat(CORE/Commands): New GM command to do something 7 | 8 | ### DESCRIPTION 9 | ## Explain why this change is being made, what does it fix etc... 10 | ## |---- Write below the examples with a maximum of 72 characters per lines ----| 11 | ## Example: Hogger (id: 492) was not charging player when being engaged. 12 | 13 | ## Provide links to any issue, commit, pull request or other resource 14 | ## Example 1: Closes issue #23 15 | ## Example 2: Ported from other project's commit (link) 16 | ## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/ 17 | 18 | ## ======================================================= 19 | ## EXTRA INFOS 20 | ## ======================================================= 21 | ## "Type" can be: 22 | ## feat (new feature) 23 | ## fix (bug fix) 24 | ## refactor (refactoring production code) 25 | ## style (formatting, missing semi colons, etc; no code change) 26 | ## docs (changes to documentation) 27 | ## test (adding or refactoring tests; no production code change) 28 | ## chore (updating bash scripts, git files etc; no production code change) 29 | ## -------------------- 30 | ## Remember to 31 | ## Capitalize the subject line 32 | ## Use the imperative mood in the subject line 33 | ## Do not end the subject line with a period 34 | ## Separate subject from body with a blank line 35 | ## Use the body to explain what and why rather than how 36 | ## Can use multiple lines with "-" for bullet points in body 37 | ## -------------------- 38 | ## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/ 39 | ## ======================================================= 40 | ## "Scope" can be: 41 | ## CORE (core related, c++) 42 | ## DB (database related, sql) 43 | ## ======================================================= 44 | ## "Subscope" is optional and depends on the nature of the commit. 45 | ## ======================================================= 46 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ## AUTO-DETECT 2 | ## Handle line endings automatically for files detected as 3 | ## text and leave all files detected as binary untouched. 4 | ## This will handle all files NOT defined below. 5 | * text=auto eol=lf 6 | 7 | # Text 8 | *.conf text 9 | *.conf.dist text 10 | *.cmake text 11 | 12 | ## Scripts 13 | *.sh text 14 | *.fish text 15 | *.lua text 16 | 17 | ## SQL 18 | *.sql text 19 | 20 | ## C++ 21 | *.c text 22 | *.cc text 23 | *.cxx text 24 | *.cpp text 25 | *.c++ text 26 | *.hpp text 27 | *.h text 28 | *.h++ text 29 | *.hh text 30 | 31 | 32 | ## For documentation 33 | 34 | # Documents 35 | *.doc diff=astextplain 36 | *.DOC diff=astextplain 37 | *.docx diff=astextplain 38 | *.DOCX diff=astextplain 39 | *.dot diff=astextplain 40 | *.DOT diff=astextplain 41 | *.pdf diff=astextplain 42 | *.PDF diff=astextplain 43 | *.rtf diff=astextplain 44 | *.RTF diff=astextplain 45 | 46 | ## DOCUMENTATION 47 | *.markdown text 48 | *.md text 49 | *.mdwn text 50 | *.mdown text 51 | *.mkd text 52 | *.mkdn text 53 | *.mdtxt text 54 | *.mdtext text 55 | *.txt text 56 | AUTHORS text 57 | CHANGELOG text 58 | CHANGES text 59 | CONTRIBUTING text 60 | COPYING text 61 | copyright text 62 | *COPYRIGHT* text 63 | INSTALL text 64 | license text 65 | LICENSE text 66 | NEWS text 67 | readme text 68 | *README* text 69 | TODO text 70 | 71 | ## GRAPHICS 72 | *.ai binary 73 | *.bmp binary 74 | *.eps binary 75 | *.gif binary 76 | *.ico binary 77 | *.jng binary 78 | *.jp2 binary 79 | *.jpg binary 80 | *.jpeg binary 81 | *.jpx binary 82 | *.jxr binary 83 | *.pdf binary 84 | *.png binary 85 | *.psb binary 86 | *.psd binary 87 | *.svg text 88 | *.svgz binary 89 | *.tif binary 90 | *.tiff binary 91 | *.wbmp binary 92 | *.webp binary 93 | 94 | 95 | ## ARCHIVES 96 | *.7z binary 97 | *.gz binary 98 | *.jar binary 99 | *.rar binary 100 | *.tar binary 101 | *.zip binary 102 | 103 | ## EXECUTABLES 104 | *.exe binary 105 | *.pyc binary 106 | -------------------------------------------------------------------------------- /.github/workflows/core-build.yml: -------------------------------------------------------------------------------- 1 | name: core-build 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | build: 8 | uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main 9 | with: 10 | module_repo: ${{ github.event.repository.name }} 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | 3 | # 4 | #Generic 5 | # 6 | 7 | .directory 8 | .mailmap 9 | *.orig 10 | *.rej 11 | *.*~ 12 | .hg/ 13 | *.kdev* 14 | .DS_Store 15 | CMakeLists.txt.user 16 | *.bak 17 | *.patch 18 | *.diff 19 | *.REMOTE.* 20 | *.BACKUP.* 21 | *.BASE.* 22 | *.LOCAL.* 23 | 24 | # 25 | # IDE & other softwares 26 | # 27 | /.settings/ 28 | /.externalToolBuilders/* 29 | # exclude in all levels 30 | nbproject/ 31 | .sync.ffs_db 32 | *.kate-swp 33 | 34 | # 35 | # Eclipse 36 | # 37 | *.pydevproject 38 | .metadata 39 | .gradle 40 | tmp/ 41 | *.tmp 42 | *.swp 43 | *~.nib 44 | local.properties 45 | .settings/ 46 | .loadpath 47 | .project 48 | .cproject 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AzerothCore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!CAUTION] 2 | > This repository is not being actively maintained, however there is an active [AC fork here](https://github.com/azerothcore/mod-breaking-news-override). 3 | 4 | # Breaking News Override 5 | This module utilizes the Warden Payload Manager to enable the Breaking News frame on the left side of the character selection screen. You can feed it a html file defined in the config to use it. 6 | 7 | # Setup 8 | - Create a html file which contains the body for your breaking news frame. 9 | - Set the path to the html file in the config. 10 | - Enable the module and login to verify it works. 11 | 12 | # Notes 13 | There is a small amount of html tags that are actually compatible, follow this guide here: https://wowwiki-archive.fandom.com/wiki/UIOBJECT_SimpleHTML 14 | 15 | You must escape the characters `[`, `]`, `'`, `\` in your title and html file because of the way the payload is sent. 16 | Example: 17 | `\'You think this hurts? Just wait.\'` 18 | 19 | # Credits 20 | Thanks to the AzerothCore community and Foe especially for getting this to work. 21 | -------------------------------------------------------------------------------- /conf/breakingnews.conf.dist: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | # 4 | 5 | [worldserver] 6 | 7 | ######################################## 8 | # Breaking News configuration 9 | ######################################## 10 | # 11 | # BreakingNews.Enable 12 | # Description: Enable the Breaking News message on the character screen. 13 | # Default: 0 - Disabled 14 | # 1 - Enabled 15 | # 16 | 17 | BreakingNews.Enable = 0 18 | 19 | # 20 | # BreakingNews.Title 21 | # Description: The title that shows up above the breaking news body. 22 | # Default: "Breaking News" 23 | # 24 | 25 | BreakingNews.Title = "Breaking News" 26 | 27 | # 28 | # BreakingNews.HtmlPath 29 | # Description: The path to the html file to show as the breaking news body. 30 | # Note: Can be absolute or relative. 31 | # Default: "./breakingnews.html" 32 | # 33 | 34 | BreakingNews.HtmlPath = "./breakingnews.html" 35 | 36 | # 37 | # BreakingNews.Cache 38 | # Description: Caches the breaking news on startup. 39 | # Note: Setting this to 0 will pull the updated news from file every login. 40 | # 0 - Disabled 41 | # Default: 1 - Enabled 42 | # 43 | 44 | BreakingNews.Cache = 1 45 | 46 | # 47 | # BreakingNews.Verbose 48 | # Description: Enables verbose logs for debugging. 49 | # Note: Don't leave this on in production. 50 | # Default: 0 - Disabled 51 | # 1 - Enabled 52 | # 53 | 54 | BreakingNews.Verbose = 0 55 | 56 | -------------------------------------------------------------------------------- /conf/conf.sh.dist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## CUSTOM SQL - Important file used by the db_assembler.sh 4 | ## Keep only the required variables (base sql files or updates, depending on the DB) 5 | 6 | ## BASE SQL 7 | 8 | DB_AUTH_CUSTOM_PATHS+=( 9 | "$MOD_SKELETON_ROOT/sql/auth/base/" 10 | ) 11 | 12 | DB_CHARACTERS_CUSTOM_PATHS+=( 13 | "$MOD_SKELETON_ROOT/sql/characters/base/" 14 | ) 15 | 16 | DB_WORLD_CUSTOM_PATHS+=( 17 | "$MOD_SKELETON_ROOT/sql/world/base/" 18 | ) 19 | 20 | ## UPDATES 21 | 22 | DB_AUTH_UPDATES_PATHS+=( 23 | "$MOD_SKELETON_ROOT/sql/auth/updates/" 24 | ) 25 | 26 | DB_CHARACTERS_UPDATES_PATHS+=( 27 | "$MOD_SKELETON_ROOT/sql/characters/updates/" 28 | ) 29 | 30 | DB_WORLD_UPDATES_PATHS+=( 31 | "$MOD_SKELETON_ROOT/sql/world/updates/" 32 | ) 33 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnchyDev/BreakingNewsOverride/8624d3bd06ab8e973d8ce9b6d375d3e62db2e86e/icon.png -------------------------------------------------------------------------------- /include.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## GETS THE CURRENT MODULE ROOT DIRECTORY 4 | MOD_SKELETON_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" 5 | 6 | source $MOD_SKELETON_ROOT"/conf/conf.sh.dist" 7 | 8 | if [ -f $MOD_SKELETON_ROOT"/conf/conf.sh" ]; then 9 | source $MOD_SKELETON_ROOT"/conf/conf.sh" 10 | fi 11 | -------------------------------------------------------------------------------- /setup_git_commit_template.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Set a local git commit template 4 | git config --local commit.template ".git_commit_template.txt" ; 5 | -------------------------------------------------------------------------------- /src/BreakingNews.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | */ 4 | 5 | #include "BreakingNews.h" 6 | 7 | bool TryReadFile(std::string& path, std::string& bn_Result) 8 | { 9 | std::ifstream bn_File(path); 10 | 11 | std::string bn_Buffer = ""; 12 | bn_Result = ""; 13 | 14 | if (!bn_File.is_open()) 15 | { 16 | return false; 17 | } 18 | 19 | while (std::getline(bn_File, bn_Buffer)) 20 | { 21 | bn_Result = bn_Result + (bn_Buffer); 22 | } 23 | 24 | bn_Result.erase(std::remove(bn_Result.begin(), bn_Result.end(), '\r'), bn_Result.cend()); 25 | bn_Result.erase(std::remove(bn_Result.begin(), bn_Result.end(), '\n'), bn_Result.cend()); 26 | 27 | return true; 28 | } 29 | 30 | bool TryReadNews(std::string& bn_Result) 31 | { 32 | std::string path = sConfigMgr->GetOption("BreakingNews.HtmlPath", "./Updates.html"); 33 | bn_Title = sConfigMgr->GetOption("BreakingNews.Title", "Breaking News"); 34 | 35 | if (path == "") 36 | { 37 | LOG_ERROR("module", "Failed to read 'BreakingNews.HtmlPath'."); 38 | return false; 39 | } 40 | 41 | if (!TryReadFile(path, bn_Result)) 42 | { 43 | LOG_ERROR("module", "Failed to read file '{}'.", path); 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | std::vector BreakingNewsServerScript::GetChunks(std::string s, uint8_t chunkSize) 51 | { 52 | std::vector chunks; 53 | 54 | for (uint32_t i = 0; i < s.size(); i += chunkSize) 55 | { 56 | chunks.push_back(s.substr(i, chunkSize)); 57 | } 58 | 59 | return chunks; 60 | } 61 | 62 | void BreakingNewsServerScript::SendChunkedPayload(Warden* warden, WardenPayloadMgr* payloadMgr, std::string payload, uint32 chunkSize) 63 | { 64 | bool verbose = sConfigMgr->GetOption("BreakingNews.Verbose", false); 65 | 66 | auto chunks = GetChunks(payload, chunkSize); 67 | 68 | if (!payloadMgr->GetPayloadById(_prePayloadId)) 69 | { 70 | payloadMgr->RegisterPayload(_prePayload, _prePayloadId); 71 | } 72 | 73 | payloadMgr->QueuePayload(_prePayloadId); 74 | warden->ForceChecks(); 75 | 76 | if (verbose) 77 | { 78 | LOG_INFO("module", "Sent pre-payload '{}'.", _prePayload); 79 | } 80 | 81 | for (auto const& chunk : chunks) 82 | { 83 | auto smallPayload = "wlbuf = wlbuf .. [[" + chunk + "]];"; 84 | 85 | payloadMgr->RegisterPayload(smallPayload, _tmpPayloadId, true); 86 | payloadMgr->QueuePayload(_tmpPayloadId); 87 | warden->ForceChecks(); 88 | 89 | if (verbose) 90 | { 91 | LOG_INFO("module", "Sent mid-payload '{}'.", smallPayload); 92 | } 93 | } 94 | 95 | if (!payloadMgr->GetPayloadById(_postPayloadId)) 96 | { 97 | payloadMgr->RegisterPayload(_postPayload, _postPayloadId); 98 | } 99 | 100 | payloadMgr->QueuePayload(_postPayloadId); 101 | warden->ForceChecks(); 102 | 103 | if (verbose) 104 | { 105 | LOG_INFO("module", "Sent post-payload '{}'.", _postPayload); 106 | } 107 | } 108 | 109 | void LoadBreakingNews() 110 | { 111 | bn_Title = sConfigMgr->GetOption("BreakingNews.Title", "Breaking News"); 112 | 113 | if (!TryReadNews(bn_Body)) 114 | { 115 | LOG_ERROR("module", "Failed to read breaking news."); 116 | return; 117 | } 118 | 119 | bn_Formatted = Acore::StringFormatFmt(_midPayloadFmt, bn_Title, bn_Body); 120 | } 121 | 122 | bool BreakingNewsServerScript::CanPacketSend(WorldSession* session, WorldPacket& packet) 123 | { 124 | if (!bn_Enabled) 125 | { 126 | return true; 127 | } 128 | 129 | if (packet.GetOpcode() == SMSG_CHAR_ENUM) 130 | { 131 | WardenWin* warden = (WardenWin*)session->GetWarden(); 132 | if (!warden) 133 | { 134 | return true; 135 | } 136 | 137 | // Trying to use Warden before it has initialized, 138 | // so we exit. 139 | if (!warden->IsInitialized()) 140 | { 141 | return true; 142 | } 143 | 144 | if (bn_Formatted == "") 145 | { 146 | return true; 147 | } 148 | 149 | 150 | auto payloadMgr = warden->GetPayloadMgr(); 151 | if (!payloadMgr) 152 | { 153 | return true; 154 | } 155 | 156 | // Just in-case there are some payloads in the queue, we don't want to send the incorrect payload. 157 | payloadMgr->ClearQueuedPayloads(); 158 | 159 | // Load in the updated news into the cache. 160 | if (!sConfigMgr->GetOption("BreakingNews.Cache", false)) 161 | { 162 | LoadBreakingNews(); 163 | } 164 | 165 | // The client truncates warden packets to around 256 and our payload may be larger than that. 166 | SendChunkedPayload(warden, payloadMgr, bn_Formatted, 128); 167 | } 168 | 169 | return true; 170 | } 171 | 172 | void BreakingNewsWorldScript::OnAfterConfigLoad(bool /*reload*/) 173 | { 174 | bn_Enabled = sConfigMgr->GetOption("BreakingNews.Enable", false); 175 | 176 | if (!bn_Enabled) 177 | { 178 | return; 179 | } 180 | 181 | LoadBreakingNews(); 182 | } 183 | 184 | // Add all scripts in one 185 | void AddBreakingNewsScripts() 186 | { 187 | new BreakingNewsWorldScript(); 188 | new BreakingNewsServerScript(); 189 | } 190 | -------------------------------------------------------------------------------- /src/BreakingNews.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_BREAKINGNEWS_H 2 | #define MODULE_BREAKINGNEWS_H 3 | 4 | #include "ScriptMgr.h" 5 | #include "WardenWin.h" 6 | #include "Player.h" 7 | #include "Config.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | bool bn_Enabled; 14 | 15 | std::string bn_Title; 16 | std::string bn_Body; 17 | std::string bn_Formatted; 18 | 19 | const std::string _prePayload = "wlbuf = '';"; 20 | const std::string _postPayload = "local a,b=loadstring(wlbuf)if not a then message(b)else a()end"; 21 | const std::string _midPayloadFmt = "local a=ServerAlertFrame;local b=ServerAlertText;local c=ServerAlertTitle;local d=CharacterSelect;if a~=nil or b~=nil or c~=nil or d~=nil then a:SetParent(d)ServerAlertTitle:SetText('{}')ServerAlertText:SetText('{}')a:Show()else message('ServerAlert(Frame|Text|Title)/CharacterSelect Frame is nil.')end"; 22 | uint16 _prePayloadId = 9500; 23 | uint16 _postPayloadId = 9501; 24 | uint16 _tmpPayloadId = 9502; 25 | 26 | std::vector GetChunks(std::string s, uint8_t chunkSize); 27 | void SendChunkedPayload(Warden* warden, std::string payload, uint32 chunkSize); 28 | 29 | class BreakingNewsServerScript : ServerScript 30 | { 31 | public: 32 | BreakingNewsServerScript() : ServerScript("BreakingNewsServerScript") { } 33 | 34 | private: 35 | bool CanPacketSend(WorldSession* session, WorldPacket& packet) override; 36 | std::vector GetChunks(std::string s, uint8_t chunkSize); 37 | void SendChunkedPayload(Warden* warden, WardenPayloadMgr* payloadMgr, std::string payload, uint32 chunkSize); 38 | }; 39 | 40 | class BreakingNewsWorldScript : public WorldScript 41 | { 42 | public: 43 | BreakingNewsWorldScript() : WorldScript("BreakingNewsWorldScript") { } 44 | 45 | private: 46 | void OnAfterConfigLoad(bool reload) override; 47 | }; 48 | 49 | #endif //MODULE_BREAKINGNEWS_H 50 | -------------------------------------------------------------------------------- /src/MP_loader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | */ 4 | 5 | // From SC 6 | void AddBreakingNewsScripts(); 7 | 8 | // Add all 9 | // cf. the naming convention https://github.com/azerothcore/azerothcore-wotlk/blob/master/doc/changelog/master.md#how-to-upgrade-4 10 | // additionally replace all '-' in the module folder name with '_' here 11 | void AddBreakingNewsOverrideScripts() 12 | { 13 | AddBreakingNewsScripts(); 14 | } 15 | 16 | --------------------------------------------------------------------------------