dracaryS

python Python Timer like queue

6 posts in this topic

On 10/2/2019 at 1:32 AM, dracaryS said:

class QueuePython(object):
	def __init__(self):
		self.eventList=[]
	def __del__(self):
		if len(self.eventList) > 0:
			self.eventList.clear()
	def Process(self):
		if len(self.eventList) > 0:
			for j in xrange(len(self.eventList)):
				if app.GetTime() > self.eventList[j]["time"]:
					i = self.eventList[j]["func"]()
					if i == 0:
						self.eventList[j].clear()
					else:
						self.eventList[j]["time"] = app.GetTime()+i
	def AppendEvent(self,name,func,time):
		self.eventList.append({"name":str(name),"func":__mem_func__(func),"time":int(app.GetTime()+time)})

Thanks for release, the idea isn't bad, but there're some bad things. 
I'll show you the problems part and how can be improved, there're just advices, i hope you'll get them.

  • def __del__(self):
    	if len(self.eventList) > 0:
    		self.eventList.clear()

If you're using Python 2+ or Python 3.2 and below, you can't use the clear() method (allowed on 3.3+), also as i said in the second message you don't need to check the length of the list, already the clear() method doing that inside and there's no reason to put it to __del__ method, it will be called when the object is garbage collected. if you really want to use in future, something outside of this and want just to check the list if isn't empty, is enough to do it just with if some_list, like a normal boolean, there no need to check the length of the list if you don't use it in your code.

  • if len(self.eventList) > 0:
    	for j in xrange(len(self.eventList)):
    		[...]

You don't have to check the list if you already did a numeric range loop or iterator based loop.

Spoiler

self.eventList = []
''' example 1 '''
for i in xrange(len(self.eventList)):
    print (self.eventList[i])
''' example 2 '''
for event in self.eventList:
    print (event)
#<nothing will be printed>
  • app.GetTime() +  time

I would say to use app.GetGlobalTimeStamp() instead of app.GetTime(), if you teleport while the event is running, the event function will run after 10 seconds like. While app.GetGlobalTimeStamp() will run after the specific time, because is the server timestamp and is updated on each enter in game.

  • if i == 0:
    	self.eventList[j].clear()

I would put here an big exclamation, with this you creating 999999999 lines in syserr, what you do here is like:

While Process() function is called in OnUpdate, so, your condition trying to get the returned value from an specific function, what means the next update time or 0 to destroy the event/clear it. Everything's fine until you return 0 and event should be stopped yes? But there is a problem, you clear the specific dictionary of event and still remained in the list [{}], and the Process() function will take your self.eventList with the items included, the empty dictionaries from your events, and of course even if you've [{}, {}, {}], that doesn't mean your list is empty, have 3 items, so, the loop will trying to read an empty dictionary and you'll get key errors in each milisecond. The method which you need is to delete the dictionary itself from the list after the result value from the function is 0, like this:

Spoiler

del self.eventList[j]

_______________________________________

I wrote fast some self extensions,  if somebody is interested i'll do another updates in the next days.

  • You can use unlimited arguments on functions, now is using the apply method which returns the result of a function or class object called with supplied arguments,  with the old structure you could use just one argument.
  • You can lock/unlock an event for being processed, it's like a prevent in some actions, if the event is created and you want to do something, you should lock the event, do some actions then you can unlock it again and the process function will run where remained.
  • Delete an event instantly and force it to stop the process.
  • Adding return t.EXIT inside of the running function, will delete the event too.
  • Functions to check if an event exists or is locked or not.
  • Check if the function is a method type.
  • Delete the events with a properly method.
  • Using app.GetGlobalTimeStamp() now will give you the chance to run the event after teleport where timer remained instantly.
Spoiler

t = ui.Queue()
# ex1
t.AppendEvent(eventName='RUN', eventStartTime=0, eventFunc=self.Run)
# ex2
t.AppendEvent(eventName='RUN', eventStartTime=0, eventFunc=self.Run, eventFuncArgs=player.GetLevel())
# ex3
t.AppendEvent(eventName='RUN', eventStartTime=0, eventFunc=self.Run, eventFuncArgs=(player.GetLevel(), player.GetName()))
# ex4
t.AppendEvent('UPDATE', 0, self.Update, {'data' : (1, True, (14, 12), [5, 1], 'Corsair')})

# Others:
if t.GetEvent('RUN'):
	print ("The event exists.")

if t.GetIsLockedEvent('RUN'):
	print ("The event exists but is locked.")
    
t.LockEvent('RUN')
t.UnlockEvent('RUN')
t.DeleteEvent('RUN')

_______________________________________

The code:

class Queue(object):
	EXIT = 0

	def __init__(self):
		self.eventList = []
		self.eventLockedList = []

	def __del__(self):
		del self.eventList
		del self.eventLockedList

	def GetEvent(self, eventName):
		""" Get the event dictionary by specific name. """
		for event in self.eventList:
			if event['name'] == eventName:
				return event
		return None
		
	def GetIsLockedEvent(self, eventName):
		""" Get a boolean if a specific event is locked. """
		for event in self.eventLockedList:
			if event['name'] == eventName:
				return True
		return False
		
	def LockEvent(self, eventName):
		""" Lock a specific event by name for being processed. """
		event = self.GetEvent(eventName)
		if event and not event in self.eventLockedList:
			self.eventLockedList.append(event)
			
	def UnlockEvent(self, eventName):
		""" Unlock a specific event by name for being processed. """
		event = self.GetEvent(eventName)
		if event in self.eventLockedList:
			self.eventLockedList.remove(event)
			
	def DeleteEvent(self, eventName):
		""" Delete a specific event by name instantly. """
		event = self.GetEvent(eventName)
		if event:
			self.eventList.remove(event)
			
	def ResetTimeEvent(self, eventName):
		""" Reset time of a specific event by name. """
		event = self.GetEvent(eventName)
		if event:
			index = self.eventList.index(event)
			self.eventList[index] = app.GetGlobalTimeStamp()
		
	def AppendEvent(self, eventName, eventStartTime, eventFunc, eventFuncArgs = ()):
		""" Append a new event by specific arguments. """
		if not eventName or not isinstance(eventStartTime, int) or not callable(eventFunc):
			return

		if not hasattr(type(eventFuncArgs), '__iter__'):
			eventFuncArgs = tuple([eventFuncArgs])

		if self.GetEvent(eventName):
			self.DeleteEvent(eventName)

		self.eventList.append({'name' : eventName, 'function' : __mem_func__(eventFunc), 'arguments' : eventFuncArgs, 'run_next_time' : app.GetGlobalTimeStamp() + eventStartTime})

	def Process(self):
		""" Processing the events. """
		for index, event in enumerate(self.eventList):
			if event in self.eventLockedList:
				continue

			if app.GetGlobalTimeStamp() > event['run_next_time']:
				result = apply(event['function'], event['arguments'])
				if result in (None, self.EXIT):
					del self.eventList[index]
					continue

				event['run_next_time'] = app.GetGlobalTimeStamp() + result

PS: Don't quote this reply, will be updated.

Edited by VegaS™
updates
  • Like 5
  • Thanks 3

Share this post


Link to post
Share on other sites
3 godziny temu, Anix napisał:

@VegaS™ sometimes i cannot understand why u spend so much time to write the comments that nobody reads 🤔

To look somewhat smart :D I actually read most of them as he has good coding habits

Share this post


Link to post
Share on other sites
14 minutes ago, filipw1 said:

To look somewhat smart :D I actually read most of them as he has good coding habits

He knows aye, no doubt. i just like to bother him. 

Share this post


Link to post
Share on other sites

V1

  • You can use unlimited arguments on functions, now is using the apply method which returns the result of a function or class object called with supplied arguments,  with the old structure you could use just one argument.
  • You can lock/unlock an event for being processed, it's like a prevent in some actions, if the event is created and you want to do something, you should lock the event, do some actions then you can unlock it again and the process function will run where remained.
  • Delete an event instantly and force it to stop the process.
  • Adding return t.EXIT inside of the running function, will delete the event too.
  • Functions to check if an event exists or is locked or not.
  • Check if the function is a method type.
  • Delete the events with a properly method.
  • Using app.GetGlobalTimeStamp() now will give you the chance to run the event after teleport where timer remained instantly.

V2

  • Fixed non-returning time for processing, if the specific event function has no value from returning, it runs continuously.
  • Fixed the check if an event exist, now will be replaced with the new one.
  • Removed types library (i heard that some people don't have it) and using builtin functions, instead of types.MethodType now we're using callable(object), which check if the event function can be called, now you can insert classes and others callable methods, not just simple functions.
  • Added a reset time event function.

Next update: (when i'll have some free time again)

  • Insert a new type of event, which you can run an event by specific counter like:
t.AppendEvent(eventName='RUN', eventStartTime=5, eventRunCount=10, eventFunc=self.Run, eventFuncArgs=player.GetLevel())

The following things will happen:

  • The function Run(args), will start to run in 5 seconds for 10 times.

PS: Check my first reply for code.

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.