Looping a Timed Task in Many Objects

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:

Looping a Timed Task in Many Objects

Postby Hymns For Disco » Wed Nov 22, 2017 7:30 am

I am trying to create a plugin where I have several entities in my map, (Instantiated through my Zone class), and I want these Zones to draw and redraw their outline beams periodically. I don't need the timing to be super precise, I just need it to be reliably recalled repeatedly throughout the lifetime of the Zone object. I am wondering what is the best way to achieve this. I would prefer if the behaviour could be contained within the Zone class itself, rather than calling it for each current Zone object through a master loop such as @OnTick. I have so far tried using time.sleep() and asyncio.sleep(), but both of these functions cause the server to time-out.

Another way to reach my end goal would be if I could spawn the beams to last forever, then manually destroy them if the Zone is removed, but I am not sure if this is possible or if it will cause issues for players who join after the Zones are first created.

Thanks, Disco
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: Looping a Timed Task in Many Objects

Postby satoon101 » Wed Nov 22, 2017 12:15 pm

One option would be Repeat which uses Delay internally, which in turn uses a tick listener. That would be my preferred option in this instance.
Image
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Looping a Timed Task in Many Objects

Postby Ayuto » Wed Nov 22, 2017 6:09 pm

Hymns For Disco wrote:Another way to reach my end goal would be if I could spawn the beams to last forever [...]

Unfortunately, that's not possible.
User avatar
Hymns For Disco
Member
Posts: 32
Joined: Wed Nov 22, 2017 7:18 am
Contact:

Re: Looping a Timed Task in Many Objects

Postby Hymns For Disco » Wed Nov 22, 2017 8:05 pm

satoon101 wrote:One option would be Repeat which uses Delay internally, which in turn uses a tick listener. That would be my preferred option in this instance.


Thank you for your response. I have tried using both Repeat() and Delay() in my Zone class, but both of these functions cause the server to immediately freeze. Here is my code

Syntax: Select all

class TimerZone:
def __init__(self, zone_origin):
self.min = Vector(-100, -100, 0)
self.max = Vector(100, 100, 100)

self.prop = Entity.create('prop_dynamic_override')
self.prop.origin = zone_origin
self.prop.set_model(Model('models/props/de_train/barrel.mdl'))
self.prop.effects |= 32;
self.prop.set_property_ushort('m_Collision.m_usSolidFlags', 12)
self.prop.spawn()
self.prop.mins = self.min
self.prop.maxs = self.max
self.prop.solid_type = 2
self.draw_beams()

def draw_beams(self):
box(
RecipientFilter(),
self.prop.origin + self.min,
self.prop.origin + self.max,
alpha=255,
blue=0,
green=0,
red=255,
amplitude=0,
end_width=1,
life_time=3,
start_width=1,
fade_length=0,
flags=0,
frame_rate=255,
halo=Model('materials/sprites/laserbeam.vmt'),
model=Model('materials/sprites/laserbeam.vmt'),
start_frame=0
)
Repeat(5.0, self.draw_beams(), running=True, time_elapsed=0)


Edit: I made a double mistake on this post. First, put the Repeat function there since I tried switching, and the args are actually wrong. The real problem was that I should have used Delay(5.0, self.draw_beams) <<<< Without "()" after the function name since it needs to call the function itself, not the functions return value.
Last edited by L'In20Cible on Wed Nov 22, 2017 11:26 pm, edited 1 time in total.
Reason: code → python
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Looping a Timed Task in Many Objects

Postby L'In20Cible » Wed Nov 22, 2017 11:25 pm

Hey, welcome to the forums! First of all, please use the PYTHON syntax when posting python code as it makes it easier to read. As for your code, this is normal that it freeze because it creates an infinite recursion. Every time the draw_beams method is called, it creates a new Repeat instance and re-call itself over and over creating new Repeat on every calls that continue re-calling itself, etc. You want to start the Repeat into your __init__ method so it only gets instantiated once for your object. However, this also means it will never stop even when the object is deleted. Are you creating multiple instances of TimerZone or only a single globalized one?

EDIT: How about inheriting from Entity directly instead? So using Entity.delay will automatically gets cancelled when the entity is removed.

Syntax: Select all

from effects import box
from engines.precache import Model
from entities.entity import BaseEntity
from entities.entity import Entity
from filters.recipients import RecipientFilter
from mathlib import Vector

class TimerZone(Entity):
min = Vector(-100, -100, 0)
max = Vector(100, 100, 100)

@classmethod
def create(cls, zone_origin):
prop = cls(BaseEntity.create('prop_dynamic_override').index)
prop.origin = zone_origin
prop.set_model(Model('models/props/de_train/barrel.mdl'))
prop.effects |= 32;
prop.set_property_ushort('m_Collision.m_usSolidFlags', 12)
prop.spawn()
prop.mins = cls.min
prop.maxs = cls.max
prop.solid_type = 2
prop.draw_beams()
return prop

def draw_beams(self):
origin = self.origin
box(
RecipientFilter(),
origin + self.mins,
origin + self.maxs,
alpha=255,
blue=0,
green=0,
red=255,
amplitude=0,
end_width=1,
life_time=3,
start_width=1,
fade_length=0,
flags=0,
frame_rate=255,
halo=Model('materials/sprites/laserbeam.vmt'),
model=Model('materials/sprites/laserbeam.vmt'),
start_frame=0
)
self.delay(5, self.draw_beams)


from players.entity import Player
player = Player(1)

prop = TimerZone.create(player.origin)

Tho, creating an invisible prop seems useless. You could simply render the effect at a location... proposing that in case you have other things planned for the entity... which I would assume you need for its Touching functions, right? In such case you could simply use a trigger_multiple.
User avatar
Hymns For Disco
Member
Posts: 32
Joined: Wed Nov 22, 2017 7:18 am
Contact:

Re: Looping a Timed Task in Many Objects

Postby Hymns For Disco » Thu Nov 23, 2017 3:05 am

L'In20Cible wrote:[...]


Thanks for your reply.
First, yes I am creating multiple instances of the TimerZone class, and also creating child classes of TimerZone to override functions for events such as touch, start_touch, end_touch etc. As well as change beam color per zone class.
I am making an invisible zone to essentially serve the same purpose as a trigger_multiple so I can bind the touch events for other parts of my plugin. I could use trigger_multiple, but as far as I can tell trigger_multiple and prop_dynamic_override work exactly the same when I substitute them in my code. I am using the latter because that is what someone had recommended to me for this use. The Entity.delay function seems to work well for this case, however I am simply calling self.prop.delay instead of self.delay along with changing the parent class. This way, as long as I delete the self.prop entity when deleting an instance of the TimerZone class, the loop shouldn't continue indefinitely.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Re: Looping a Timed Task in Many Objects

Postby iPlayer » Thu Nov 23, 2017 3:35 am

Welcome to the forums :)

I believe Invincible proposed using trigger_multiple's OnStartTouch output, which is possible to listen to using OnEntityOutput listener. This way you don't need to hook anything, and you'll also be able to utilize trigger's own filtering/flag system that would, for example, filter out all entities besides players.
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Looping a Timed Task in Many Objects

Postby L'In20Cible » Thu Nov 23, 2017 4:29 am

iPlayer is correct. Using the output would be preferred, I remember some issues with hooking the virtual touch methods. Tho I think it was only post ones? Can't remember.

As for inheriting from Entity, I think this would be the best approach. Simply because you can delegate their creation to an EntityDictionary which will cleanup for you on round/map ends. But all implementation are fine, go with the one you are the most comfortable with. :wink:
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Re: Looping a Timed Task in Many Objects

Postby iPlayer » Thu Nov 23, 2017 4:36 am

About those touch hook issues... Apart from removing the entity in a pre-hook and not cancelling the call (it's not touch-specific), there were issues with teleporting inside of the touch-related hooks, they are noted in the discussion of #157.
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 32 guests