Knights Forum

General Category => Knights Discussion => Topic started by: Moo on June 11, 2013, 03:36:33 PM

Title: Duel to the Death black screen problem
Post by: Moo on June 11, 2013, 03:36:33 PM
Currently a loser in a duel to the death type game on the official server will consistently get a black screen rather than being eliminated, and the game will never end.

With the help of K9 as guinea pig, I managed to locate the cause of the problem...
In Toolbox, init.lua, line 126, kts.SetRespawnFunction(resp).

Commenting out that line, everything works properly again.

Then the question was, is the problem with the toolbox script, or the SetRespawnFunction itself. By trying it with a simple function that always returns nil, and getting the black screen problem, I'd say it's the latter. So, another one for you, Stephen :-X

Anyway... For now, commenting out that line in toolbox would cure the server.
Title: Re: Duel to the Death black screen problem
Post by: K9 on June 11, 2013, 09:40:44 PM
Thank you Moo, I was happy to test with your server, through your debugging of this issue.

It's been very frustrating on Duel to the Death quests lately, without having the proper end-game closure.

Looking forward to Stephen making that tweak to fix the official server for everyone to enjoy.

Great work spotting the cause.
Title: Re: Duel to the Death black screen problem
Post by: Stephen on June 15, 2013, 10:34:48 AM
First of all, my apologies to anyone who has been affected by this, and thank you to K9 and Moo for tracking down the bug.

I do not know exactly what is going wrong, and unfortunately I don't really have time to investigate further at the moment. I have added a ticket to Trac, will try to come back to it at some future point.

For now I have commented out that line on the server as Moo suggests. I confirmed that this does indeed fix the problem.
Title: Re: Duel to the Death black screen problem
Post by: ImpassIve on June 24, 2014, 11:44:53 AM
Unfortunately, I haven't yet realized how to build Knights from sources on Windows, so I can't check my suspicion, but:

in src\engine\impl\player.cpp (http://www.knightsgame.org.uk/trac/browser/trunk/src/engine/impl/player.cpp)
function bool Player::respawn() (http://www.knightsgame.org.uk/trac/browser/trunk/src/engine/impl/player.cpp#L404) looks like this:
____
{
    if (!respawn_func.hasValue() && getRespawnType() != R_RANDOM_SQUARE && (!home_dmap || home_location.isNull())) {
        if (!already_eliminated) {
            //----BRANCH 1----
           //SEND "Player X eliminated" message and execute  mediator.eliminatePlayer(*this);
        }
        return true;  // this counts as a "success" -- we do not want the respawn task to keep retrying.
    }

    // Find out where we should respawn
    if (!respawn_map || respawn_point.isNull())
        return false; //----BRANCH 2----

    // Respawn successful -- Create a new knight.
    //----BRANCH 3----
 
    return true;
}
____

So the Branch 1 (which is responsible for "eliminated" messages) can be reached only if there is no lua respawn function set.
Otherwise, if the respawn_func is set and there is no spawn points left, BRANCH 2 will be executed (just return false without any other actions).
Does that mean what it will keep trying to respawn a player later without any success?

void RespawnTask::execute(TaskManager &tm)
{
    if (this != player.respawn_task.get()) return;

    bool success = player.respawn();
    if (!success) {
        tm.addTask(shared_from_this(), TP_NORMAL, tm.getGVT() + 100); // try again later
    }
}


IMHO, on the one hand  - that would mean what any lua respawn function should somehow detect this situation and call kts.EliminatePlayer() manually (even if it was used just to detect knight respawn event and it always returns nil). On the other hand - I'm not sure how lua function can check whether there are any more spawn points left (haven't used lua for a long time)
Title: Re: Duel to the Death black screen problem
Post by: ImpassIve on June 24, 2014, 03:47:11 PM
Just tried this on a recently compiled Linux build with Toolbox mod installed.
Current version: black screen for loser in Duel to Death.
After commenting out /*!respawn_func.hasValue() &&*/ part: everything is OK.

Of course, it's too rough solution, since the game should really check whether the user-defined respawn function is present (otherwise, there would be problems with 'custom maps' without spawn points or something like this).
But, maybe, it should somehow distinguish "return nil" case and real custom respawn function (which would choose a spawn points for knights)?
Title: Re: Duel to the Death black screen problem
Post by: ImpassIve on June 26, 2014, 09:29:45 AM
Well... I've tried to solve this problem on a mod's side.
Modified my respawn function like this:
(1)

...
local home = kts.GetHomeFor(player)
if (home == nil) or ((home.secured_by ~= nil) and (home.secured_by ~= player)) then
    kts.EliminatePlayer(player)
end
...


Aaand... nothing changed. Still a black screen for loser.
I've tried adding debug output and modifying this code, so:

(2)

...
local home = kts.GetHomeFor(player)
if (home == nil) or (home.secured_by ~= nil)) then
    kts.EliminatePlayer(player)
end
...

^ works fine. Pick up a wand, secure your own spawn point, suicide - you are eliminated.

But I don't quite understand the returned value of the kts.GetHomeFor(player) function.
For example, even if all homes on a map were destroyed (by double securing them) - it will return some non-nil value.


Upd: tried a more detailed output to see which one.
(http://s018.radikal.ru/i505/1406/86/11fbcd5797c1.jpg)
Well, I suppose, the 'tile' field would solve the problem (as it is nil only if the player's last spawn door was secured)...
Title: Re: Duel to the Death black screen problem
Post by: Stephen on June 27, 2014, 12:46:36 PM
Hi Impassive, thanks for your detailed investigation.

That respawn function logic does seem broken.

I think originally I designed the respawn_function for use in the Tutorial, which wants to customize the respawn point depending on where you are. (For example if you die in the Chamber of Bats we want to respawn the player in the same room, not send them all the way back to the beginning.)

I didn't anticipate your use case, where you just want to be notified when a respawn happens, without changing the respawn behaviour at all.

Anyway I would suggest we change the definition of the respawn_func to be as follows:


Then you could return nil in your respawn function and it would work as you expect.

Does that sound ok?

Also, regarding kts.GetHomeFor: I think that is just a bug. In the C++ code, if no home exists, the home position is set to (-2,-2) (which is outside the map). That is what you are seeing in your lua code. However, kts.GetHomeFor is supposed to return nil in this case, so I will change it to do that.
Title: Re: Duel to the Death black screen problem
Post by: ImpassIve on June 27, 2014, 01:39:10 PM
Quote from: Stephen on June 27, 2014, 12:46:36 PMDoes that sound ok?
Of course, thank you
Title: Re: Duel to the Death black screen problem
Post by: Stephen on July 04, 2014, 11:56:39 AM
OK, I have now made the above changes.

It does seem to have fixed the "black screen problem", which is good :)

Please note that kts.GetHomeFor can now return nil, so if you are using that function, you may need to update your code to check for a nil result.