Source-Python-Dev-Team / Source.Python

This plugin aims to use boost::python and create an easily accessible wrapper around the Source Engine API for scripter use.
http://forums.sourcepython.com
GNU General Public License v3.0
163 stars 31 forks source link

Adds entity collisions functionalities. #443

Closed jordanbriere closed 2 years ago

jordanbriere commented 2 years ago
from listeners import OnPlayerCollision

@OnPlayerCollision
def on_player_collision(player, entity):
    """Called when a player is about to collide with an entity."""
    # Disable teammates collisions
    if not entity.is_player():
        return
    return player.team_index != entity.team_index
from listeners import OnEntityCollision

@OnEntityCollision
def on_entity_collision(entity, other):
    """Called when a non-player entity is about to collide with another entity."""
    # Disable weapons/projectiles collisions with everything except players
    return not (entity.is_weapon() and not other.is_player())
from entities.collisions import CollisionHash
from events import Event
from players.entity import Player

h = CollisionHash()

@Event('player_say')
def player_say(game_event):
    player = Player.from_userid(game_event['userid'])
    entity = player.view_entity
    if entity is None:
        return
    # Toggle collisions with aimed entity
    if h.has_pair(player, entity):
        h.remove_pair(player, entity)
    else:
        h.add_pair(player, entity)
from entities.collisions import CollisionSet
from events import Event
from players.entity import Player

s = CollisionSet()

@Event('player_say')
def player_say(game_event):
    player = Player.from_userid(game_event['userid'])
    # Toggle collisions with everything
    if player in s:
        s.remove(player)
    else:
        s.add(player)
from entities.collisions import CollisionMap
from events import Event
from players.entity import Player

m = CollisionMap()

@Event('player_say')
def player_say(game_event):
    player = Player.from_userid(game_event['userid'])
    entity = player.view_entity
    if entity is None:
        return
    # Toggle one-way collisions with aimed entity
    s = m[player]
    if entity in s:
        s.remove(entity)
    else:
        s.add(entity)
from entities.collisions import CollisionMap
from entities.collisions import CollisionMode
from events import Event
from players.entity import Player

# Setting the collision mode to ALLOW rather than PREVENT will negate the rules.
m = CollisionMap(CollisionMode.ALLOW)

@Event('player_say')
def player_say(game_event):
    player = Player.from_userid(game_event['userid'])
    entity = player.view_entity
    if entity is None:
        return
    s = m[player]
    if entity in s:
        s.remove(entity.index)
    else:
        # Player will now collide with nothing except this entity
        s.add(entity)
from engines.trace import ContentFlags
from entities.collisions import CollisionHook

@CollisionHook
def collision_hook(entity, other, trace_filter, mask):
    """Called whenever two entities are tested for colliding contents."""
    # Prevent hostages from being killed by bullets
    if not mask & ContentFlags.HITBOX:
        return
    return other.classname != 'hostage_entity'
jordanbriere commented 2 years ago

Just to clarify; if CCollisionManager::ShouldHitEntity is called, then that means the game allows the collision. If a CollisionHook (that is always called, regardless of the cache) prevent the collision then the cache for the current tick is updated. If the original m_pExtraShouldHitCheckFunction function prevents the collision, regardless of the cache, the cache is not updated and this decision takes precedence over any CollisionHash/OnEntityCollision/OnPlayerCollision callbacks. Basically, the cache is only used to limit CollisionHash lookups, as well as python calls to the listeners, and should not affect anything else beside being a major improvement because the game usually does one trace, then a dozen leaves/sweeps checks on the same test and this is what we no longer have to process.

CookStar commented 2 years ago

I'll leave this for the record and warning, CollisionHash will cause a crash if you add more than 256 entity combinations.

You should STOP using EntityIter or similar methods to add entities to CollisionHash.

See the comments for more details. https://github.com/Source-Python-Dev-Team/Source.Python/pull/444#issuecomment-989106572 https://github.com/Source-Python-Dev-Team/Source.Python/pull/444#issuecomment-989234996