Question [Question] Weird Mechanics of Dart Traps and Teal Pressure Plates

putianyi888

Terrarian
I discussed with some other members about mechanics of dart traps and teal pressure plates. We had disagreements and I did some experiments to prove or disprove my views. However, it came out that none of us can explain what happened in the experiments. I'm working on another project so I'm not going to study deeper on this topic. So I'm just posting the experiments here and see if anyone can explain them.

Our questions came from this type of engine:
upload_2019-1-1_13-32-17.png


The original question is: is there any delay between the activation of dart traps?
The answer is no. The screenshot shows that all dart traps are triggered at the same tick.
upload_2019-1-1_12-59-12.png
Maybe darts are spawned in front of traps and trigger the plates instantly? It's probably true, but not always.

I changed the direction of this engine:
upload_2019-1-1_13-1-11.png
Now there is an obvious delay.
upload_2019-1-1_13-2-19.png
The screenshot shows that the darts shot upwards are spawned right on the traps, causing the delay.

Then I reduced the distance between traps and plates.
upload_2019-1-1_13-6-21.png
It came out that the first dart shot upwards can trigger the plate, but the second one shot downwards can't. The dart traps aiming up and down work differently!

So I used engines containing only downward traps.
upload_2019-1-1_13-11-31.png
Now there is a delay. But does that mean that downward traps work differently from horizontal traps? Not really. Change the direction of pressure plates:
upload_2019-1-1_13-12-52.png
Now all dart traps are triggered at the same tick.
upload_2019-1-1_13-13-37.png
Thus the directions of teal pressure plates make a difference!

Let's check the upward traps. The following engine failed.
upload_2019-1-1_13-15-33.png
But the next have a delay!
upload_2019-1-1_13-16-54.png
If a pressure plate can be triggered instantly by a dart spawned just on it, why does the first fail?

It's not the only weird thing. Connect the pressure plates to torches, activate this engine, record a video and play it frame by frame:
upload_2019-1-1_13-20-58.png

upload_2019-1-1_13-22-0.png

upload_2019-1-1_13-22-10.png

upload_2019-1-1_13-22-29.png

upload_2019-1-1_13-22-38.png

upload_2019-1-1_13-22-44.png

upload_2019-1-1_13-22-54.png

upload_2019-1-1_13-23-2.png

upload_2019-1-1_13-23-51.png

upload_2019-1-1_13-23-11.png
See? In the second picture, 5 dart traps have been activated, but none of the torches have. Does anyone know why this happens? I have made other experiments showing that torches are activated instantly by weighted pressure plates.
 
I think I have most of these examples figured out. I created a quick and dirty patch, that disables projectile updates, and then I can re-enable them for about one update cycle with a hotkey. (This shouldn't affect the outcome of the experiments much.) I also used Modder's toolkit to highlight the projectile hitboxes.

First of all, darts start at slightly different offset from the trap, depending on the direction of the trap.
t8XGIRi.jpg

This is immediately after firing the darts, before triggering any projectile updates. As you can see the biggest difference is when firing up. I'm guessing this is probably just due to some sort of rounding error.

Another important thing, is that when the darts first spawn in those positions, they won't trigger pressure plates. Collision only happens after updates. This is why you have to put the plate one block away from the trap.
UtyeygO.jpg
DQqUING.jpg

In this case, the bolt only barely touches the plate.

The original question is: is there any delay between the activation of dart traps?
The answer is no. The screenshot shows that all dart traps are triggered at the same tick.
index.php
Maybe darts are spawned in front of traps and trigger the plates instantly? It's probably true, but not always.

So this one is interesting. You start out with this:
pMXtAoh.jpg
And then you get this after the update:
xnHyPj9.jpg

The game updates projectiles one after the other. It iterates over them based on their index in the Main.projectile array. So what I think is happening:
  • The first dart updates.
  • Triggers the plate.
  • Wiring happens, triggers second trap, spawns new dart.
  • (The new dart has a higher index than the one that triggered it.)
  • The new dart gets updated.
  • Triggers next plate
  • ...
I changed the direction of this engine:
index.php
Now there is an obvious delay.
index.php
The screenshot shows that the darts shot upwards are spawned right on the traps, causing the delay.

That's not really true, the darts hit the plates at the same time in both directions.
35XUr5e.jpg
tkVy5U7.jpg
4mRru1F.jpg

There is a slight difference in their offset, but that doesn't matter in this case.

Then I reduced the distance between traps and plates.
index.php
It came out that the first dart shot upwards can trigger the plate, but the second one shot downwards can't. The dart traps aiming up and down work differently!

This is where the offset does matter. My bodged update debugger unfortunately won't stop collisions from happening, so I wasn't able to make a good screenshot for this.
Keq9eYo.jpg
dHBSwQ1.jpg

Looking at the sort of distance that darts travel in one update, I think when firing down, the dart misses the plate, and ends up inside the tile. While when firing down, it just about hits the top half of the plate.

So I used engines containing only downward traps.
index.php
Now there is a delay.

Yup, with this one, the dart takes two updates to reach the plate.
3N4CkmE.jpg
85vDRkl.jpg
2WdI3sy.jpg
jYyst3K.jpg
80027zV.jpg
fkFP1qH.jpg


But does that mean that downward traps work differently from horizontal traps? Not really. Change the direction of pressure plates:
index.php
Now all dart traps are triggered at the same tick.
index.php
Thus the directions of teal pressure plates make a difference!

This is just the same thing that happened on the original setup. Darts hit after one update.
oSG2HKS.jpg
SaIbkZ2.jpg


Let's check the upward traps. The following engine failed.
index.php

Not entirely sure what's going on here.
bSWAEjr.jpg
ARC5lWA.jpg
VWfPiiS.jpg

The dart touches the plate in both the first and the second frame, but it still doesn't trigger. This might just be because the hitbox of the plate is actually smaller than the sprite. In this case the dart is in fact slightly further from the plate than in my second and third pictures.

But the next have a delay!
index.php
If a pressure plate can be triggered instantly by a dart spawned just on it, why does the first fail?

It's not the only weird thing. Connect the pressure plates to torches, activate this engine, record a video and play it frame by frame:
index.php

index.php

index.php

index.php

index.php

index.php

index.php

index.php

index.php

index.php
See? In the second picture, 5 dart traps have been activated, but none of the torches have.

Yeah this one is weird. (Each picture was taken after only 1 update.)
2ZNMDS4.jpg
x9HWPpt.jpg
7nEtCC4.jpg
BSvlF2Y.jpg

You'd expect this to also just rigger the whole thing at the same time, but it only seems to trigger two at a time. Here's what's going on:
  • First dart updates.
  • Triggers the plate, which triggers the next trap, spawns second dart.
  • (The second dart gets an index higher than the original.)
  • First dart gets destroyed.
  • Second dart updates.
  • Triggers the plate, which triggers the next trap, spawns third dart.
  • (There is now a gap in the projectiles array, where the first dart was, third dart gets inserted there)
  • Second dart gets destroyed.
  • No more projectiles to update, game does other things.
  • New projectile update cycle begins.
  • Third dart gets updated.
  • ...
So this is because the dart hits the pad and gets destroyed, all in the same update.
(Q.E.D.)
 
Thanks for your work!
This might just be because the hitbox of the plate is actually smaller than the sprite.
But normally the dart can hit a plate on the side.
SaIbkZ2.jpg

Edit: I got it. The hitbox of the plate is not only narrow but also slightly shorter than a tile.
You'd expect this to also just rigger the whole thing at the same time, but it only seems to trigger two at a time. Here's what's going on:
  • First dart updates.
  • Triggers the plate, which triggers the next trap, spawns second dart.
  • (The second dart gets an index higher than the original.)
  • First dart gets destroyed.
  • Second dart updates.
  • Triggers the plate, which triggers the next trap, spawns third dart.
  • (There is now a gap in the projectiles array, where the first dart was, third dart gets inserted there)
  • Second dart gets destroyed.
  • No more projectiles to update, game does other things.
  • New projectile update cycle begins.
  • Third dart gets updated.
  • ...
So this is because the dart hits the pad and gets destroyed, all in the same update.
I don't understand how your patch works. Does it pause game per tick or per update? If per update, the darts should fire one by one. If per tick, that means that darts don't work at a frequency of 60Hz.
My point of the series of pictures is that the activating order should be: first trap, first torch, second trap, second torch, ... . But the result shows that the first 5 traps are all activated before the first torch, since in the second picture, 5 darts have been fired, but no torch is lit.
[doublepost=1546380749,1546380038][/doublepost]Ah I see that it's per update.
So this one is interesting. You start out with this:
pMXtAoh.jpg
And then you get this after the update:
xnHyPj9.jpg
In this example, there is an update between the generation of first dart and the first hit. But why isn't there an update between the second generation and the second hit? You may say that it's a special mechanic between trap and plate, but it's against our common understanding of how wiring works. By common understanding of wiring, a dart hits a plate, the plate activates the wire, the wire activates the second dart trap, the second dart trap fires, the second dart updates and the second dart hits the second plate.
 
Last edited:
Thanks for your work!
But normally the dart can hit a plate on the side.
SaIbkZ2.jpg

Edit: I got it. The hitbox of the plate is not only narrow but also slightly shorter than a tile.

I did some more digging in the source, and according to Collision.SwitchTiles, teal pressure plates will only trigger after an update, if the new position of the projectile intersects the plate, but the old one does not.
Code:
...
if (Utils.FloatIntersect(r1StartX, r1StartY, r1Width, r1Height, Position.X, Position.Y, (float)Width, (float)Height) && !Utils.FloatIntersect(r1StartX, r1StartY, r1Width, r1Height, oldPosition.X, oldPosition.Y, (float)Width, (float)Height))
...
Also, it looks like the plate hitbox is actually 16p long and 10p high, so it's actually bigger than the sprite, which is only 8p high.

I don't understand how your patch works. Does it pause game per tick or per update? If per update, the darts should fire one by one. If per tick, that means that darts don't work at a frequency of 60Hz.

Basically I just added a new patch to MechScope, that looks like this:
Code:
using Harmony;
using Terraria;

namespace MechScope.Patches
{
    [HarmonyPatch(typeof(Projectile), "Update")]
    class ProjectileUpdatePatch
    {
        [HarmonyPrefix]
        private static bool Prefix()
        {
            return SuspendableWireManager.doProjectile;
        }
    }
}
The Harmony library will put this at the beginning of the targeted method. (Projectile.Update in this case.) If it returns false, the rest if the method is skipped. SuspendableWireManager.doProjectile is a static filed, I set it back to false every time TModLoader's PostUpdate happens. When the hotkey triggers, which is luckily quite early in the update, I set it to true.

So basically the game runs as normal, but it skips projectile updates, unless I press a button first.

My point of the series of pictures is that the activating order should be: first trap, first torch, second trap, second torch, ... . But the result shows that the first 5 traps are all activated before the first torch, since in the second picture, 5 darts have been fired, but no torch is lit.

According to my test though, that isn't what's happening. Since your pictures are from a video capture, they are also dependent on things like the rendering. Torches might take a bit of time to actually turn on. Plus it looks like you dropped a frame between your first and second picture.
[doublepost=1546384858,1546384360][/doublepost]
In this example, there is an update between the generation of first dart and the first hit. But why isn't there an update between the second generation and the second hit? You may say that it's a special mechanic between trap and plate, but it's against our common understanding of how wiring works. By common understanding of wiring, a dart hits a plate, the plate activates the wire, the wire activates the second dart trap, the second dart trap fires, the second dart updates and the second dart hits the second plate.
Well, like I said here:
The game updates projectiles one after the other. It iterates over them based on their index in the Main.projectile array. So what I think is happening:
  • The first dart updates.
  • Triggers the plate.
  • Wiring happens, triggers second trap, spawns new dart.
  • (The new dart has a higher index than the one that triggered it.)
  • The new dart gets updated.
  • Triggers next plate
  • ...
The new dart gets updated in the same update cycle, because it was inserted into Main.projectile at an index, that didn't get updated yet when the first dart created it. Take a look at Projectile.NewProjectile and Main.DoUpdate (Line 770 ish in DnSpy) to see how that works.
Something interesting to test would be to somehow make a whole bunch of projectiles, and then destroy them as soon as the first dart spawns. This ways there would be an empty gap at the beginning of the projectiles array, the new dart would get inserted there, and wouldn't update instantly.

EDIT: Well, I've sort of got something.
Ez3LfsC.gif
 
Last edited:
Something interesting to test would be to somehow make a whole bunch of projectiles, and then destroy them as soon as the first dart spawns. This ways there would be an empty gap at the beginning of the projectiles array, the new dart would get inserted there, and wouldn't update instantly.
This is my understanding.
In each tick, the game updates all projectiles by traversing over the projectiles array. A projectile can trigger a plate instantly after its update, and a wiring process is inserted, generating the next projectile. The new projectile is inserted into the first empty slot in the projectiles array. If it's inserted before the last projectile, it cannot be updated until the next tick. If it's inserted after the last projectile, it will be updated during this traversing.

Also I have to mention that it's not plates that check projectiles. It's projectiles that check plates.
upload_2019-1-2_12-9-15.png

In this experiment, when the switch is triggered, the bullet from the lower gun is generated before the one from the upper gun because the lower gun is closer to the switch. The bullet is so fast that it triggers 5 plates in one tick. By the wiring on the right, we can check the order of activation of green wire and blue wire. It comes out that the green wire is activated before the blue wire.
[doublepost=1546435333,1546435039][/doublepost]In the weird example, the first dart is destroyed before generation of the third dart, so the third dart is inserted into the slot of the first dart, and can only be updated in the next tick.
 
Yes, that is exactly right.

Soooo, with this knowledge, I managed to create a sort of "projectile interferometer"...

Dh0VKCG.png
msINwkF.png

Basically this creates a dart in the second projectile slot, waits a bit, spawns two more darts, then measures the order in which they trigger the plate in front of them. If the first slot was filled by something, the order will be different.
This will detect any projectile in the world. It's a little bit fiddly, sometimes it can kind of get stuck in a "detected" output. This is mostly just a proof of concept. I am sure this could be useful for something. Like, some kind of remote triggered... something. The only trouble is, that there are many things that can set it off.
 
Very interesting stuff about dart traps. I still need to finish the dart trap game I was working on. I just haven't really had the time to work on it. None of this stuff really applies to my dart trap game, but it is interesting stuff to see. `:)
 
Yes, that is exactly right.

Soooo, with this knowledge, I managed to create a sort of "projectile interferometer"...

Dh0VKCG.png
msINwkF.png

Basically this creates a dart in the second projectile slot, waits a bit, spawns two more darts, then measures the order in which they trigger the plate in front of them. If the first slot was filled by something, the order will be different.
This will detect any projectile in the world. It's a little bit fiddly, sometimes it can kind of get stuck in a "detected" output. This is mostly just a proof of concept. I am sure this could be useful for something. Like, some kind of remote triggered... something. The only trouble is, that there are many things that can set it off.
Some of my friends are figuring behaviors of trap projectiles. It's not quite useful, just a matter of interest. Could you release the patch?
 
Sure thing. It's a bit messy though. I recommend using the multi-color wrench instead of the grand design, as that one doesn't work without projectiles. :p
At some point, I would like to implement stepping for various physics related things in MechScope properly. However, I'll wait until the next version of TModLoader, since it's gonna have a builtin way of IL patching, which will probably not be compatible with the way I do things now.

EDIT: Is it just me, or can we just not upload any files anymore? Anyways, here's the link: https://1drv.ms/u/s!Av10DsbKAhBlvmLmNPqAtOzLyN95
 
Back
Top Bottom