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

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
Hymns For Disco
Member
Posts: 32
Joined: Wed Nov 22, 2017 7:18 am
Contact:

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

Postby Hymns For Disco » Tue Feb 11, 2020 2:24 am

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.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

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

Postby L'In20Cible » Tue Feb 11, 2020 3:19 am

Sp info? Complete reproducible code/steps?
User avatar
Hymns For Disco
Member
Posts: 32
Joined: Wed Nov 22, 2017 7:18 am
Contact:

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

Postby Hymns For Disco » Tue Feb 11, 2020 5:20 am

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
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

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

Postby L'In20Cible » Tue Feb 11, 2020 4:27 pm

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.
User avatar
Hymns For Disco
Member
Posts: 32
Joined: Wed Nov 22, 2017 7:18 am
Contact:

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

Postby Hymns For Disco » Wed Mar 11, 2020 1:40 pm

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.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

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

Postby L'In20Cible » Fri Mar 13, 2020 2:27 am

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.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 19 guests