Page 1 of 1

trace ray

Posted: Sat Sep 17, 2022 12:51 pm
by decompile
Hello,

I'm using trace ray's to figure out if the player is touching a surface, and if so, return the steepness angle of the surface if its found.

Syntax: Select all

def get_trace_ray(self):
origin = self.origin

destination = Vector(*origin)
destination.z -= 3500

trace = GameTrace()

engine_trace.trace_ray(
Ray(origin, destination, self.mins, self.maxs),
ContentMasks.PLAYER_SOLID_BRUSH_ONLY,
TraceFilterSimple((self.player,)),
trace,
)

trace_plane = None

if trace.did_hit():
destination_distance = trace.end_position.get_distance(origin)

if destination_distance < 0.1:
print("Player is touching a surface!")

trace_plane = trace.plane.normal.z

return trace_plane


This works as intended, however, since I'm using noblock, this would trigger if the player is standing inside another player. Is it possible to block this scenario, e.g. to setup an ignore other player filter.

Re: trace ray

Posted: Sat Sep 17, 2022 3:30 pm
by VinciT
You can simply modify the TraceFilterSimple to ignore all players:

Syntax: Select all

from filters.players import PlayerIter

engine_trace.trace_ray(
Ray(origin, destination, self.mins, self.maxs),
ContentMasks.PLAYER_SOLID_BRUSH_ONLY,
TraceFilterSimple(ignore=[player.index for player in PlayerIter()]),
trace
)

Re: trace ray

Posted: Sun Sep 18, 2022 6:37 am
by L'In20Cible
VinciT wrote:You can simply modify the TraceFilterSimple to ignore all players:

Syntax: Select all

engine_trace.trace_ray(
TraceFilterSimple(ignore=[player.index for player in PlayerIter()]),
)

Despite what I believe is outdated documentation, the TraceFilterSimple class actually accept an iterable of BaseEntity, not indexes:
https://github.com/Source-Python-Dev-Te ... ce.py#L207

Moreover, you don't need to build a list yourself, and you could simply pass your PlayerIter directly since it is remapped as inthandle internally anyways.

That said, I don't recall testing for players, but I can see an opportunity to use a SyncedEntityDictionary which is much faster to interact because the entities it contains are already tested and done with. In theory, for players, it should look like the following:

Syntax: Select all

synced_players = SyncedEntityDictionary(Player, PlayerIter())
engine_trace.trace_ray(
TraceFilterSimple(ignore=synced_players),
)


The idea behind that addition was to improve performance over using EntityIter that can be very costly when done frequently. For example, here is the timings I have in my notes at the time:

Syntax: Select all

from time import time
from entities.dictionary import SyncedEntityDictionary
from filters.entities import EntityIter

entities = EntityIter()
synced_entities = SyncedEntityDictionary()

t = time()
for _ in range(1000000):
for _ in entities:
...
print(time() - t)

t = time()
for _ in range(1000000):
for _ in synced_entities:
...
print(time() - t)
EntityIter: 392.2801203727722
SyncedEntityDictionary: 9.281311988830566

Re: trace ray

Posted: Tue Sep 20, 2022 3:09 pm
by decompile
Thank you both for the help, it works!

Re: trace ray

Posted: Tue Sep 27, 2022 5:15 pm
by VinciT
L'In20Cible wrote:That said, I don't recall testing for players, but I can see an opportunity to use a SyncedEntityDictionary which is much faster to interact because the entities it contains are already tested and done with.
Ooooh that is awesome! Can't believe I missed that commit. What an amazing feature.