Heh
#557 posted by necros on 2011/05/02 02:37:38
yeah, i guess i could have at least tried it out to see.
you're right, self isn't being lost when touching triggers. trying to figure out now would be pointless though, because the code has change by a huge amount since last time i posted about it.
SV_TouchLinks: Next != L->next
#558 posted by necros on 2011/05/08 20:20:10
is it bad to call setorigin(self) in a touch function? does that cause the touchlinks warning in fitz?
i googled the forums, but i don't think it was ever really explained what this error is, only that it used to crash in e2m2.
Potentially
#559 posted by Preach on 2011/05/09 00:29:39
I'm not brilliant at following how the engine handles this touch stuff, but here goes:
The following functions could cause problems with sv_touchlinks:
setorigin
setsize
droptofloor
movetogoal
walkmove
All these functions can cause the entity to be relinked, which potentially causes the issue. There are some other conditions that need to be met before the error is encountered: firstly the entity has to be part of the same areanode as the touch is coming from*. My understanding is that there are 32 areanodes in a map to reduce the number of entities considered in the collision code by approx. that factor.
The other important thing is that the entity has to actually break the chain of linked entities at exactly the point that sv_touchlinks is operating. I believe that this translates to applying any of the dangerous functions to other, but again not too sure how all the code fits together.
A final small point is that even if do apply one of the dangerous functions to other (and since we're in a touch function with other it's safe to assume by now that they share an areanode) we might still get away with it. This case would occur when other is the first entity in the areanode - relinking it will reinsert it in the same place as before. There's no safe way to exploit this though, as it's determined entirely engine-side.
The last thing to remember is that sv_touchlinks only looks through the list of triggers, so anything that's not SOLID_TRIGGER* ought to be safe. Best of luck!
*Technically that should read "that wasn't SOLID_TRIGGER last time the entity got linked into the world" but that's a bit of a mouthful. All that means is that you can't quickly set the entity to SOLID_NOT and get away with anything, it's about whether the entity is truly a trigger according to the engine at that time...
Footnote
#560 posted by Preach on 2011/05/09 00:31:10
That first asterisk should have been removed, the footnote is about the SOLID_TRIGGER statement - though most of you spotted that anyway I expect...
#561 posted by necros on 2011/05/09 00:54:07
yeah, this is happening with some of my code. unfortunately, i have the report from a third party and haven't been able to reproduce it myself. apparently, occasionally, it spams the console with sv_touchlinks errors in fitz085.
i noticed this tiny comment in defs.qc for setmodel:
void(entity e, string m) setmodel = #3; // set movetype and solid first
and i checked that entity and found that i was setting self.model before movetype. so i fixed that anyway, but maybe that might also have been the problem? the entity wasn't properly linked in the first place?
geez, i dunno. :P
it's supposed to be a visible solid_trigger entity that changes origin when you touch it.
i was wondering, maybe if i used to bad method of just setting self.origin in the touch function, that way, it's not breaking whatever links?
Danger
#562 posted by Preach on 2011/05/09 09:11:32
From what I've gleaned, that is the most dangerous thing you could do in a touch function, although I didn't post it correctly. I was talking about the danger of moving other, but I should have been talking about self. I had the two muddled up and I'm sorry about that.
The standard way to cope with this is to set up a quick think function from the touch function, and have that think reset the origin. You can put a guard into the touch function to prevent multiple touches before it moves - set up a flag on the entity and toggle it in the touch and think.
Hm Ok
#563 posted by necros on 2011/05/09 20:57:07
so what i can do is just set a flag after the touch function to disallow further touches until the think function has been run. that should work i guess. a little roundabout but last thing i want to do is start causing crashes. :P
Speed-up
#564 posted by Preach on 2011/05/09 22:19:31
You can also use a little trick to make sure the think function runs as soon as possible (either this frame or the next). Just set self.nextthink = 0.05; - note that we are deliberately omitting time from the assignment. Since this will be in the past for every frame the engine runs (frame 1 runs at time = 0.1) it will execute the think as soon as the entity is checked by the engine.
The flag works a bit like the way that
if (self.nextthink > time) line works for a trigger_multiple, so if you don't want to use another field that approach is an option. My feeling is that the flag is simpler because you don't need the flexibility of a custom delay but it's basically a preference thing.
Spot The Deliberate Mistake?
#565 posted by Lardarse on 2011/05/10 19:59:18
(frame 1 runs at time = 0.1)
Time starts at 1, not 0. This is one of the quirks of the system, that makes very little difference, except for when it trips you up (and when it does, it hurts). For example (from the id1 code):
self.nextthink = self.nextthink + random()*0.5;
This line appears in all of the $foomonster_start functions. The original intention was for monsters to not all do their setup on the same frame, to reduce computer load. However, what actually happens, is that on a roughly 1 in 32000 chance (or, according to LordHavoc, 1 in 2 billion on Linux), self.nextthink is set to 0, which means that it never thinks again (as .nextthink is set to 0 before the think function is called), and the rest of the time, it happens on the next frame.
Thinking About The Other One
#566 posted by Lardarse on 2011/05/10 20:00:41
When a think function is being called, what is other set to? Does it get set to something predictable, or is it just left as whatever it was last time?
#567 posted by necros on 2011/05/10 20:30:38
so that bit of code doesn't actually do anything then?
might be a good idea to change to it 1 + random() * 0.5 then? because that must mean thinks are being all processed on the same frame.
also, on other, a few think functions steal other for their own uses so even if it is being reset every frame, you might get a semi-random entity if one of those thinks happened during the frame?
I'd Say
(1 + random()) * 0.5
#569 posted by necros on 2011/05/10 22:09:03
won't that still generate nextthinks < 1?
Depends
Is nextthink a float or an int, and how do conversions work in QC? If it is like in C, then yeah. I just thought it's closer to the original, but heh we don't really want that.
<1
#571 posted by Preach on 2011/05/10 22:42:23
It's ok to generate thinks which are less than 1 in this case, because as long as it's non-zero the think function will run, and you'll still spread the monsters out over many frames because not all of them are going to get the same random number.
And if they did, they'd all be set off on the same frame no matter what function you did...
Good catch on the server starting at 1 there though, I must remember that. Either way, as long as you don't set nextthink to 0, any value less than 1 will give you the soonest think function possible.
However
#572 posted by Lardarse on 2011/05/11 00:41:39
any value less than time will give you the soonest think function possible
As Spike has pointed out a few times, when a think function is called, for that dive into the code only, time is set to what .nextthink was before being reset. So the most reliable way for a "do this next frame" is probably self.nextthink = time;
Well
#573 posted by Preach on 2011/05/11 00:52:53
Only if your code depends on the value of time in some way. If all you need is for it to run in the next server frame then you can take the shortcut. If time cannot every be less than 1 then a value less than 1 is always less than time...
#574 posted by necros on 2011/05/11 01:27:20
i think it's more about successive thinks.
the less aligned monster thinks are, the less impact the ai routine has when it's run, i would think.
if you just set nextthink to 1, every monster will be thinking at the same time.
Shadow Casting Bmodels
#575 posted by necros on 2011/05/14 23:03:56
could someone modify MH's Aguirre's light utility so that it casts shadows from bmodels?
and maybe a new key '_noshadows' to disable shadows on that particular bmodel?
or is it not possible? like bmodels can't be used for some reason?
Reversal Of Fortune
#576 posted by Preach on 2011/05/15 02:00:54
Not commenting on how it can or can't be done, but I'd recommend making it opt-in rather than opt-out. Having an entity key _castshadows which you set to 1 to enable the new function would keep the current behaviour on existing maps, which is always desirable when possible. I also think there's a good chance that the cases you don't want it on (entities which move or have little to no impact on shadow casting) outnumber the entities which would benefit. It would make it reactive - used only when the lighting looks wrong - but I don't think that's a bad thing.
#577 posted by necros on 2011/05/15 02:05:40
maybe. either way, it'd still be great if someone could haxor that in. :)
#578 posted by necros on 2011/05/21 01:45:14
we were talking about how bsp models use their bboxes to figure out collision a little while ago.
i mentioned about setting bbox in qc affecting that. i tested it out, and yes, if you manually set bbox size, you can don't need to put visible brushes at the min/max extents.
also, if there are visible parts of the bsp model but the bbox is smaller, any bits outside the bbox are nonsolid.
Award
#579 posted by Preach on 2011/05/21 10:02:36
also, if there are visible parts of the bsp model but the bbox is smaller, any bits outside the bbox are nonsolid.
Hack of the week right there, folks. Awesome!
Backup Past 0
#580 posted by necros on 2011/05/30 00:15:26
what the heck is this anyway? :P
Tracing Error
#581 posted by Preach on 2011/05/30 11:42:39
It's a glitch in the trace code. It arises in the part of the code that tries to determine the exact impact point of a trace on a solid surface. The loop starts with a point at "0" which it knows is in the open, and a midpoint which it knows is in solid BSP. It then backs up from the solid point in small increments until it gets into the open, and so fixes the endpoint of the trace.
The glitch occurs because the increments don't always exactly hit the 0 point as they build towards it. It is possible for the trace to be in solid for all of the test points before 0, and for the increment to never hit exactly 0. The loop would then return the first point past 0 as the nearest point-in-open to the impact point(i.e. backup past 0). However, we already know that 0 is closer to the surface and in-open so that point is returned instead.
Phew, so basically I think this is most likely to occur on short traces where an endpoint is near a surface, as these are the traces where floating point inaccuracy is most prevalent, and I believe that makes a difference. However, there is a binary chop portion of the trace algorithm, so the circumstances that cause it to happen may just occur at random on any given surface.
Possibly also complicated or intricate BSP architecture could make this more likely, since you would have to dive down to a smaller scale to check exactly which bit of fine detail a trace collides with, but I've got no example to back that up with.
|