I've noticed that server randomly crashes on caster/spectator logout if both of them logged out at the same time or if 2 casters logged out at the same time.
I did read a solution on Github on 1 of the replies saying:
release() before my changes.
release() after my changes.
logout() before my changes.
logout() after my changes.
When server crashes it points me to this line in protocolspectator.cpp.
Here's the function containing this line.
I know that's not the normal type of Support threads people post and it's harder than what people expect but it's the only free system out there that I found and I can add and also I've seen several other people who successfully added it so sharing their own solutions wouldn't harm I believe.
Here's a link to the system too.
Edit:
There's also a copy of Visual Studio debugger messages.
Autos:
Locals:
Call Stack:
I did read a solution on Github on 1 of the replies saying:
So I followed his solution and moved them from release() to logout().I have probably fixed it by copying kick functions from ProtocolGame::release() to logout(). I observe that release() function is not casted instantly on logout, but on next ProtocolGame task, such as login...
release() before my changes.
C++:
void ProtocolGame::release()
{
//dispatcher thread
if (player && player->client == shared_from_this()) {
// in the dispatcher thread, this should release the protocol after the player is null and this protocol has released
// so we must exclude every spectator before releasing
if (isLiveCasting()) {
sendChannelEvent(CHANNEL_CAST, player->name, CHANNELEVENT_EXCLUDE);
for (auto spectator : castinfo.spectators) {
sendChannelEvent(CHANNEL_CAST, spectator->name, CHANNELEVENT_EXCLUDE); // which is gonna be sent to every spectator
}
stopLiveCasting();
}
player->client.reset();
player->decrementReferenceCounter();
player = nullptr;
}
OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this());
Protocol::release();
}
C++:
void ProtocolGame::release()
{
//dispatcher thread
if (player && player->client == shared_from_this()) {
player->client.reset();
player->decrementReferenceCounter();
player = nullptr;
}
OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this());
Protocol::release();
}
C++:
void ProtocolGame::logout(bool displayEffect, bool forced)
{
//dispatcher thread
if (!player) {
return;
}
if (!player->isRemoved()) {
if (!forced) {
if (!player->isAccessPlayer()) {
if (player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) {
player->sendCancelMessage(RETURNVALUE_YOUCANNOTLOGOUTHERE);
return;
}
if (!player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) {
player->sendCancelMessage(RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT);
return;
}
}
//scripting event - onLogout
if (!g_creatureEvents->playerLogout(player)) {
//Let the script handle the error message
return;
}
}
if (displayEffect && player->getHealth() > 0) {
g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
}
}
disconnect();
g_game.removeCreature(player);
}
C++:
void ProtocolGame::logout(bool displayEffect, bool forced)
{
//dispatcher thread
if (!player) {
return;
}
if (!player->isRemoved()) {
if (!forced) {
if (!player->isAccessPlayer()) {
if (player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) {
player->sendCancelMessage(RETURNVALUE_YOUCANNOTLOGOUTHERE);
return;
}
if (!player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) {
player->sendCancelMessage(RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT);
return;
}
}
//scripting event - onLogout
if (!g_creatureEvents->playerLogout(player)) {
//Let the script handle the error message
return;
}
}
if (displayEffect && player->getHealth() > 0 && !player->isInGhostMode()) {
g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
}
}
//dispatcher thread
if (player && player->client == shared_from_this()) {
// in the dispatcher thread, this should release the protocol after the player is null and this protocol has released
// so we must exclude every spectator before releasing
if (isLiveCasting()) {
sendChannelEvent(CHANNEL_CAST, player->name, CHANNELEVENT_EXCLUDE);
for (auto spectator : castinfo.spectators) {
sendChannelEvent(CHANNEL_CAST, spectator->name, CHANNELEVENT_EXCLUDE); // which is gonna be sent to every spectator
}
}
stopLiveCasting();
}
disconnect();
g_game.removeCreature(player);
}
C++:
OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this());
C++:
void ProtocolSpectator::release()
{
// dispatcher thread
if (player && casterProtocol && player->client == casterProtocol->shared_from_this()) {
casterProtocol->castinfo.spectators.erase(
std::find(casterProtocol->castinfo.spectators.begin(),
casterProtocol->castinfo.spectators.end(), getThis())
);
casterProtocol->sendChannelEvent(CHANNEL_CAST, name, CHANNELEVENT_EXCLUDE);
TextMessage message = TextMessage(MESSAGE_STATUS_WARNING, name + " has left the channel.");
message.channelId = CHANNEL_CAST;
casterProtocol->sendTextMessage(message);
IOLoginData::updateCast(player->getGUID(), casterProtocol->castinfo.spectators.size());
}
OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this());
}
Here's a link to the system too.
Live casting system by slavidodo · Pull Request #2230 · otland/forgottenserver
Continues #994 . And closes #984 Additional features than the ones mentioned there in the issue are that you can mute/ban a specific spectator and pause the cast while in need to do. Furthermore, c...
github.com
There's also a copy of Visual Studio debugger messages.
Autos:
Code:
+ casterProtocol 0x0000025c9c102cb0 {castinfo={lastSpectatorNum=0 enabled=false paused=false ...} } ProtocolGame *
+ casterProtocol->castinfo {lastSpectatorNum=0 enabled=false paused=false ...} ProtocolGame::<unnamed-type-castinfo>
+ casterProtocol->castinfo.spectators { size=0 } std::vector<std::shared_ptr<ProtocolSpectator>,std::allocator<std::shared_ptr<ProtocolSpectator>>>
+ player 0x0000025c9c219020 {attackedSet={ size=0 } VIPList={ size=0 } openContainers={ size=0 } ...} Player *
+ this 0x0000025cb77ec150 {lastSpeak=0 name="Spectator [1]" casterProtocol=0x0000025c9c102cb0 {castinfo={lastSpectatorNum=...} } } ProtocolSpectator *
Code:
+ this 0x0000025cb77ec150 {lastSpeak=0 name="Spectator [1]" casterProtocol=0x0000025c9c102cb0 {castinfo={lastSpectatorNum=...} } } ProtocolSpectator *
+ message {type=0 '\0' text="H‰\\$\x10H‰t$\x18H‰|$ UATAUAVAWHl$ÉHì " position={x=1 y=0 z=0 '\0' } ...} TextMessage
Code:
theforgottenserver-x64.exe!std::_Throw_bad_weak_ptr() Line 1045 C++
[Inline Frame] theforgottenserver-x64.exe!std::shared_ptr<Protocol>::{ctor}(const std::weak_ptr<Protocol> &) Line 1580 C++
[Inline Frame] theforgottenserver-x64.exe!std::enable_shared_from_this<Protocol>::shared_from_this() Line 3080 C++
> theforgottenserver-x64.exe!ProtocolSpectator::release() Line 198 C++
[Inline Frame] theforgottenserver-x64.exe!std::_Func_class<void>::operator()() Line 880 C++
[Inline Frame] theforgottenserver-x64.exe!Task::operator()() Line 25 C++
theforgottenserver-x64.exe!Dispatcher::threadMain() Line 43 C++
[External Code]
Last edited: