Performance issue!!!

All other Source.Python topics and issues.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Performance issue!!!

Postby velocity » Sun Oct 07, 2018 3:13 pm

I am having issues with running code inside run_command without affecting server performance. After all, I have tried to make a GameThread with a repeater inside to replace this, but it doesn't really improve the performance. In this SP code example, I'm trying to find the nearest player. In SourcePython I generally have problems with running code inside a tick listener or a repeater (anything that repeats a code over and over again) without making the server go crazy. It most likely has something to do with Player base class, because when I try to access player properties, such as .teleport, .origin etc., I have to be very careful how I go about it.

My end goal is to re-create my old EventScripts plugin that generally ran with many gamethread.delayedname(0.01, with heavy code without affecting the server at all. If you look at my old code from my Github: https://github.com/Velocity-plus/css-tr ... kztimer.py at line 825 auto_stuck(userid) you will see this is some heavy code that ran without problem with more than 32 players. Also, notice that this is one file of many, for example, I have another file within my old plugin https://github.com/Velocity-plus/css-tr ... r/timer.py that have a gamethread loop for every player with a heavy code as well. When I get near recreating this in SourcePython it can easily lag. I wonder what is going on.

To give another example, if you look at the code in KZTimer from SourceMod (particularly line 847 (OnPlayerRunCmd) https://bitbucket.org/kztimerglobalteam ... oks.sp-847 I don't see myself being available to recreate this in SourcePython in its current state without making the server crash because of performance problems.

I have posted an example code that makes the server lag when the player slots is above 12-20 (Can't remember exact number when it goes nuts).

Game: CS:GO, OS: Windows

Syntax: Select all

player_instances = PlayerDictionary()

@EntityPreHook(EntityCondition.is_player, 'run_command')
def player_run_command(args):
player = player_instances[index_from_pointer(args[0])]
index = player.index

if not player.dead or player.team_index < 2:
target = closeplayer(player, radius=200)


def closeplayer(player, radius):
for other in player_instances.values():
if not player.index == other.index and not player.dead and not other.dead:
dist = player.origin.get_distance(other.origin)
if player.origin.get_distance(other.origin) <= radius:
return (dist, other)

return (10000, None)
Last edited by velocity on Sat Oct 13, 2018 12:11 am, edited 16 times in total.
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Performance issue!!!

Postby Ayuto » Sun Oct 07, 2018 4:33 pm

Code?
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Mon Oct 08, 2018 11:03 pm

Yeah sorry for the vague explaination. I have updated the topic. I have been thinking about how to explain it. Please take a look now.
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Performance issue!!!

Postby Ayuto » Tue Oct 09, 2018 5:06 am

Thanks for the updated info. One more question: what's your SP version? I guess it lags, because of accessing the dead-property.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Tue Oct 09, 2018 10:27 am

Always the newest version. I'm not sure what you mean by the dead-property.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sat Oct 13, 2018 12:11 am

Is there any fix to this?
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: Performance issue!!!

Postby VinciT » Sat Oct 13, 2018 2:22 am

If Ayuto's guess about the dead property is right, you could try using the player.life_state instead (SourceMod does it this way).

Syntax: Select all

from players.constants import LifeState

if player.life_state == LifeState.ALIVE:
print('This player is alive!')

I don't know if this would improve the performance though, maybe the life_state (m_lifeState) property needs to be moved to C++?
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Performance issue!!!

Postby Ayuto » Sat Oct 13, 2018 5:05 am

I will take a look at it when I get home next week.
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: Performance issue!!!

Postby satoon101 » Sat Oct 13, 2018 12:14 pm

I'd add that you are retrieving the player's index, dead, and origin every single time during that loop. I would recommend grabbing each of them once, prior to the loop, instead.

Also, is there any reason you are using this in a run_command hook? Not knowing what you are using this for, it's difficult to know if maybe there's a better way to achieve your overall goal.
Image
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sat Oct 13, 2018 3:04 pm

Sure you can do it in 1000 ways, or the initial problem can be solved. It shouldn't be lagging by receiving the origin/dead/get_distance etc.. every tick or evey 2nd tick etc.. It doesn't matter when more players join.

This makes SourcePython worse optimized than EventScripts. This literally gives 0% freedom, if I have to post everything I want to accomplish with SourcePython because my code is not perfect and a better suggestion could be posted.

@satoon101 I appreciate that you want to help find a different solution to 'channel' the issue, but I would like to be available to do these things as you easily could do in ES/SM with no problems. I personally want to help combat the problem, but I do not know how to sadly.

What I'm trying to accomplish can be read on https://github.com/Velocity-plus/css-tr ... kztimer.py at line 825 auto_stuck(userid)
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Performance issue!!!

Postby L'In20Cible » Sat Oct 13, 2018 3:46 pm

velocity wrote:Sure you can do it in 1000 ways, or the initial problem can be solved. It shouldn't be lagging by receiving the origin/dead/get_distance etc.. every tick or evey 2nd tick etc.. It doesn't matter when more players join.

It does matter. In the code you linked, your function is executed every 0.1 second. For example, on a 100 tick server, your function would be executed 10 times per second. When you use a run_command hook, your function is executed each frame for each player. So again, for example, on a 100 tick server with 20 players, your code would be executed 100 * 20 = 2000 times per second.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sat Oct 13, 2018 7:35 pm

Yes and as I mentioned in my original post, I have another file timer.py which has loop at 0.001 seconds that is every tick for every player. This involves check if a player is inside multiple zones and if the player is dead, if his partner is inside the zone and so much more. Also, I mentioned that this doesn't lag in SourceMod or EventScripts which I feel like you are ignoring at this point.


File 1 AntiCheat: https://github.com/Velocity-plus/css-tr ... ticheat.py
gamethread.delayedname(0.01, "server_loop", Serverloop) (Involves checking player grounded, dead, velocity, vecmath, list goes on

File 2 LjStats https://github.com/Velocity-plus/css-trikztimer/blob/master/trikztimer/plugins/ljstats/ljstats.py
Notice a new gamethread is created for every player (Involves checking player grounded, dead, velocity, vecmath, a lot of calculations etc etc.
gamethread.delayedname(0.001, 'Check_Runboost_%s' % userid, Check_Runboost, args=(userid))
gamethread.delayedname(0.001, 'Check_Ground_%s' % userid, Check_When_Grounded, args=(userid, bhop, runboost))
gamethread.delayedname(0.001, 'Set_Location_%s' % userid, Set_Location, args=(userid))

File 3 Spectate https://github.com/Velocity-plus/css-tr ... pectate.py
gamethread.delayedname(0.1, ('spectarget_loop'), loop)

File 4 Timer https://github.com/Velocity-plus/css-tr ... kztimer.py
gamethread.delayedname(0.1, 'drawbox_%s' % int(loop_number), drawbox,
args=(userid, loop_number, start_point, type, end_point))
gamethread.delayedname(0.1, 'CheckZone_%s' % userid, CheckZone, args=(userid))

File 4 AutoGhost https://github.com/Velocity-plus/css-tr ... kztimer.py
gamethread.delayedname(0.01, 'esp_%s' % userid, esp, args=(userid))
gamethread.delayedname(0.1, 'auto_stuck_%s' % userid, auto_stuck, args=(userid))


Just to sum it up, first view the files see how much is going on, second THIS DOES BASICALLY everything you can think of. All this ran in harmony. It is not true what you are saying, I'm sorry to say that.
Last edited by velocity on Sat Oct 13, 2018 7:45 pm, edited 5 times in total.
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: Performance issue!!!

Postby satoon101 » Sat Oct 13, 2018 7:41 pm

L'In20Cible wrote:
velocity wrote:Sure you can do it in 1000 ways, or the initial problem can be solved. It shouldn't be lagging by receiving the origin/dead/get_distance etc.. every tick or evey 2nd tick etc.. It doesn't matter when more players join.

It does matter. In the code you linked, your function is executed every 0.1 second. For example, on a 100 tick server, your function would be executed 10 times per second. When you use a run_command hook, your function is executed each frame for each player. So again, for example, on a 100 tick server with 20 players, your code would be executed 100 * 20 = 2000 times per second.

This is exactly why I asked. If you just did a 1-to-1 conversion from your ES script to SP, I guarantee you would not be seeing performance issues. To me, this is not a case of SP's performance being inadequate, but rather the inefficiency of your implementation. There are certainly times when using a run_command hook makes sense, but I don't believe your use-case is one of them. If you want to do a 0.1 delay, SP has that capability.

Also, your SP code is different in that it just finds a player within a certain radius, not necessarily the 'closest' player. If you truly just want to know if 'any' other player happens to be within that radius, once you find one, store it in a dictionary, so that the next time you need to know, you can just check to see if that specific player is still alive and within that radius. And, since you're doing it for each player, technically you at that point know not only that player 2 is within the radius of player 1, but that player 1 is within the radius of player 2. So, when you get to the second player, you also do not need to loop through all players to find out if there is a player within the radius, because you already know that there is.

Here is a great video I saw recently that I believe showcases exactly why you should always look for the most efficient way to write your code:
Image
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sat Oct 13, 2018 7:46 pm

satoon101 It is not true. I currently run everything in a GameThread with a repeater it doesn't help. I'm telling you that code inside run_command or a repeater doesn't work well. In case you don't see my previous comment you answered very quickly I have linked everything.
Last edited by velocity on Sun Oct 14, 2018 12:14 am, edited 1 time in total.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sat Oct 13, 2018 7:52 pm

I will follow your suggestion and convert it to SP and see if I have issues, to prove my point once again with the ES Emulator. I read through your comment and yes it is totally correct that the function can be optimized but my point is I think that SourcePython should be available to handle this and if you want please let me know a more optimized way to do and I will use it right away (code example please ;) ). Nonetheless, I just want to create awareness that I could do stuff in ES that is not possible in SP (performance wise) ATLEAST it appears that way.
Last edited by velocity on Sat Oct 13, 2018 11:54 pm, edited 1 time in total.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sat Oct 13, 2018 11:26 pm

So I did a 1:1 conversion with ES Emulator this is my results:

Test 1
First of all, I want to note that this test was done by running this code in the ES Emulator https://github.com/Velocity-plus/css-tr ... kztimer.py which includes the auto_stuck function.

So I started out with putting 20 bots in the server with no loaded plugins. Here is the graph:


Now I loaded the plugin trikztimer.py with 20 bots in the server (at 0.1 gamethread delay ofcourse). The server became unplayable you only see a small cut of the graph because it was moving so slowly


Here is the exact code I used in the ES Emulator:

Syntax: Select all

import es
import playerlib
import popuplib
import os
import pickle
import vecmath
import effectlib
import gamethread
import time

client = {}
location = {}

times = 0

current_map = es.ServerVar('eventscripts_currentmap')

timer_plugin = True


class QueueExtendTrikz(object):
def __init__(self):
self.primary_color = "#245,0,61"
self.secondary_color = "None"

def Validate(self, userid, message=1):
steamid = es.getplayersteamid(userid)
if steamid not in client:
client[steamid] = {'auto_switch': "On",
'auto_flash': "On",
'auto_stuck': "On",
'stop_speed': "Off",
'save_angles': "Off",
'view_angles': False,
'auto_jump': "On",
'check_stuck': 1,
'strafe_sync': 'Off',
'esp': "Off",
'partner': 'Nobody',
'player_state': "Block",
'time_elapsed': 0,
'snapshot_1': (0, 0, 0),
'snapshot_2': (0, 0, 0),
'pratice_mode': 0,
'time': 0,
'ignored': [],
'tp_accept': 0,
'tp_location': None,
'tp_userid': None,
'x': 1,
'x_mh': 1,
'bot_style': "Normal",
'bot_firstboost': "ML",
'bot_jump': 'Yes',
'bot_crouch': "No",
'best_x': 1,
'last_k': 0,
'spam': 0,
'view_angle': (0, 0, 0),
'view_angle_2': (0, 0, 0),
'ignore_list': [],
'save_speed': (0, 0, 0),
'save_speed_stack': 0,
'save_speed_2': 0,
'save_speed_stack_2': 0}
if message == 1:
es.tell(userid,
'#124,252,0[ Trikz] #snowCorrupt data has been found and has been restored!')
else:
if message == 1:
es.tell(userid,
'#124,252,0[ Trikz] #snowThis is a validation check. If you get this message you are all set.')

def Intro_menu(self, userid):
info = popuplib.create('intro_menu')
info.addline('Queue Plugin')
info.addline('=> Running [Queue] 0.9.8v')
info.addline(' ')
info.addline('1. Commands')
info.addline('2. Menus')
info.addline('3. Credits')
info.addline('4. Modules')
info.addline(' ')
info.addline('0 Exit')
info.enablekeys = "08"
info.unsend(userid)
info.send(userid)
info.delete()
info.menuselect = None


QueueAPI = QueueExtendTrikz()


def load():
es.set('eventscripts_noisy', 1)
global client
for userid in es.getUseridList():
QueueAPI.Validate(userid)
gamethread.cancelDelayed("antispam")
antispam()


def unload():
es.set('eventscripts_noisy', 0)
global client
client = {}


def player_activate(ev):
userid = ev["userid"]
QueueAPI.Validate(userid, 0)

def iequal(a, b):
try:
return a.upper() == b.upper()
except AttributeError:
return a == b


def get_usp(userid, text, steamid, name):
player = playerlib.getPlayer(userid)
if not player.isdead:
if not client[steamid]["spam"] > 3:
es.tell(userid, '#124,252,0[ Trikz] #snowYou have received an #yellowUSP.')
es.server.queuecmd('es_xgive %s weapon_usp' % userid)
client[steamid]["spam"] += 1
else:
es.tell(userid, '#124,252,0[ Trikz] #snowStop spamming the command #yellow%s' % text)


def get_glock(userid, text, steamid, name):
player = playerlib.getPlayer(userid)
if not player.isdead:
if not client[steamid]["spam"] > 3:
es.tell(userid, '#124,252,0[ Trikz] #snowYou have received an #yellowGlock.')
es.server.queuecmd('es_xgive %s weapon_glock' % userid)
client[steamid]["spam"] += 1
else:
es.tell(userid, '#124,252,0[ Trikz] #snowStop spamming the command #yellow%s' % text)


def change_spec(userid):
es.server.queuecmd('es_xchangeteam %i 1' % int(userid))
es.tell(userid, "#124,252,0[ Trikz] #snowYou've been sent to #yellowspectator!")


def antispam():
for userid in es.getUseridList():
steamid = es.getplayersteamid(userid)
if steamid not in client:
QueueAPI.Validate(userid, 0)
client[steamid]["spam"] = 0
gamethread.delayedname(30, "spam", antispam)


def player_spawn(ev):
userid = ev['userid']
player = playerlib.getPlayer(userid)
steamid = es.getplayersteamid(userid)
interp = es.getclientvar(userid, 'cl_interp')

if not player.isdead:
es.server.queuecmd('es_xgive %s weapon_flashbang' % userid)
es.server.queuecmd('es_xgive %s weapon_flashbang' % userid)
gamethread.cancelDelayed("auto_stuck_%s" % userid)
auto_stuck(userid)
QueueAPI.Validate(userid, 0)
if not interp == "0":
es.tell(userid,
"#124,252,0[ Trikz] #snowYou lerp is not optimal, do #yellow'cl_interp 0' #snowin console")


def auto_switch(userid):
es.server.queuecmd('es_sexec %s use weapon_knife' % userid)
es.server.queuecmd('es_sexec %s use weapon_flashbang' % userid)


def weapon_fire(ev):
userid = ev["userid"]
steamid = es.getplayersteamid(userid)
player = playerlib.getPlayer(userid)
if ev['weapon'] == 'flashbang':
if client[steamid]["auto_flash"] == "On":
if player.getFB() < 10:
player.setFB(30)

if client[steamid]['auto_switch'] == "On":
gamethread.delayed(0.10, auto_switch, userid)


def trikz_menu(userid, text=None, steamid=None, name=None):
QueueAPI.Validate(userid, 0)
steamid = es.getplayersteamid(userid)
info = popuplib.create('trikz_menu')
info.addline('[ DreamAboutNow ]')
info.addline(' ')
if client[steamid]["auto_switch"] == "On":
info.addline('->1. Auto Switch: On')
else:
info.addline('->1. Auto Switch: Off')

if client[steamid]["auto_jump"] == "On":
info.addline('->2. Auto Jump: On')
else:
info.addline('->2. Auto Jump: Off')
if client[steamid]["auto_stuck"] == "On":
info.addline('->3. Anti Stuck: On')
else:
info.addline('->3. Anti Stuck: Off')

if client[steamid]["player_state"] == "Ghost":

info.addline('->4. Blocking: Off')
else:
info.addline('->4. Blocking: On')
info.addline(' ')
info.addline('->5. Checkpoints')
info.addline(' ')
info.addline('0. Exit')
info.enablekeys = "12345680"
info.unsend(userid)
info.send(userid)
info.delete()
info.menuselect = trikz_menu_select


def commands(userid):
steamid = es.getplayersteamid(userid)
QueueAPI.Validate(userid, 0)
player = playerlib.getPlayer(userid)
info = popuplib.create('commands')
info.addline('<!commands list> ')
info.addline('Timer Commands:')
info.addline(' ')
info.addline('!r')
info.addline('!b <number>')
info.addline('!end')
info.addline('!bend <number>')
info.addline('!wr ')
info.addline('!bwr ')
info.addline('!rank <name|steamid>')
info.addline('!crank <name|steamid> ')
info.addline('!top')
info.addline('!ctop <country name>')
info.addline('!partner | !p')
info.addline('!unpartner')
info.addline('!tags')
info.addline('!points <map name>')
info.addline('!mode | !style | (!sw,!n,!hsw, !w)')
info.addline('!hud | !settings')
info.addline('!stop | Stops your timer')
info.addline(' ')
info.addline('Server Commands:')
info.addline('!retry, !tp, !cp, !trikz, !lj, !ip')
info.addline('!spec | !spectate')
info.addline(' ')
info.addline('0. Exit')
info.enablekeys = "123456780"
info.unsend(userid)
info.send(userid)
info.delete()
info.menuselect = None


def trikz_menu_select(userid, choice, popupid):
steamid = es.getplayersteamid(userid)
player = playerlib.getPlayer(userid)
timer = es.import_addon("queue_timer/plugins/timer")
"""
if int(choice) == 1:
if player.getFB() in (0, 1):
client[steamid]['auto_flash'] = "On"
es.tell(userid, '#124,252,0[ Trikz] #snowYou got a #yellowrefill #245,61,0flash')
trikz_menu(userid)
if int(choice) == 1:
if not client[steamid]['auto_flash'] == "On":
client[steamid]['auto_flash'] = "On"
auto_switch(userid)
es.tell(userid, '#124,252,0[ Trikz] #245,61,0AutoFlash#snow is now #yellowON')
else:
client[steamid]['auto_flash'] = "Off"
auto_switch(userid)
es.tell(userid, '#124,252,0[ Trikz] #245,61,0AutoFlash#snow is now #yellowOFF')
trikz_menu(userid)
"""
if int(choice) == 1:
if not client[steamid]['auto_switch'] == "On":
client[steamid]['auto_switch'] = "On"
es.tell(userid, '#124,252,0[ Trikz] #245,61,0AutoSwitch#snow is now #yellowON')
else:
client[steamid]['auto_switch'] = "Off"
es.tell(userid, '#124,252,0[ Trikz] #245,61,0AutoSwitch#snow is now #yellowOFF')
trikz_menu(userid)

if int(choice) == 2:
if not client[steamid]['auto_jump'] == "On":
client[steamid]['auto_jump'] = "On"
es.cexec(userid, 'sm_%s' % "autojump")

else:
client[steamid]['auto_jump'] = "Off"
es.cexec(userid, 'sm_%s' % "autojump")
trikz_menu(userid)

if int(choice) == 3:

if client[steamid]['auto_stuck'] == "Off":
es.tell(userid,
'#124,252,0[Trikz] #245,61,0Anti-Stuck #snowis now #yellowON')
client[steamid]['auto_stuck'] = "On"
gamethread.cancelDelayed("auto_stuck_%s" % userid)
auto_stuck(userid)
else:
es.tell(userid,
'#124,252,0[ Trikz] #245,61,0Anti-Stuck #snowis now #yellowOFF #255,0,0(NOT Recommended)')
client[steamid]['auto_stuck'] = "Off"
gamethread.cancelDelayed("auto_stuck_%s" % userid)
trikz_menu(userid)

if int(choice) == 4:
toggle(userid)
trikz_menu(userid)

if int(choice) == 5:
cp_menu(userid)

if int(choice) == 6:
es.cexec(userid, 'sm_delay')


def development(userid):
steamid = es.getplayersteamid(userid)
QueueAPI.Validate(userid, 0)
timer = es.import_addon("queue_timer/plugins/timer")
player = playerlib.getPlayer(userid)
timer.player[steamid]["disabled"] = 1
info = popuplib.create('development')
info.addline('Development features')
info.addline('---------------------')
if client[steamid]["esp"] == "Off":
info.addline('->1. ESP [Off]')
else:
info.addline('->1. ESP [On]')
if client[steamid]["strafe_sync"] == "Off":
info.addline('->2. Strafe Re-Sync [Off]')
else:
info.addline('->2. Strafe Re-Sync [On]')
info.addline('----------------------')
info.addline('0. Exit')
info.enablekeys = "123456780"
info.unsend(userid)
info.send(userid)
info.delete()
info.menuselect = development_select


def development_select(userid, choice, popupid):
steamid = es.getplayersteamid(userid)
player = playerlib.getPlayer(userid)
timer = es.import_addon("queue_timer/plugins/timer")
if int(choice) == 1:
if client[steamid]["esp"] == "Off":
es.tell(userid,
'#245,0,61[Development] #245,61,0ESP #snowis now #yellowOn')
client[steamid]["esp"] = "On"
gamethread.cancelDelayed("esp_%s" % userid)
esp(userid)
else:
es.tell(userid,
'#245,0,61[Development] #245,61,0ESP #snowis now #yellowOff')
client[steamid]["esp"] = "Off"
gamethread.cancelDelayed("esp_%s" % userid)

if int(choice) == 2:

if client[steamid]['strafe_sync'] == "Off":
if timer.CheckPartner(userid):
timer_id = timer.player[steamid]["timer_id"]
state = timer.timer[timer_id]["state"]
if state == 2:
return
else:
es.tell(userid,
'#124,252,0[ Trikz] #245,61,0Perfect Strafe synchronization #snowis now #yellowON')
client[steamid]['strafe_sync'] = "On"
else:
es.tell(userid,
'#124,252,0[ Trikz] #245,61,0Perfect Strafe synchronization #snowis now #yellowON')
client[steamid]['strafe_sync'] = "On"

else:
es.tell(userid,
'#124,252,0[ Trikz] #245,61,0Perfect Strafe synchronization #snowis now #yellowOFF')
client[steamid]['strafe_sync'] = "Off"
if int(choice) in (1, 2, 3, 4, 5, 6):
development(userid)


def esp(userid):
if es.exists("userid", userid):
steamid = es.getplayersteamid(userid)
player = playerlib.getPlayer(userid)
if not player.isdead:
if client[steamid]["auto_flash"] == "On":
if player.getFB() < 2:
es.server.queuecmd('es_xgive %s weapon_flashbang' % userid)
# es.server.queuecmd('es_xgive %s weapon_flashbang' % userid)
# player.setFB(30)

if client[steamid]['auto_stuck'] == "On":
alive = es.getlivingplayercount()
if alive > 1:
location = es.getplayerlocation(userid)
PosBoxUp = (location[0] + 64, location[1] + 64, location[2] + 64)
PosBoxDown = (location[0] - 64, location[1] - 64, location[2])

player = playerlib.getPlayer(userid)
steamid = es.getplayersteamid(userid)

target = playerlib.getPlayer(player.getClosestPlayer(team=None)[1])
player_target = playerlib.getPlayer(target)

target_pos = es.getplayerlocation(player.getClosestPlayer(team=None)[1]) # Tuple
player_pos = es.getplayerlocation(userid)

target_x = float(target_pos[0])
target_y = float(target_pos[1])
target_z = float(target_pos[2])

player_x = float(player_pos[0])
player_y = float(player_pos[1])
player_z = float(player_pos[2])

if not player.isdead:
if abs(-target_z - (-player_z)) < 61 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 128 and abs(-target_y - (-player_y)) < 128:
drawbox(userid, userid, PosBoxDown, "Noob", PosBoxUp)
else:

drawbox(userid, userid, PosBoxDown, "extra", PosBoxUp)

gamethread.delayedname(0.01, 'esp_%s' % userid, esp, args=(userid))


def drawbox(userid, loop_number, start_point, type, end_point=None):
if not end_point:
effectlib.drawBox(start_point, es.getplayerlocation(userid), 'materials/sprites/laser.vmt',
'materials/sprites/laser.vmt', 2, '3', '3', 255, 255, 255, '255', '10', '0', '0', '0', '0')
else:
if type == "end":

effectlib.drawBox(start_point, end_point, 'materials/sprites/laser.vmt', 'materials/sprites/laser.vmt', 2,
'3', '3', 255, 0, 0, '255', '10', '0', '0', '0', '0')
elif type == "extra":
effectlib.drawBox(start_point, end_point, 'materials/sprites/laser.vmt', 'materials/sprites/laser.vmt', 0.1,
'3', '3', 255, 0, 0, '255', '10', '0', '0', '0', '0')
else:
effectlib.drawBox(start_point, end_point, 'materials/sprites/laser.vmt', 'materials/sprites/laser.vmt', 0.1,
'3', '3', 0, 255, 0, '255', '10', '0', '0', '0', '0')

def cp_menu(userid):
steamid = es.getplayersteamid(userid)
timer = es.import_addon("queue_timer/plugins/timer")
QueueAPI.Validate(userid, 0)
info = popuplib.create('checkpoint_menu')
info.addline('Checkpoints')
info.addline(' ')
info.addline('->1. Save CP 1')
info.addline('->2. Teleport to CP 1 ')
info.addline(' ')
info.addline('->3. Save CP 2')
info.addline('->4. Teleport to CP 2')
info.addline(' ')
if client[steamid]["stop_speed"] == "On":
info.addline('->5. Save speed: On')
else:
info.addline('->5. Save speed: Off')
if client[steamid]["save_angles"] == "On":
info.addline('->6. Save angles: On')
else:
info.addline('->6. Save angles: Off')
info.addline(' ')
if timer.CheckPartner(userid):
info.addline('Disabled during timer!')
info.addline(' ')
info.addline('->8. Back')
info.addline('0 Exit')
info.enablekeys = "12345608"
info.unsend(userid)
info.send(userid)
info.delete()
info.menuselect = cp_menu_select


def set_boost(userid, cp):
steamid = es.getplayersteamid(userid)
if cp == 0:
client[steamid]["save_speed_stack"] += 1
myNewVector2 = es.createvectorstring(client[steamid]['save_speed'][0], client[steamid]['save_speed'][1],
client[steamid]['save_speed'][2])
# es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector)
es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector2)
if client[steamid]["save_speed_stack"] > 1:
es.tell(userid,
"#124,252,0[ Trikz] #245,0,61Speed has now been stacked (multiplier X%s" %
client[steamid]["save_speed_stack"])
client[steamid]["save_speed_stack"] -= 1
else:
client[steamid]["save_speed_stack_2"] += 1
myNewVector2 = es.createvectorstring(client[steamid]['save_speed_2'][0], client[steamid]['save_speed_2'][1],
client[steamid]['save_speed_2'][2])
# es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector)
es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector2)
if client[steamid]["save_speed_stack_2"] > 1:
es.tell(userid,
"#124,252,0[ Trikz] #245,0,61Speed has now been stacked (multiplier X%s" %
client[steamid]["save_speed_stack"])
client[steamid]["save_speed_stack_2"] -= 1


def cp_menu_select(userid, choice, popupid):
steamid = es.getplayersteamid(userid)
velocity_x = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[0]'))
velocity_y = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[1]'))
velocity_z = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[2]'))
timer = es.import_addon("queue_timer/plugins/timer")
if timer.CheckPartner(userid):
timer_id = timer.player[steamid]["timer_id"]
state = timer.timer[timer_id]["state"]

if int(choice) == 1:
if timer.CheckPartner(userid):
cp_menu(userid)
else:
player = playerlib.getPlayer(userid)
client[steamid]["view_angles"] = player.getViewAngle()
view_angles = client[steamid]["view_angles"]
client[steamid]['snapshot_1'] = es.getplayerlocation(userid)
client[steamid]['save_speed'] = (velocity_x, velocity_y, velocity_z)
es.tell(userid,
'#124,252,0[ Trikz] #snowYou have saved your #yellow1st #245,61,0checkpoint')
cp_menu(userid)

if int(choice) == 2:
if timer.CheckPartner(userid):
cp_menu(userid)
else:
if client[steamid]['snapshot_1'] != (0, 0, 0):
current_location = es.getplayerlocation(userid)
location = client[steamid]['snapshot_1']
distance = vecmath.distance(current_location, location)
player = playerlib.getPlayer(userid)
view_angles = client[steamid]["view_angles"]
timer.TimerSolo_Stop(userid)
client[steamid]["time"] = time.time()
player.setColor(255, 255, 255, 255)
player.noblock(0)
if client[steamid]["stop_speed"] == "On":
es.server.queuecmd('es_setpos %s %s %s %s' % (userid, location[0], location[1], location[2]))

velocity_x = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[0]'))
velocity_y = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[1]'))
velocity_z = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[2]'))
myNewVector2 = es.createvectorstring(-velocity_x, -velocity_y, -velocity_z)

es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector2)

gamethread.delayed(0.025, set_boost, args=(userid, 0))


else:
es.server.queuecmd('es_setpos %s %s %s %s' % (userid, location[0], location[1], location[2]))
velocity_x = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[0]'))
velocity_y = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[1]'))
velocity_z = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[2]'))
myNewVector2 = es.createvectorstring(-velocity_x, -velocity_y, -velocity_z)
es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector2)

if client[steamid]["save_angles"] == "On":
es.server.queuecmd('es_xsetang %s %s %s %s' % (
userid, str(view_angles[0]), str(view_angles[1]), str(view_angles[2])))

else:
es.tell(userid, '#124,252,0[ Trikz] #245,0,61You have not set your 1st checkpoint.')
cp_menu(userid)

if int(choice) == 3:
if timer.CheckPartner(userid):
cp_menu(userid)
else:
player = playerlib.getPlayer(userid)
client[steamid]["view_angles_2"] = player.getViewAngle()
client[steamid]['snapshot_2'] = es.getplayerlocation(userid)
client[steamid]['save_speed_2'] = (velocity_x, velocity_y, velocity_z)
es.tell(userid,
'#124,252,0[ Trikz] #snowYou have saved your #yellow2nd #245,61,0checkpoint')
cp_menu(userid)

if int(choice) == 4:
if timer.CheckPartner(userid):
cp_menu(userid)
else:
if client[steamid]['snapshot_2'] != (0, 0, 0):
current_location = es.getplayerlocation(userid)
location = client[steamid]['snapshot_2']
distance = vecmath.distance(current_location, location)
player = playerlib.getPlayer(userid)
view_angles = client[steamid]["view_angles_2"]
client[steamid]["time"] = time.time()
timer.TimerSolo_Stop(userid)
player.setColor(255, 255, 255, 255)
player.noblock(0)
if client[steamid]["stop_speed"] == "On":
es.server.queuecmd('es_setpos %s %s %s %s' % (userid, location[0], location[1], location[2]))

velocity_x = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[0]'))
velocity_y = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[1]'))
velocity_z = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[2]'))
myNewVector2 = es.createvectorstring(-velocity_x, -velocity_y, -velocity_z)

es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector2)

gamethread.delayed(0.025, set_boost, args=(userid, 1))
else:

es.server.queuecmd('es_setpos %s %s %s %s' % (userid, location[0], location[1], location[2]))

velocity_x = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[0]'))
velocity_y = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[1]'))
velocity_z = float(es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[2]'))
myNewVector2 = es.createvectorstring(-velocity_x, -velocity_y, -velocity_z)
es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector2)

if client[steamid]["save_angles"] == "On":
es.server.insertcmd('es_xsetang %s %s %s %s' % (
userid, str(view_angles[0]), str(view_angles[1]), str(view_angles[2])))

else:
es.tell(userid, '#124,252,0[ Trikz] #245,0,61You have not set your 2nd checkpoint.')
cp_menu(userid)

if int(choice) == 5:
if client[steamid]['stop_speed'] == "Off":
es.tell(userid,
'#124,252,0[ Trikz] #snowYour speed will now be restored when teleporting!')
client[steamid]['stop_speed'] = "On"
cp_menu(userid)
else:
es.tell(userid, '#124,252,0[ Trikz] #snowYou will not save speed anymore!')
client[steamid]['stop_speed'] = "Off"
cp_menu(userid)

if int(choice) == 6:
if client[steamid]['save_angles'] == "Off":
es.tell(userid, '#124,252,0[ Trikz] #snowYou will now save ur angles!')
client[steamid]['save_angles'] = "On"
cp_menu(userid)
else:
es.tell(userid, '#124,252,0[ Trikz] #snowYou angles wont be saved!')
client[steamid]['save_angles'] = "Off"
cp_menu(userid)

if int(choice) == 8:
trikz_menu(userid)


def toggle(userid):
steamid = es.getplayersteamid(userid)
player = playerlib.getPlayer(userid)
if not player.getNoBlock():
es.setplayerprop(userid,
"CCSPlayer.baseclass.baseclass.baseclass.baseclass.baseclass.baseclass.m_CollisionGroup", 2)

player.setColor(255, 255, 255, 100)
es.tell(userid, '#124,252,0[ Trikz] #245,61,0Blocking#snow is now #yellowOFF')
client[steamid]["player_state"] = "Ghost"
else:
es.tell(userid, '#124,252,0[ Trikz] #245,61,0Blocking#snow is now #yellowON')
es.setplayerprop(userid,
"CCSPlayer.baseclass.baseclass.baseclass.baseclass.baseclass.baseclass.m_CollisionGroup", 0)
player.setColor(255, 255, 255, 255)
client[steamid]["player_state"] = "Block"


def auto_stuck(userid):
# Player X-X width = 64.0625 units
# Player Y-Y width = 64.2360839844
# Player height = 62.03125 units
steamid = es.getplayersteamid(userid)
player = playerlib.getPlayer(userid)
QueueAPI.Validate(userid, 0)
if not player.isdead:
if client[steamid]["auto_flash"] == "On":
if player.getFB() == 0:
es.server.queuecmd('es_give %s weapon_flashbang' % userid)
es.server.queuecmd('es_give %s weapon_flashbang' % userid)
# player.setFB(100)

if client[steamid]['auto_stuck'] == "On":
alive = len(playerlib.getUseridList('#alive'))
es.tell(userid, ' Loop 3 Alive %s' % alive)
if alive > 1:
player = playerlib.getPlayer(userid)
steamid = es.getplayersteamid(userid)

target = playerlib.getPlayer(player.getClosestPlayer()[1])

if not target == None:

player_target = playerlib.getPlayer(target)
target_steamid = player_target.steamid

target_pos = es.getplayerlocation(player.getClosestPlayer()[1]) # Tuple
player_pos = es.getplayerlocation(userid)

target_x = float(target_pos[0])
target_y = float(target_pos[1])
target_z = float(target_pos[2])

player_x = float(player_pos[0])
player_y = float(player_pos[1])
player_z = float(player_pos[2])

if not player.isdead:
if abs(-target_z - (-player_z)) < 61 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 32 and abs(-target_y - (
-player_y)) < 32 and not player_target.isDucked() and not player.isDucked():
player.noblock(1)
player_target.noblock(1)
player.setColor(255, 255, 255, 100)
player_target.setColor(255, 255, 255, 100)
es.centertell(userid, 'Anti-Stuck')

elif abs(-target_z - (-player_z)) < 45 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 32 and abs(-target_y - (
-player_y)) < 32 and player_target.isDucked() and not player.isDucked():
player.noblock(1)
player_target.noblock(1)
player.setColor(255, 255, 255, 100)
player_target.setColor(255, 255, 255, 100)
es.centertell(userid, 'Anti-Stuck')

elif abs(-target_z - (-player_z)) < 45 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 32 and abs(-target_y - (
-player_y)) < 32 and not player_target.isDucked() and player.isDucked():

player.noblock(1)
player_target.noblock(1)
player.setColor(255, 255, 255, 100)
player_target.setColor(255, 255, 255, 100)
es.centertell(userid, 'Anti-Stuck')

elif abs(-target_z - (-player_z)) < 45 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 32 and abs(-target_y - (
-player_y)) < 32 and player_target.isDucked() and player.isDucked():
player.noblock(1)
player_target.noblock(1)
player.setColor(255, 255, 255, 100)
player_target.setColor(255, 255, 255, 100)
es.centertell(userid, 'Anti-Stuck')



elif abs(-target_z - (-player_z)) < 61 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 32 and abs(-target_y - (
-player_y)) < 32 and not player_target.isDucked() and player.isDucked():
if target_z < player_z:
player.noblock(1)
player_target.noblock(1)
player.setColor(255, 255, 255, 100)
player_target.setColor(255, 255, 255, 100)
es.centertell(userid, 'Anti-Stuck 1')

elif abs(-target_z - (-player_z)) < 61 and abs(-target_z - (-player_z)) >= 0 and abs(
-target_x - (-player_x)) < 32 and abs(-target_y - (
-player_y)) < 32 and player_target.isDucked() and not player.isDucked():
if target_z > player_z:
player.noblock(1)
player_target.noblock(1)
player.setColor(255, 255, 255, 100)
player_target.setColor(255, 255, 255, 100)
es.centertell(userid, 'Anti-Stuck 2')

else:
if client[steamid]["player_state"] == "Block" and client[target_steamid][
"player_state"] == "Block":
player.setColor(255, 255, 255, 255)
player.noblock(0)
player_target.noblock(0)
player_target.setColor(255, 255, 255, 255)



else:
gamethread.cancelDelayed("auto_stuck_%s" % userid)
return

gamethread.delayedname(0.1, 'auto_stuck_%s' % userid, auto_stuck, args=(userid))


def tp_menu(userid):
steamid = es.getplayersteamid(userid)
info = popuplib.easymenu(str(steamid) + 'tpto', None, tp_menu_select)
info.settitle("Teleport menu\nStops your timer\n\nSelect a player..")
info.c_beginsep = " "
info.c_pagesep = " "
for userid_2 in es.getUseridList():
if not es.isbot(userid_2):
if userid == userid_2:
name = es.getplayername(userid_2)

info.addoption(str(userid_2), "%s" % name, False)
else:
name = es.getplayername(userid_2)
info.addoption(str(userid_2), "%s" % name)

info.send(userid)


def tp_menu_select(userid, choice, popupid):
timer = es.import_addon("queue_timer/plugins/timer")
steamid = es.getplayersteamid(choice)
if not timer.CheckPartner(userid):
# if es.getplayerprop(userid, "CCSPlayer.baseclass.localdata.m_hGroundEntity") != -1:
client[steamid]["tp_location"] = es.getplayerlocation(choice)
client[steamid]["tp_userid"] = userid
client[steamid]["tp_accept"] = 1
es.tell(userid,
'#124,252,0[ Trikz] #snowYou have sent a teleport request to %s' % es.getplayername(
choice))
es.tell(choice,
'#124,252,0[ Trikz]#tomato %s #snowwants to teleport to you! Type #tomato!yes #snowor #tomatoignore' % (
es.getplayername(userid)))
else:
es.tell(userid,
'#124,252,0[ Trikz] #snowPlease unpartner first!')


def tp_accept(userid, text, steamid, name):
if client[steamid]["tp_accept"] == 1:

if timer_plugin:
timer = es.import_addon('queue_timer/plugins/timer')
timer.TimerSolo_Stop(userid)
timer.TimerPartner_Stop(userid)

tp_userid = client[steamid]["tp_userid"]
location = es.getplayerlocation(userid)

es.server.queuecmd('es_setpos %s %s %s %s' % (tp_userid, location[0], location[1], location[2] + 64))
es.tell(tp_userid,
'#124,252,0[ Trikz] #snowYou have #245,61,0teleported#snow to #yellow%s' % es.getplayername(
userid))
client[steamid]["tp_accept"] = 0


def getPushAngle(userid, view_angle, horiz, vert, vert_override=False):
"""
Pushes the player along his or her view vector.
Call without underscore, i.e.: player.push(horiz, vert, vert_override)
"""

myVector = view_angle

horzX = float(horiz) * float(myVector[0])

horzY = float(horiz) * float(myVector[1])

if str(vert_override) == '0':

vertZ = float(myVector[2]) * float(vert)

else:

vertZ = vert

myNewVector = es.createvectorstring(horzX, horzY, vertZ)

es.setplayerprop(userid, "CBasePlayer.localdata.m_vecBaseVelocity", myNewVector)



Now I didn't have the chance to test this with EventScripts itself, so you will just have to take my word for it that it did not lag with more than 20 players, and also trust me that all other files I mentioned in my previous reply worked together in harmony including this code with no noticeable lag with EventScripts.

Test 2
This test was to prove that the code in my first post, should NOT cause lag, specifically this code (reference):

Syntax: Select all

player_instances = PlayerDictionary()

@EntityPreHook(EntityCondition.is_player, 'run_command')
def player_run_command(args):
player = player_instances[index_from_pointer(args[0])]
index = player.index

if not player.dead or player.team_index < 2:
target = closeplayer(player, radius=200)


def closeplayer(player, radius):
for other in player_instances.values():
if not player.index == other.index and not player.dead and not other.dead:
dist = player.origin.get_distance(other.origin)
if player.origin.get_distance(other.origin) <= radius:
return (dist, other)

return (10000, None)


So I went ahead and made it SourceMod (It is a little different) and as predicted did not cause lag but I have to admit that this server ran btw 2-5 ms which is also a lot but with SourcePython it totally crashed ms over 60, so if you guys have more efficient way of getting the nearest player please let me know but I want to clarify that there is some kind of performance problem SourcePython OR maybe I am just a crazy person?

Syntax: Select all

/*
COMPILE OPTIONS
*/

// enforce semicolons after each code statement
#pragma semicolon 1

// enforice 1.7 syntax
#pragma newdecls required

/*
INCLUDES
*/

#include <sourcemod>

#include <cstrike>
#include <sdktools>



/*
PLUGIN INFO
*/

public Plugin myinfo = {
name = "Test",
author = "Flexlolo",
description = "Test",
version = "1.0",
url = ""
}



public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2])
{
if (IsPlayerAlive(client))
{
DataPack result = FindNearestPlayer(client, 96.0);

result.Reset();

int client_nearest = result.ReadCell();
float distance_nearest = result.ReadFloat();

delete result;

PrintToChatAll("game tick: %d | to client %d nearest is: %d with dist %.2f", GetGameTickCount(), client, client_nearest, distance_nearest);
}
}


public DataPack FindNearestPlayer(int client, float within)
{
float pos1[3];
GetEntPropVector(client, Prop_Send, "m_vecOrigin", pos1);

float distance_min;
int client_min;

float pos2[3];

for (int i = 1; i <= MaxClients; i++)
{
if (i != client)
{
if (IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i))
{
GetEntPropVector(i, Prop_Send, "m_vecOrigin", pos2);

float distance = GetVectorDistance(pos1, pos2);

if ((client_min && distance < distance_min) || !client_min)
{
distance_min = distance;
client_min = i;
}
}
}
}

DataPack result = new DataPack();

if (client_min)
{
if ((within > 0.0 && distance_min <= within) || within <= 0.0)
{
result.WriteCell(client_min);
result.WriteFloat(distance_min);

return result;
}
}

result.WriteCell(0);
result.WriteFloat(0.0);

return result;
}


Here is an image of net_graph also note that both of these code snippets was tested in CS:GO.

Link (image was not showing for some reason, here is the link)
imgur.com/dEmNUqy
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Performance issue!!!

Postby L'In20Cible » Sun Oct 14, 2018 12:15 am

velocity wrote:Yes and as I mentioned in my original post, I have another file timer.py which has loop at 0.001 seconds that is every tick for every player. This involves check if a player is inside multiple zones and if the player is dead, if his partner is inside the zone and so much more. Also, I mentioned that this doesn't lag in SourceMod or EventScripts which I feel like you are ignoring at this point.

I'm not ignoring anything. I just pointed out that your implementation will always matter and that you cannot compare the efficiency of 2 codes when one runs 200 times more often than the other, that's all. That being said; can the core of SP be optimized? Of course, it can. Does that means the way you implement your plugins and manage the resource available to you doesn't matter and is not your responsibility? Definitely not.

Taking your "example", let's see how this could be optimized and the why and how repetitive tasks can have an overall impact on the overall performance of your implementation. First of all, retrieving, assigning and reuse values is the basic of optimization. Here are the obvious repeated tasks that can be avoided:

player_instances = PlayerDictionary()

@EntityPreHook(EntityCondition.is_player, 'run_command')
def player_run_command(args):
player = player_instances[index_from_pointer(args[0])]
index = player.index

if not player.dead or player.team_index < 2:
target = closeplayer(player, radius=200)


def closeplayer(player, radius):
for other in player_instances.values():
if not player.index == other.index and not player.dead and not other.dead:
dist = player.origin.get_distance(other.origin)
if player.origin.get_distance(other.origin) <= radius:
return (dist, other)

return (10000, None)


You already made sure the player was not dead, checking it again every time you test against another player is redundant; you can safely remove the second occurrence without breaking the logic of your code.

player_instances = PlayerDictionary()

@EntityPreHook(EntityCondition.is_player, 'run_command')
def player_run_command(args):
player = player_instances[index_from_pointer(args[0])]
index = player.index

if not player.dead or player.team_index < 2:
target = closeplayer(player, radius=200)


def closeplayer(player, radius):
for other in player_instances.values():
if not player.index == other.index and not player.dead and not other.dead:
dist = player.origin.get_distance(other.origin)
if player.origin.get_distance(other.origin) <= radius:
return (dist, other)

return (10000, None)


Without mentioning the fact you are never using dist, you can safely move that and assign it to a local variable outside of the loop. It can seem insignificant, but dynamically retrieving an attribute performs few loops and few calls behind the scene. Let's say it performs 10 loops and 15 calls and that there is 20 players on your server. You just saved 10 * 20 = 200 loops and 15 * 20 = 300 calls just by removing your redundant dead check and 10 * (20 - 1) = 190 loops and 15 * (20 - 1) = 285 calls by retrieving the player's origin outside of your loop for a total of 390 loops and 585 calls every frame that your implementation no longer have to perform. EDIT: And since this code runs for every players every frames, this means a total of 20 * 390 = 7,800 loops and 20 * 585 = 11,700 calls saved each frames or 780,000 loops and 1,170,000 calls every second; this makes a HUGE difference. Manage your repeated tasks better in your code and you just improved its performance by twice just by moving a line or two around. Does it still doesn't matter? This is exactly what they do in the SM code you keep posting; they retrieve values once and reuse them everywhere else using global arrays.

velocity wrote:I personally want to help combat the problem, but I do not know how to sadly.

Helping us help you would be a good start. From your past threads, we are always asking for complete codes and the answers we get are always secretive and enigmatic about what your intentions and overall goals are. We should not have to go dig ES/SM codes in order to "guess" how you converted them to SP in order to try to profile and debug the issues. Without mentioning the dozens edits that make the whole thread more than confusing. Like I once said into another thread:
L'In20Cible wrote:The other day, my car was making some weird noises so I went to the garage. Once there, the mechanic asked me where my car was so he could examine it but I told him I didn't want anyone to see it so I left it at home and guess what? He was unable to help me!


velocity wrote:so if you guys have more efficient way of getting the nearest player please let me know but I want to clarify that there is some kind of performance problem SourcePython OR maybe I am just a crazy person?[/syntax]

Writing an helper method in C++ and exporting it would be the fastest solution. Actually, a lot of stuff could be done on the C++ side. In the early days, we decided to do minimal stuff and export the engine as is to avoid having to ship re-compiled binaries more than needed but now with the buidbot and sp update command, it wouldn't be too much of an issue; except maybe the huge amount of work it would need. Ayuto already moved a lot of stuff from the entities packages for optimization purposes earlier this year.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sun Oct 14, 2018 12:54 am

Thank you for the reply I do not post the whole code if I do not intend to share it with the public, does that sound ridiculous, maybe! Does that mean I should receive help, probably not, but are you available to help me anyway, yes!
The other day, my car was making some weird noises so I went to the garage. Once there, the mechanic asked me where my car was so he could examine it but I told him I didn't want anyone to see it so I left it at home and guess what? He was unable to help me!


This is my modified version:
The other day, my car was making some weird noises so I went to the garage. Once there, the mechanic asked me where my car was so he could examine it but I told him I didn't want anyone to see it, yet I knew it was the engine that made the noise so I left that in the garage for the mechanic to examine. He was able to help me but he didn't understand why.


That being said, I didn't look at it that way, so I will change these things. Thank you.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Performance issue!!!

Postby L'In20Cible » Sun Oct 14, 2018 1:31 am

I totally understand where you are coming from but, being a community where we prone open-source by having an open-source project, this kinda goes against our philosophy. :tongue:

Anyways, another repeated task:

Syntax: Select all

player = player_instances[index_from_pointer(args[0])]
index = player.index

What about:

Syntax: Select all

index = index_from_pointer(args[0])
player = player_instances[index]
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Performance issue!!!

Postby velocity » Sun Oct 14, 2018 1:44 am

Now that we are on it:

If I remove all redundancy etc.. which I most certainly will, is this the best way of getting the nearest player (My main goal is actually to determine if the player is stuck inside another player and I actually did share my code there is no difference from my old ES plugin and SP only what SP force me to do differently), maybe the source engine has a function for it?

Another thing, this is the code I wrote to replace gamethread.delayedname. First of all, is this a valid replacement? Secondly, do I even need to make a gamethread, is it true that player attributes run on the main thread anyway? What doesn't?

Syntax: Select all

class threadDelayed:
def __init__(self):
self.index = None
self.repeater = None
self.thread = None

def _threader(self):
# Do code here
pass

def repeat_thread(self):
self.repeater = Repeat(self._threader, cancel_on_level_end=False)
self.repeater.start(0.1)

def start_thread(self):
# Creates the thread
self.thread = GameThread(target=self.repeat_thread)
self.thread.daemon = True
self.thread.start()
Last edited by velocity on Sun Oct 14, 2018 2:07 am, edited 2 times in total.

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 24 guests