Page 1 of 1

Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 7:51 am
by InvisibleSoldiers
What is best way to do Repeat timers when you should get player variables there. I know I can't pass a self player object, only a player index because the object won't utilize when player will disconnect from a server. Does it mean that only conveni3nt way is taking it from PlayerDictionary by index passed as argument but with it comes problems with cyclic imports :mad: .

Re: Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 8:01 am
by L'In20Cible
Example of what you are trying to do?

Re: Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 8:33 am
by InvisibleSoldiers

Syntax: Select all

from listeners.tick import Repeat
from players.dictionary import PlayerDictionary


class CustomPlayer(Player):
def __init__(self, index):
super().__init__(index)

self.sex = 'female'
self.age = 16
self.is_dead = False

self.aging_timer = Repeat(aging, (self.index, ))

PLAYERS = PlayerDictionary(CustomPlayer)

def aging(index):
player = PLAYERS[index]
player.age += 1

if player.sex == 'female' and player.age == 74:
player.is_dead = True
elif player.sex == 'male' and player.age == 68:
player.is_dead = True
else:
print('Dead or Alive')


It's just a minuature example :tongue:. And if the code will split into different files, this will lead to cyclic imports :confused:
Maybe with your early commits linked with entity instances caching i can simply will do it.
BTW, why you haven’t done a new build yet to http://downloads.sourcepython.com/

Syntax: Select all

class CustomPlayer(Player):
def __init__(self, index):
super().__init__(index)
self.sex = 'female'
self.age = 16
self.is_dead = False

self.aging_timer = Repeat(aging, (self.index, ))

def aging(index):
player = CustomPlayer(index)
player.age += 1

if player.sex == 'female' and player.age == 74:
player.is_dead = True
elif player.sex == 'male' and player.age == 68:
player.is_dead = True
else:
print('Dead or Alive')

Re: Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 9:01 am
by L'In20Cible
InvisibleSoldiers wrote:

Syntax: Select all

from listeners.tick import Repeat
from players.dictionary import PlayerDictionary


class CustomPlayer(Player):
def __init__(self, index):
super().__init__(index)

self.sex = 'female'
self.age = 16
self.is_dead = False

self.aging_timer = Repeat(aging, (self.index, ))

PLAYERS = PlayerDictionary(CustomPlayer)

def aging(index):
player = PLAYERS[index]
player.age += 1

if player.sex == 'female' and player.age == 74:
player.is_dead = True
elif player.sex == 'male' and player.age == 68:
player.is_dead = True
else:
print('Dead or Alive')

You could simply use something like this:

Syntax: Select all

from listeners.tick import Repeat
from players.dictionary import PlayerDictionary


class CustomPlayer(Player):
def __init__(self, index):
super().__init__(index)

self.sex = 'female'
self.age = 16
self.is_dead = False

self.aging_timer = Repeat(aging, (self, ))

class CustomPlayers(PlayerDictionary):
def on_automatically_removed(self, index):
self[index].aging_timer.stop()

PLAYERS = CustomPlayers(CustomPlayer)

def aging(player):
player.age += 1

if player.sex == 'female' and player.age == 74:
player.is_dead = True
elif player.sex == 'male' and player.age == 68:
player.is_dead = True
else:
print('Dead or Alive')


Or if your repeat needs to run infinitely, you could probably just use a delay to repeat it:

Syntax: Select all

def aging(player):
player.delay(interval, (player,))

aging(player)

Entity.delay takes care to cancel delays when the entities are deleted. Perhaps we could add something similar for repeats. Open an issue as a feature request on the repo if you'd like to see something like that.

InvisibleSoldiers wrote:And if the code will split into different files, this will lead to cyclic imports :confused:

If you request a function or a class before it is declared then yes, you will end with a cyclic import. A solution is often to move the import into local scope, or simply import the whole module like import x rather than the object through a from x import y, etc. But generally, if you have modules that needs to import each other they are often a good fit to form a module together.

InvisibleSoldiers wrote:Maybe with your early commits linked with entity instances caching i can simply will do it.

Yes, this would work, as the same object would be returned. However I would probably personally use a dictionary as demonstrated above regardless, as it is more elegant in my opinion as it allows you to pass the object around directly instead of instantiating/looking up the cache every times.

InvisibleSoldiers wrote:BTW, why you haven’t done a new build yet to http://downloads.sourcepython.com/

I don't have access to the backend, Ayuto is the one doing the public builds since our buildbot was shut down last year. I'm sure he will do a new build in due time.

Re: Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 10:07 am
by InvisibleSoldiers
L'In20Cible wrote:You could simply use something like this:

Syntax: Select all

from listeners.tick import Repeat
from players.dictionary import PlayerDictionary


class CustomPlayer(Player):
def __init__(self, index):
super().__init__(index)

self.sex = 'female'
self.age = 16
self.is_dead = False

self.aging_timer = Repeat(aging, (self, ))

class CustomPlayers(PlayerDictionary):
def on_automatically_removed(self, index):
self[index].aging_timer.stop()

PLAYERS = CustomPlayers(CustomPlayer)

def aging(player):
player.age += 1

if player.sex == 'female' and player.age == 74:
player.is_dead = True
elif player.sex == 'male' and player.age == 68:
player.is_dead = True
else:
print('Dead or Alive')



Ok, thank you, it is best, but i remember that i did similar and __del__ didn't call.
Rather it the best for infinity loops, and entity.delay for single usage.

Re: Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 10:27 am
by L'In20Cible
InvisibleSoldiers wrote:Ok, thank you, it is best, but i remember that i did similar and __del__ didn't call.

That method won't get called when an entity is deleted. That method is called when the object is being garbage collected (when the refcount of that object reaches 0) and is not even guaranteed to be called at all so should really only be used in very specific cases and not as a generic destructor. If you want to know when an entity is deleted, then you must listen to the OnEntityDeleted listener, which is what on_automatically_removed is being called from.

Re: Repeat timers with cached player instances

Posted: Sat Dec 14, 2019 2:31 pm
by Ayuto
To be more precise: __del__ is getting called when the refcount reaches 0 and the garbage collector decides to collect it. That can be immediately, in 5 minutes or never.

I will publish a new build tomorrow. Just wrote myself a reminder.