Repeat timers with cached player instances

Please post any questions about developing your plugin here. Please use the search function before posting!
InvisibleSoldiers
Senior Member
Posts: 114
Joined: Fri Mar 15, 2019 6:08 am

Repeat timers with cached player instances

Postby InvisibleSoldiers » Sat Dec 14, 2019 7:51 am

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

Re: Repeat timers with cached player instances

Postby L'In20Cible » Sat Dec 14, 2019 8:01 am

Example of what you are trying to do?
InvisibleSoldiers
Senior Member
Posts: 114
Joined: Fri Mar 15, 2019 6:08 am

Re: Repeat timers with cached player instances

Postby InvisibleSoldiers » Sat Dec 14, 2019 8:33 am

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

Re: Repeat timers with cached player instances

Postby L'In20Cible » Sat Dec 14, 2019 9:01 am

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.
InvisibleSoldiers
Senior Member
Posts: 114
Joined: Fri Mar 15, 2019 6:08 am

Re: Repeat timers with cached player instances

Postby InvisibleSoldiers » Sat Dec 14, 2019 10:07 am

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

Re: Repeat timers with cached player instances

Postby L'In20Cible » Sat Dec 14, 2019 10:27 am

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.
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Repeat timers with cached player instances

Postby Ayuto » Sat Dec 14, 2019 2:31 pm

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.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 34 guests