Page 1 of 1

Getting Player Reference on Connect and Disconnect (ValueError: Conversion from "Index" to "BaseEntity" failed)

Posted: Tue Feb 11, 2020 2:24 am
by Hymns For Disco
ValueError: Conversion from "Index" (1) to "BaseEntity" failed


I get this error when trying to get the player reference for a player on disconnect.

Syntax: Select all

@listeners.OnClientDisconnect
def on_disconnect(index):
player = Player(index)


This error seemingly only happens on map change when all players are disconnected
Normally disconnecting has no issues, I am able to get the Player reference and access the values I need to access

Is there any way to actually get a safe reference to the Player before they leave the server? I have a custom player class that is storing data that I need to reference on disconnect (it is for tracking player sessions).

Of course I could store all the necessary values in a dictionary and manage the cleanup manually, just seems a bit silly as custom Player classes otherwise accommodate this use case very well.

Re: Getting Player Reference on Connect and Disconnect (ValueError: Conversion from "Index" to "BaseEntity" failed)

Posted: Tue Feb 11, 2020 3:19 am
by L'In20Cible
Sp info? Complete reproducible code/steps?

Re: Getting Player Reference on Connect and Disconnect (ValueError: Conversion from "Index" to "BaseEntity" failed)

Posted: Tue Feb 11, 2020 5:20 am
by Hymns For Disco
console wrote:map dust2
---- Host_Changelevel ----

[SP] Caught an Exception:
Traceback (most recent call last):
File "..\addons\source-python\plugins\myplugin\accounts.py", line 111, in on_disconnect
player = Player(index)
File "..\addons\source-python\packages\source-python\entities\_base.py", line 106, in __call__
obj = super().__call__(index)
File "..\addons\source-python\plugins\myplugin\accounts.py", line 35, in __init__
super(Player, self).__init__(*args)
File "..\addons\source-python\packages\source-python\players\_base.py", line 90, in __init__
PlayerMixin.__init__(self, index)

ValueError: Conversion from "Index" (1) to "BaseEntity" failed.

.......
sp info

IMPORTANT: Please copy the full output.
--------------------------------------------------------
Checksum : 740c4dd69b96581962ded112b4a78237
Date : 2020-02-11 05:10:32.531143
OS : Windows-10-10.0.18362
Game : csgo
SP version : 694
Github commit : e65bf547b5f036b50a89dc9461af75efb24a3b1d
Server plugins:
00: Source.Python, (C) 2012-2019, Source.Python Team.
SP plugins:
00: myplugin
--------------------------------------------------------


accounts.py

Syntax: Select all

import listeners

from players.entity import Player as _Player

class Player(_Player):
def __init__(self, *args):
super(Player, self).__init__(*args)
# ...

@listeners.OnClientDisconnect
def on_disconnect(index):
player = Player(index) # line 111



Again the thing of note here is that it only occurs on forced map change, see the console log. Normal disconnect of the player passes just fine.

Edit: same error occurs if using players.entity.Player directly, though in my plugin I have a custom subclass being used

Re: Getting Player Reference on Connect and Disconnect (ValueError: Conversion from "Index" to "BaseEntity" failed)

Posted: Tue Feb 11, 2020 4:27 pm
by L'In20Cible
Seems like the player's edict had already been freed (or at least, removed from the global array, and passed to the callbacks) by the time the engine calls this listener. Try to listen for entity deletion instead (won't work on OB games, as their server unknown instance appears to be unbound already):

Syntax: Select all

import listeners

from players.entity import Player as _Player

class Player(_Player):
def __init__(self, *args):
super(Player, self).__init__(*args)
# ...

@listeners.OnEntityDeleted
def on_entity_deleted(base_entity):
if not base_entity.is_player():
return
player = Player(index) # line 111


Or listen for team changes:

Syntax: Select all

from events import Event
import listeners

from players.entity import Player as _Player

class Player(_Player):
def __init__(self, *args):
super(Player, self).__init__(*args)
# ...

@Event('player_team')
def player_team(game_event):
if not game_event.get_bool('disconnect'):
return
player = Player.from_userid(game_event.get_int('userid'))


That event should only happens on direct disconnect, not on map changes though. Could also listen for player_disconnect directly as well.

Re: Getting Player Reference on Connect and Disconnect (ValueError: Conversion from "Index" to "BaseEntity" failed)

Posted: Wed Mar 11, 2020 1:40 pm
by Hymns For Disco
Sorry I had forgotten to check back on this thread.

The solution I ended up going with was

Syntax: Select all

@listeners.OnLevelShutdown
def on_level_shutdown():
disconnect_all_players()

OnLevelShutdown allows me to get the player entities of all connected players before they are freed, and run my disconnect routine for every player before their actual disconnect event is called. On disconnect, I check if the player has already had the disconnect routine called for them.

Re: Getting Player Reference on Connect and Disconnect (ValueError: Conversion from "Index" to "BaseEntity" failed)

Posted: Fri Mar 13, 2020 2:27 am
by L'In20Cible
Hymns For Disco wrote:Sorry I had forgotten to check back on this thread.

The solution I ended up going with was

Syntax: Select all

@listeners.OnLevelShutdown
def on_level_shutdown():
disconnect_all_players()

OnLevelShutdown allows me to get the player entities of all connected players before they are freed, and run my disconnect routine for every player before their actual disconnect event is called. On disconnect, I check if the player has already had the disconnect routine called for them.

Ah yeah, this is a great solution. We use this internally as a workaround to disconnect bots when the server is hibernating. Alternatively, instead of OnLevelShutdown, you could use OnLevelEnd which is guaranteed to only be called once so you wouldn't have to track players that are already disconnected, etc.