-
Notifications
You must be signed in to change notification settings - Fork 333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
E2 Collision Core(now part of propcore) #3099
Conversation
Nice job, but it should be moved to propcore imo, to lesser the sheer amount of vanilla cores, and due to collision tracking having little sense outside of prop manipulation scope. I would rename their/our prefixes to something more general. Perhaps hitentity/entity? Would be also nice to have functions throw strict-only errors on attempting to use invalid entity/track already tracked entity, etc, to make more use out of strict mode, and make debuggin for people easier |
Moved to propcore
Made aliases for our/their getters as entity/hitentity for them, but keeping the original our/theirs around
The 1/0's for the functions now produce runtime errors instead, or in non-strict return 1/0 for success/fail, and trying to check if we're tracking an invalid ent now produces an error too in strict instead |
Seems good enough |
I think this would be a great addition to expression 2, but i would also like to see a way to manipulate what collision group an entity belongs to like the glua function Entity:SetCollisionGroup would allow, maybe even Entity:SetOwner. |
@unknao Collision group functionality exists in e2 for ~half a year already :D. |
It would be great if you could add E2Helper descriptions and convert the collision method names to camel case to be consistent with the rest of the E2 functions. Here are some issues I've found:
@name Chip1
@strict
if (first()) {
ToTrack = noentity()
}
if (clk("track")) {
trackCollision(ToTrack)
}
event entityCreated(Ent:entity) {
if (Ent:type() == "prop_physics" & Ent:owner() == owner()) {
ToTrack = Ent
# A delay is needed to order the collision callbacks so that this
# chip's callback always executes after the vector has been modified.
timer("track", 0)
}
}
event entityCollision([_ _]:entity, Coll:collision) {
print("E2: " + Coll:ouroldvelocity())
} @name Chip2
@strict
event entityCreated(Ent:entity) {
if (Ent:type() == "prop_physics" & Ent:owner() == owner()) {
trackCollision(Ent)
}
}
event entityCollision([_ _]:entity, Coll:collision) {
const Vec = Coll:ouroldvelocity() # Or: Coll:toTable()["OurOldVelocity", vector]
Vec[1] = 1
Vec[2] = 2
Vec[3] = 3
} hook.Add("PlayerSpawnedProp", "e2test", function(_, _, ent)
timer.Simple(0, function()
if not ent:IsValid() then return end
ent:AddCallback("PhysicsCollide", function(_, data)
print("Lua", data.OurOldVelocity)
end)
end)
end) If you run these scripts and spawn a prop, you will get this output:
You can prevent this by copying vectors using the vector constructor before passing them to E2. |
E2Helper descriptions have been written
In this particular case I missed changing 'this' to' collision', 'self' refers to the e2 chip and 'this' refers to the object that the :function() was called from.
Thank you for bringing this to my attention especially though, as I was under the impression initially that the physcollide callback wouldn't pass the same table(or contents) to every callback func |
function( us, cd ) | ||
chip:ExecuteEvent("entityCollision",{us,cd.HitEntity,cd}) | ||
end) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this function is executed in the physics engine context which can allow user code to break the physics engine by doing weird stuff inside of this hook. Collisions should be stored in a table and then execute the E2 via a think hook, similar to what SF does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So would I want to set something up like E2's tick hook to run the event on the chip for each queued collision?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the heck is that timer there for?
Yeah, create a tick hook when collisions get queued and remove it after it runs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the heck is that timer there for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the heck is that timer there for?
The timer there goes back to 2009(pre-github presumably), the last time it was touched was for style standardization in 2013, so I don't know either.
Would be nice if this could be its own core for more fine-grained control |
@wrefgtzweve He made it in it's own core at first, but then moved to propcore. I guess, again, it would be alright if there would be just a convar to disable it, as moving it to complete separate brand new core will just bloat the sheer amount of vanilla cores even more, while also adding a core that have only few functions, single event, and have little to no application if the propcore is disabled. (Nor possibility that this core will grow, as it already does everything its suppose to) What I would want to test - will this make a new way to spam network? For example you start tracking 100 ents, and then collide hell out of them? If the network do raise significantly - I think silly limit (like 25 ents tracked at the same time) would be sufficient. |
the entire point of cores is to have fine grained control over them i dont see how networking could be an issue here, it seems all serversided unless i missed something. my main concern is that a player adds a lot or a few laggy running collision listeners, this will currently lag the server but not add to cputime/ops. |
hook.Add("Think", "Expression2CollisionClock", E2CollisionEventHandler) | ||
timer.Create("Expression2CollisionClock", 5, 0, function() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this timer exist. You should add the think hook when a collision is queued and remove it after it runs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So like, the function I have right now is fine, just have it added on a collision and have it hook.remove itself after run?
Or do you want a unique hook generated for each chip / collision to run the event once for that single event?
Is there a big cost to hook.add overwriting a pre-existing hook that might make it worth storing a bool for the hooks existence locally to check against?
On the matter of the timer, I figured it was a failsafe for the e2 tick hook getting cleared during load but if we shift away from the check being every think to just the think after a collision the timer can definitely go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even better is
if not var then
var = true
timer.Simple(0,function()
processCollisions()
var = false
end)
end
Regarding core/convar convo: Regarding possible lag: |
It would be a lot cleaner to use function callbacks instead of events. |
Do you have code example for that? |
I could probably make an overload for trackCollision that'll store a passed lambda and call it instead of executing the event for that entity, if that's what you mean |
I also thought of that, but that is not in style if E2 to use callback functions as arguments at all. A lot of people will not understand this concept, and thus will not use it. (Most of e2 users are not irl programmers) I guess an additional function with callback could be done, but not by not firing event, as it will break the current events expected behavior. Also no need to not execute event, as people that would want and know how to use callbacks will understand how not to get rekt by both callback and event. |
return self:throw("Attempting to track collisions for an invalid entity",0) | ||
end | ||
|
||
e2function number trackCollision( entity ent, function cb ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to break glualint but it's valid & works ingame, fairly certain this may be the only vanilla e2 function(not automatically generated) that takes a lambda at present.
May not be the most scientific stress test but here's two recordings of the same save, one with an e2 set up to count ALL collisions and one without. E2 code used: @outputs Collisions:number Tracked:number
@strict
Collisions = 0
Tracked = 0
event entityCreated(Ent:entity) {
if(Ent:isValid()) {
if(!isTrackingCollision(Ent)) {
trackCollision(Ent)
Tracked++
}
}
}
event entityCollision(Entity:entity, HitEntity:entity, CollisionData:collision) {
Collisions++
} e2.tracking.mp4no.e2.tracking.mp4Edit: Here's three saves, 1 has no e2, 2 has 20 that display the number of collisions & tracked entities, and 3 has 20 that display & have a potentially expensive sqrt while loop |
Seems fine to me |
if self.data.E2TrackedCollisions[entIndex] then | ||
return self:throw("Attempting to track collisions for an already tracked entity",0) | ||
end | ||
-- First, double check the arg sig lines up |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI, This is what Function:Unwrap
is for, in case you didn't know. Although you used other Function:
Methods, so you probably did. Maybe a separate method for just checking the arguments would suffice.
function Function:Unwrap(arg_sig, ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had overlooked unwrap, it would be nice if it could be passed an optional format/prepended string though so I can use the wording of the error message here but if you don't think that's needed I'll get a PR up soon to replace this check and msg with the unwrap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
,
Adds entity collision tracking for E2s.
Collision type (xcd)
Has the contents and naming scheme from the Gmod struct of the same name, but without the PhysObj'sFunctions
table collision:toTable()Returns a table with the key names and values being the same as the CollisionData struct(minus the physobjs)
Getters
Vectors
HitPos
OurOldVelocity
TheirOldVelocity
HitNormal
HitSpeed
OurNewVelocity
TheirNewVelocity
OurOldAngularVelocity
TheirOldAngularVelocity
Entity
HitEntity - collisiondata:hitentity()Number
Speed - collisiondata:speed()DeltaTime
OurSurfaceProps
TheirSurfaceProps
Adds event entityCollision(Entity:entity, HitEntity:entity, CollisionData:collision)
Called when a tracked entity collides with another entity(does not trigger on hit world)
Tracking function applies the PhysCollide and CallOnRemove callbacks to an entity if it's valid, cleans up on chip destruct, if tracking is stopped manually, or ent is deleted.
Functions
number trackCollision(entity ent)Returns 1 when tracking is successfully started, returns 0 if already tracking this ent or failed to track. Needs event entityCollision
number trackCollision(entity ent, function cb(eexcd) )
Calls callback on collision, then fires the event entityCollision afterward, same functionality as trackCollision but doesn't need event entityCollision to exist
number isTrackingCollision(entity ent)
Returns 1 if ent is being tracked by this chip, 0 if not or if ent is invalid
void stopTrackingCollision(entity ent)
Stops tracking ent, removes callbacks from ent
Open to suggestions