Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/development' into repacker
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Sep 29, 2024
2 parents a282617 + d1f0c11 commit 6d0cb62
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 28 deletions.
82 changes: 82 additions & 0 deletions contrib/soap/example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*!
* Copyright (C) 2024-present VMaNGOS https://github.com/vmangos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

// Using https://www.npmjs.com/package/soap does not work because it expects
// a WSDL file, which we don't have. Instead, we can use a regular HTTP client
// (like the native `fetch` API which is stable since Node.js v21) to construct
// and send SOAP requests manually.

// Optional:
// We can replace XML entities with their respective characters by installing
// https://www.npmjs.com/package/entities:
// const entities = require('entities')

const username = 'ADMINISTRATOR'
const password = 'ADMINISTRATOR'
const host = 'localhost'
const port = 7878
const command = 'server info'

const buildSoapRequest = command => `
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:MaNGOS">
<SOAP-ENV:Body>
<ns1:executeCommand>
<command>${command}</command>
</ns1:executeCommand>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
`

const soapRequest = buildSoapRequest(command)

;(async () => {
try {
const response = await fetch(`http://${host}:${port}`, {
method: 'POST',
headers: {
'Content-Type': 'text/xml',
'SOAPAction': 'urn:MaNGOS',
'Authorization': 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64')
},
body: soapRequest
})

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}

const rawResult = await response.text()

if (response.status !== 200) {
console.warn(`Unexpected status code: ${response.status}`)
console.warn('Raw output:', rawResult)
return
}

const resultBeginIdx = rawResult.indexOf('<result>') + '<result>'.length
const resultEndIdx = rawResult.lastIndexOf('</result>')
let result = rawResult.slice(resultBeginIdx, resultEndIdx)
// If we chose to install the `entities` package, we can decode XML
// entities:
// result = entities.decodeXML(result)

console.log('Command succeeded! Output:', result)
} catch (error) {
console.error('Command failed! Reason:', error.message)
}
})()
12 changes: 12 additions & 0 deletions src/game/Maps/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,18 @@ bool Map::EnsureGridLoaded(Cell const& cell)
return false;
}

void Map::ForceLoadGridsAroundPosition(float x, float y)
{
if (!IsLoaded(x, y))
{
CellPair p = MaNGOS::ComputeCellPair(x, y);
Cell cell(p);
EnsureGridLoadedAtEnter(cell);
NULLNotifier notifier = NULLNotifier();
Cell::VisitAllObjects(x, y, this, notifier, GetGridActivationDistance(), false);
}
}

void Map::LoadGrid(Cell const& cell, bool no_unload)
{
EnsureGridLoaded(cell);
Expand Down
1 change: 1 addition & 0 deletions src/game/Maps/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ class Map : public GridRefManager<NGridType>

bool GetUnloadLock(GridPair const& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); }
void SetUnloadLock(GridPair const& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); }
void ForceLoadGridsAroundPosition(float x, float y);
void LoadGrid(Cell const& cell, bool no_unload = false);
bool UnloadGrid(uint32 const& x, uint32 const& y, bool pForce);
virtual void UnloadAll(bool pForce);
Expand Down
14 changes: 10 additions & 4 deletions src/game/Maps/MapManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ MapManager::MapManager()
:
i_gridCleanUpDelay(sWorld.getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN)),
i_MaxInstanceId(RESERVED_INSTANCES_LAST),
m_threads(new ThreadPool(sWorld.getConfig(CONFIG_UINT32_MAPUPDATE_INSTANCED_UPDATE_THREADS)))
m_threads(new ThreadPool(sWorld.getConfig(CONFIG_UINT32_MAPUPDATE_INSTANCED_UPDATE_THREADS))),
m_instanceCreationThreads(new ThreadPool(1))
{
i_timer.SetInterval(sWorld.getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE));
m_threads->start<ThreadPool::MySQL<>>();
m_instanceCreationThreads->start<>();
}

MapManager::~MapManager()
Expand Down Expand Up @@ -275,6 +277,7 @@ void MapManager::CreateNewInstancesForPlayers()
DungeonMap* pMap = static_cast<DungeonMap*>(CreateInstance(dest.mapId, player));
if (pMap->CanEnter(player))
{
pMap->ForceLoadGridsAroundPosition(dest.x, dest.y);
pMap->BindPlayerOrGroupOnEnter(player);
player->SendNewWorld();
}
Expand Down Expand Up @@ -336,7 +339,10 @@ void MapManager::Update(uint32 diff)
}
}

std::thread instanceCreationThread = std::thread(&MapManager::CreateNewInstancesForPlayers, this);
std::vector<std::function<void()>> instanceCreators;
instanceCreators.emplace_back([this]() {CreateNewInstancesForPlayers();});
std::future<void> instances = m_instanceCreationThreads->processWorkload(std::move(instanceCreators),
ThreadPool::Callable());

i_maxContinentThread = continentsIdx;
i_continentUpdateFinished.store(0);
Expand Down Expand Up @@ -367,8 +373,8 @@ void MapManager::Update(uint32 diff)
SwitchPlayersInstances();
asyncMapUpdating = false;

if (instanceCreationThread.joinable())
instanceCreationThread.join();
if (instances.valid())
instances.wait();

// Execute far teleports after all map updates have finished
ExecuteDelayedPlayerTeleports();
Expand Down
1 change: 1 addition & 0 deletions src/game/Maps/MapManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ class MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockab

std::unique_ptr<ThreadPool> m_threads;
std::unique_ptr<ThreadPool> m_continentThreads;
std::unique_ptr<ThreadPool> m_instanceCreationThreads;
bool asyncMapUpdating = false;

// Instanced continent zones
Expand Down
7 changes: 0 additions & 7 deletions src/game/Objects/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3460,13 +3460,6 @@ void WorldObject::Update(uint32 update_diff, uint32 /*time_diff*/)
ExecuteDelayedActions();
}

class NULLNotifier
{
public:
template<class T> void Visit(GridRefManager<T>& m) {}
void Visit(CameraMapType&) {}
};

void WorldObject::LoadMapCellsAround(float dist) const
{
ASSERT(IsInWorld());
Expand Down
7 changes: 7 additions & 0 deletions src/game/Objects/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ class GenericTransport;
struct FactionEntry;
struct FactionTemplateEntry;

class NULLNotifier
{
public:
template<class T> void Visit(GridRefManager<T>& m) {}
void Visit(CameraMapType&) {}
};

typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;

//use this class to measure time between world update ticks
Expand Down
48 changes: 31 additions & 17 deletions src/game/World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1941,12 +1941,16 @@ void World::DetectDBCLang()
// Only processes packets while session update, the messager, and cli commands processing are NOT running
void World::ProcessAsyncPackets()
{
while (!sWorld.IsStopped())
do
{
do
{
std::this_thread::sleep_for(std::chrono::milliseconds(20));
} while (!m_canProcessAsyncPackets);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::lock_guard<std::mutex> lock(m_asyncPacketsMutex);

if (IsStopped())
return;

if (!m_canProcessAsyncPackets)
continue;

for (auto const& itr : m_sessions)
{
Expand All @@ -1959,7 +1963,7 @@ void World::ProcessAsyncPackets()
if (!m_canProcessAsyncPackets)
break;
}
}
} while (!IsStopped());
}

// Update the World !
Expand Down Expand Up @@ -1994,16 +1998,21 @@ void World::Update(uint32 diff)
sAuctionMgr.Update();
}

GetMessager().Execute(this);
{
m_canProcessAsyncPackets = false;
std::lock_guard<std::mutex> lock(m_asyncPacketsMutex);

GetMessager().Execute(this);

// <li> Handle session updates
uint32 updateSessionsTime = WorldTimer::getMSTime();
UpdateSessions(diff);
updateSessionsTime = WorldTimer::getMSTimeDiffToNow(updateSessionsTime);
if (getConfig(CONFIG_UINT32_PERFLOG_SLOW_SESSIONS_UPDATE) && updateSessionsTime > getConfig(CONFIG_UINT32_PERFLOG_SLOW_SESSIONS_UPDATE))
sLog.Out(LOG_PERFORMANCE, LOG_LVL_MINIMAL, "Update sessions: %ums", updateSessionsTime);
// <li> Handle session updates
uint32 updateSessionsTime = WorldTimer::getMSTime();
UpdateSessions(diff);
updateSessionsTime = WorldTimer::getMSTimeDiffToNow(updateSessionsTime);
if (getConfig(CONFIG_UINT32_PERFLOG_SLOW_SESSIONS_UPDATE) && updateSessionsTime > getConfig(CONFIG_UINT32_PERFLOG_SLOW_SESSIONS_UPDATE))
sLog.Out(LOG_PERFORMANCE, LOG_LVL_MINIMAL, "Update sessions: %ums", updateSessionsTime);

m_canProcessAsyncPackets = true;
m_canProcessAsyncPackets = true;
}

// <li> Update uptime table
if (m_timers[WUPDATE_UPTIME].Passed())
Expand Down Expand Up @@ -2113,10 +2122,15 @@ void World::Update(uint32 diff)
// Update ban list if necessary
sAccountMgr.Update(diff);

m_canProcessAsyncPackets = false;
{
m_canProcessAsyncPackets = false;
std::lock_guard<std::mutex> lock(m_asyncPacketsMutex);

// And last, but not least handle the issued cli commands
ProcessCliCommands();

// And last, but not least handle the issued cli commands
ProcessCliCommands();
m_canProcessAsyncPackets = true;
}

//cleanup unused GridMap objects as well as VMaps
if (getConfig(CONFIG_BOOL_CLEANUP_TERRAIN))
Expand Down
1 change: 1 addition & 0 deletions src/game/World.h
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,7 @@ class World

// This thread handles packets while the world sessions update is not running
std::unique_ptr<std::thread> m_asyncPacketsThread;
std::mutex m_asyncPacketsMutex;
bool m_canProcessAsyncPackets;
void ProcessAsyncPackets();

Expand Down

0 comments on commit 6d0cb62

Please sign in to comment.