box

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Bounding box

Postby velocity » Sat Aug 11, 2018 5:46 pm

Is there a way to modify the bounding box (hitbox) of a given player using code? If so, how would I get started?
Last edited by velocity on Sat Aug 11, 2018 5:46 pm, edited 1 time in total.
Reason: Original post version
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: Bounding box

Postby VinciT » Sat Aug 11, 2018 11:03 pm

In most games, you can use m_flModelScale to change the size of the player model. This also changes the size of the bounding box and the hitboxes.

Syntax: Select all

# ../resize/resize.py

# Source.Python
from players.entity import Player
from commands.say import SayCommand


# Resize the player / entity you are looking at.
# Chat command: resize <size>
@SayCommand('resize')
def resize_command(command, index, team_only=False):
# Was the size not specified?
if len(command) < 2:
return

player = Player(index)
entity = player.view_entity

try:
size = abs(float(command[1]))
except ValueError:
# The specified size was of the wrong type (not a float / int).
return

entity.set_property_float('m_flModelScale', size)

(cyan = absbox, magenta = render box, gold/yellow = bounding box)
Image

I tried changing the bounding box and the hitboxes without using m_flModelScale, and.. I got nothing.
I've been messing around with all the properties related to the bounding box:

Code: Select all

m_Collision.m_vecMaxs
m_Collision.m_vecMaxsPreScaled
m_Collision.m_vecMins
m_Collision.m_vecMinsPreScaled
m_Collision.m_vecSpecifiedSurroundingMaxs
m_Collision.m_vecSpecifiedSurroundingMaxsPreScaled
m_Collision.m_vecSpecifiedSurroundingMins
m_Collision.m_vecSpecifiedSurroundingMinsPreScaled
m_Collision.m_vecSurroundingMaxs
m_Collision.m_vecSurroundingMins
And none of them worked for me. Maybe it has something to do with the m_Collision.m_nSurroundType?
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Sat Aug 11, 2018 11:50 pm

Yeah model size not gonna cut it :(. How did you display the boxes in-game?
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: Bounding box

Postby satoon101 » Sat Aug 11, 2018 11:57 pm

I haven't tried, but you might check into using the bones/hitboxes:
https://github.com/Source-Python-Dev-Te ... o_wrap.cpp

Example:

Syntax: Select all

from players.constants import HitGroup
from players.entity import Player

player = Player(1)
header = player.model_header
hitbox = header.get_hitbox_set(player.hitbox_set)
hitgroups = {y.value: x for x, y in HitGroup.__members__.items()}
for x in range(hitbox.hitboxes_count):
y = hitbox.get_hitbox(x)
print('=' * 40)
print(y.bone)
print(header.get_bone(y.bone).position)
print(y.group, '-', hitgroups.get(y.group, 'unknown'))
print(y.min)
print(y.max)

Those min/max values are relative to the bone, which has a relative position to the player.
Image
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Sun Aug 12, 2018 1:02 am

There are some errors in the code.

There are no attribute .position and some KeyError '8' in y.group and other variables.

Is it possible to modify the hitboxes with this=?
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: Bounding box

Postby VinciT » Sun Aug 12, 2018 1:07 am

velocity wrote:How did you display the boxes in-game?
Look at a player and type these in your console:

Code: Select all

cl_ent_absbox
cl_ent_rbox
cl_ent_bbox
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Sun Aug 12, 2018 1:13 am

A new follow up question: Is it possible to make a grenade collide with the bounding box instead of the hitbox like it is in CS:S
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: Bounding box

Postby satoon101 » Sun Aug 12, 2018 2:06 am

velocity wrote:There are no attribute .position

Sorry, I added that after having tested.

velocity wrote:KeyError '8' in y.group and other variables.

I tested with default models on CS:S, so if there's a hitgroup 8, you're likely using another game and/or custom model. That line really isn't necessary, I only included it to show the name of the hitgroup (ie HEAD, LEFTARM, CHEST, etc..). I'll update my script for both of these errors.

velocity wrote:Is it possible to modify the hitboxes with this=?

The min/max are read/write, so I believe you might be able to. I'm honestly not sure how well it will work, but it's an idea.

https://github.com/Source-Python-Dev-Te ... #L228-L229
Image
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Sun Aug 12, 2018 1:19 pm

Okay it actually works, but I have a problem it is only bullets that collide with the hitbox. I would like grenades to collide differently with the player, so I thought changing the hitbox would solve it. How would I proceed if grenades should work aswell? My theory is that the nades only collide with the bounding box, but i'm not sure.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Sun Aug 12, 2018 7:19 pm

Nobody knows? Please tell if the issue is explained so it can be understood :/
User avatar
Doldol
Senior Member
Posts: 200
Joined: Sat Jul 07, 2012 7:09 pm
Location: Belgium

Re: Bounding box

Postby Doldol » Thu Aug 16, 2018 4:02 am

velocity wrote:Nobody knows? Please tell if the issue is explained so it can be understood :/


Maybe you can accomplish what you want by parenting an entity to the player that has your desired dimensions/collision or maybe hook ontouch and push the grenade when it hits that entity or the player? (There are some caveats with that though, search the forums)
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Thu Aug 16, 2018 10:57 am

Parent the entity, how can that be done? Ontouch won't be using the right collision box
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: Bounding box

Postby VinciT » Thu Aug 16, 2018 9:09 pm

Doldol wrote:Maybe you can accomplish what you want by parenting an entity to the player that has your desired dimensions/collision or maybe hook ontouch and push the grenade when it hits that entity or the player? (There are some caveats with that though, search the forums)

Great idea Doldol! I kept trying to do this with virtual functions, but I think this should work:

Syntax: Select all

# ../trigger_bbox/trigger_bbox.py

# Source.Python
from mathlib import Vector
from events import Event
from players.entity import Player
from players.dictionary import PlayerDictionary
from entities.entity import Entity
from entities.helpers import index_from_pointer
from entities.hooks import EntityPreHook, EntityCondition
from entities.constants import SolidType, EntityEffects
from commands.say import SayCommand
from listeners import OnEntityOutput, OnEntityDeleted


bbox_triggers = {}


class PlayerBBOX(Player):

def __init__(self, index):
super().__init__(index)
# Instance of the 'trigger_multiple' used for the custom bounding box.
self.custom_bbox = None


player_instances = PlayerDictionary(PlayerBBOX)


def unload():
# Remove all custom bounding boxes when unloading the plugin.
for player in player_instances.values():
if player.custom_bbox:
player.custom_bbox.remove()


@EntityPreHook(EntityCondition.is_player, 'post_think')
def pre_post_think(stack_data):
player = player_instances[index_from_pointer(stack_data[0])]

# Is the player dead or a spectator?
if player.dead or player.team < 2:
return

# Does the player not have a custom bounding box?
if not player.custom_bbox:
return

# Adjust the size of the custom bounding box according to the player
# bounding box.
player.custom_bbox.mins = player.mins
player.custom_bbox.maxs = player.maxs


@OnEntityOutput
def on_entity_output(output, activator, caller, value, delay):
# Don't go further if the entity output isn't OnStartTouch.
if output != 'OnStartTouch':
return

# Is the entity that called OnStartTouch not a custom bounding box?
# (specialised 'trigger_multiple')
if caller.index not in bbox_triggers:
return

# Is the entity that touched the 'trigger_multiple' not a projectile?
# (hegrenade_projectile, flashbang_projectile, etc.)
if 'projectile' not in activator.classname:
return

player = player_instances[caller.parent.index]
# Position of the player.
player_pos = player.origin
# Get the center / middle point of the player.
player_pos.z += player.maxs.z / 2

# First pass at calculating the custom bounding box normal.
# If you were to use this, it would act more like a cylinder and not a box.
normal = activator.origin - player_pos
normal.normalize()
# Second and final pass at calculating the normal, this one should work.
# Subtract the normalized projectile velocity from the normal to get
# more pronounced values. Maybe I'm overthinking this?
final_normal = get_box_normal(normal - activator.velocity.normalized())

# Calculate the direction / velocity of the bouncing projectile.
bounce_direction = final_normal * final_normal.dot(activator.velocity) * 2
bounce_velocity = activator.velocity - bounce_direction
# Decrease the velocity of the projectile by 45%.
bounce_velocity.length = activator.velocity.length * 0.45
# Add the new velocity to the projectile.
activator.teleport(None, None, bounce_velocity)


def get_box_normal(normal):
# If a projectile hits near the bottom of the custom bounding box, it
# might freak out and go through the ground or the player.
# Decrease the z axis of the normal to avoid this (mostly).
normal.z *= 0.55
# Get the largest normal value to determine which side of the box got hit.
primary_side = max(map(abs, normal))

# Go through all the normal axes.
for axis, value in enumerate(normal):
# Is this the side that got hit?
# Subtracting 0.04 here allows for bouncing off of edges.
if abs(value) >= primary_side - 0.04:
normal[axis] = round(value)
else:
normal[axis] = 0

return normal


@OnEntityDeleted
def on_entity_deleted(base_entity):
try:
index = base_entity.index
except ValueError:
return

# Is this a custom bounding box?
if index in bbox_triggers:
try:
userid = bbox_triggers[index]
player_instances.from_userid(userid).custom_bbox = None
except ValueError:
pass

del bbox_triggers[index]


@Event('player_death', 'player_team')
def events_for_removal(event):
player = player_instances.from_userid(event['userid'])

# Does the player have a custom bounding box?
if player.custom_bbox:
# Remove it when the player dies or changes their team.
player.custom_bbox.remove()


def create_trigger_multiple(origin, model, mins, maxs):
trigger = Entity.create('trigger_multiple')
trigger.model = model
# Don't render the 'trigger_multiple'.
# Without this the players' consoles will get spammed with this error:
# ERROR: Can't draw studio model models/props/cs_assault/money.mdl
# because CBaseTrigger is not derived from C_BaseAnimating
trigger.effects |= EntityEffects.NODRAW
trigger.origin = origin
trigger.spawn()
# Enable collisions with everything (not including physics debris).
# https://developer.valvesoftware.com/wik ... iple#Flags
trigger.spawn_flags = 64
# Set the bounding box size.
trigger.mins = mins
trigger.maxs = maxs
# Make sure the 'trigger_multiple' uses its bounding box for collision.
trigger.solid_type = SolidType.BBOX
# How often can the 'trigger_multiple' be triggered? (0 - all the time)
trigger.wait = 0
return trigger


@SayCommand('custom_bbox')
def custom_bbox_command(command, index, team_only=False):
player = player_instances[index]
target = player.view_entity

if not target.is_player():
return

# Get the PlayerBBOX instance.
target = player_instances[target.index]

trigger = create_trigger_multiple(
origin=target.origin,
model=target.model,
mins=target.mins,
maxs=target.maxs
)

trigger.set_parent(target, -1)
# Add the 'trigger_multiple' index to a dictionary.
# (trigger_multiple index:player userid)
bbox_triggers[trigger.index] = target.userid
# Does the player already have a custom bounding box?
if target.custom_bbox:
# Remove it.
target.custom_bbox.remove()
# Store the 'trigger_multiple' entity instance within the Player instance.
target.custom_bbox = trigger
Look at a player and type custom_bbox in chat, they should now have a trigger_multiple on them that will act as their bounding box. You can do whatever you want with the projectile (and the player) inside the on_entity_output() function.
Last edited by VinciT on Fri Aug 17, 2018 7:36 pm, edited 3 times in total.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Bounding box

Postby L'In20Cible » Thu Aug 16, 2018 11:23 pm

Nice! I have a few points though. First of all, the model:
VinciT wrote:

Syntax: Select all

TRIGGER_MODEL = Model('models/props/cs_assault/money.mdl')
I don't think using a random model is a good idea because depending of the angles it will parent, you may end with the parented trigger being slightly off the player. I think the best approach would be to simply use the player's model and resize it how you want.
VinciT wrote:

Syntax: Select all

# Bounding box size for players in CS:GO.
PLAYER_MINS = Vector(-16, -16, 0)
PLAYER_MAXS = Vector(16, 16, 72)
Don't forget that the size of a player is reduced when he is crouched so you might want to keep it updated to the size of the player at all time instead of using hard-coded vectors. And to make it compatible with other plugins, should also use dynamic size based on the scale of the player in case someone else is resizing them.
VinciT wrote:

Syntax: Select all

# Is the entity that called OnStartTouch not a 'trigger_multiple'?
if caller.classname != 'trigger_multiple':
return
I think you should rather stores the indexes and compare them to ensure that your code doesn't execute unless it was a trigger you created because in certain cases, this condition can pass without being by an entity you would expect (one present in the map, or created by another plugin for examples).
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: Bounding box

Postby VinciT » Fri Aug 17, 2018 4:23 am

I completely forgot that crouching changes the bounding box! I've updated the plugin in my previous post based on a couple of your points.
When it comes to the model, isn't it irrelevant what the model itself is? The trigger_multiple is a brush entity, so the model shouldn't matter, right?
I'm not 100% sure on this, which is why I took your advice and changed it to use the player model.

L'In20Cible wrote:should also use dynamic size based on the scale of the player in case someone else is resizing them.
Velocity mentioned he needed this for CS:GO. Sadly, m_flModelScale doesn't work in CS:GO like it does in other Source games, so I left the mins and maxs hardcoded for now.Image
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Bounding box

Postby L'In20Cible » Fri Aug 17, 2018 6:06 am

VinciT wrote:When it comes to the model, isn't it irrelevant what the model itself is? The trigger_multiple is a brush entity, so the model shouldn't matter, right?
I'm not 100% sure on this, which is why I took your advice and changed it to use the player model.

It is more than important. The model is the shape of your trigger. Take in example bombsites, they are brush entities (you can use their model on other entities using *x or x* I don't remember if the asterisk is prefixed or suffixed -- been years last time I played with that, where x is their pre-cached index) and they will trigger in different shape and not a flat box. Same concept applies to any brush entities you are creating, for example a func_precipitation needs to be set to the current bsp file if you want it to be rendered on the entire map, or you can use any model and it will render the precipitation only in that shape, etc.

VinciT wrote:Velocity mentioned he needed this for CS:GO. Sadly, m_flModelScale doesn't work in CS:GO like it does in other Source games, so I left the mins and maxs hardcoded for now.
I still think you should use player.mins and player.maxs instead of hard-coding vectors if only to support custom models that might be set by other plugins.
User avatar
velocity
Senior Member
Posts: 220
Joined: Sat May 10, 2014 6:17 pm

Re: Bounding box

Postby velocity » Fri Aug 17, 2018 11:28 am

So I tested it but the grenades doesn't collide with it before I change the trigger solid flags to USE_TRIGGER_BOUNDS, but then they player is stuck in place :/
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: Bounding box

Postby VinciT » Fri Aug 17, 2018 7:03 pm

L'In20Cible wrote:It is more than important. The model is the shape of your trigger. Take in example bombsites, they are brush entities (you can use their model on other entities using *x or x* I don't remember if the asterisk is prefixed or suffixed -- been years last time I played with that, where x is their pre-cached index) and they will trigger in different shape and not a flat box. Same concept applies to any brush entities you are creating, for example a func_precipitation needs to be set to the current bsp file if you want it to be rendered on the entire map, or you can use any model and it will render the precipitation only in that shape, etc.
I just thought that because we're using SolidType.BBOX and setting the mins and maxs directly, that the shape of the model doesn't matter. Thanks for the insight, L'In20Cible.

velocity wrote:So I tested it but the grenades doesn't collide with it before I change the trigger solid flags to USE_TRIGGER_BOUNDS, but then they player is stuck in place :/
That's because the plugin doesn't do anything other than give you access to the projectile that touched a player's custom bounding box and the instance of the player whose custom bounding box was touched. Until now, that is.

I've updated the plugin to make sure the mins and maxs of the trigger_multiple are dynamically adjusted and I've added basic collision.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 29 guests