Class DrawFrame
- All Implemented Interfaces:
DrawTarget, AutoCloseable
try (DrawFrame frame = draw.frame()) {
frame.rect("box", x, y, w, h).color(Colors.GREEN).submit();
frame.text("label", x, y - 12, npc.name()).submit();
frame.npc(npc).color(Colors.RED).submit();
} // one debug_draw_set_batch for the primitives, one highlight_entity, here
Commands submitted to a frame are held, not sent. close() sends them
and is what try-with-resources calls; flush() is the same send with the
result handed back. Both are safe to call repeatedly — a frame with nothing
pending sends nothing.
A frame is one round-trip for primitives and one more per highlight, and
that is the wire's shape rather than a shortcoming here.
debug_draw_set_batch applies debug_draw_set items, whose
kind field cannot name a semantic highlight, so there is no batch a
DrawCommand.Highlight could ride. Both families are accepted here anyway,
because the alternative — refusing frame.npc(...) at compile time — would
break a call site to tell the caller something they cannot act on, and would
scatter a script's drawing across two mechanisms for a reason that is not the
script's business. pendingHighlightCount() is how many extra calls a
flush will make, if it matters.
The cost is bounded by what highlights are for: a script marks a handful of tracked things a tick, while the batch exists for the dozens of primitives it draws around them. Twenty rects and three highlights is four round-trips, not twenty-three.
Not thread-safe, and not meant to be: a frame is a tick-scoped local.
-
Method Summary
Modifier and TypeMethodDescriptionintabandon()Discard everything queued without sending it.voidclose()Flush.flush()Send everything queued and answer what the producer did with it.intHow many commands are waiting to be sent, of both families.intHow many of the pending commands are highlights — which is how many round-trips beyond the batch a flush will cost, since none of them can be batched.submit(DrawCommand command) Route a fully-built command, answering the key it is stored under.
-
Method Details
-
submit
Route a fully-built command, answering the key it is stored under.The plumbing seam the fluent builders call, and the escape hatch for a caller holding a
DrawCommandit built or stored itself.Queues rather than sends, into whichever of the two pending lists the command's family belongs to. The key is answered immediately because it is the caller's own — nothing about it depends on the producer.
- Specified by:
submitin interfaceDrawTarget
-
pendingCount
public int pendingCount()How many commands are waiting to be sent, of both families. -
pendingHighlightCount
public int pendingHighlightCount()How many of the pending commands are highlights — which is how many round-trips beyond the batch a flush will cost, since none of them can be batched. -
flush
Send everything queued and answer what the producer did with it.The primitives go first, as one
debug_draw_set_batchperDrawLimits.MAX_BATCH_ITEMSof them — so exactly one for any frame of that size or smaller, which is every realistic frame. Beyond it the frame is split rather than truncated or refused, because the producer rejects an over-size batch outright and would lose the whole frame including the part that would have fit. Then each highlight, as its ownhighlight_*call, because no batch can carry one.The returned result is the aggregate over all of it. Check
DrawBatchResult.dropped(): the wire reports per-item refusals inside a successful reply, so a frame that drew nothing does not throw. A refused highlight is folded into the same count rather than thrown, so one contract covers the whole frame. Anything refused is also logged at WARN, so a caller that ignores this return is still told.If this throws, the store is in a partly-known state — not a clean one.
What is applied when it does, in the order the flush attempts them:
- Sub-batches that completed are entirely drawn. The producer applies each item to its store as it walks the array, so a batch that fails at the envelope level may still have drawn part of what it carried, and the error reply says nothing about how far it got. Splitting sharpens that: when a later sub-batch fails, every command in an earlier one is definitely drawn.
- The failing sub-batch is the unknown. Somewhere between none and all of it reached the store.
- Highlights are not half-applied. Each is a single store operation behind a single call, so every highlight before a failure is drawn and the failing one is not. That is strictly more determinate than the batch half — the one thing sending them separately buys.
- Nothing after the failure was sent at all.
Two things make it recoverable, and both are deliberate:
- The pending commands are kept rather than cleared, so the keys are
still in hand and calling
flush()again is safe — setting a key replaces rather than appends, so a redelivered command is a no-op rather than a duplicate. Draw.list()reports what the producer actually retained, andDraw.clearAll()removes all of it without needing any keys at all.
In practice a content-level rejection is not reachable from this API — see
DrawCodecTestfor why the encoder cannot emit an item the producer would refuse structurally — so a throw here is a transport or script-lifecycle failure. When it is severe enough to close the pipe, the producer drops everything this connection drew, which leaves the store clean rather than half-full; a revoked script is the case where earlier calls stay drawn until their TTL expires. -
abandon
public int abandon()Discard everything queued without sending it. Answers how many were dropped on the floor, of both families. -
close
public void close()Flush. Never throws for refused commands — a debug overlay must not be able to take a script's tick down, and that holds for a refused highlight as much as for a refused rect — but every refusal is logged at WARN. Callflush()instead when the script wants to act on the result.A transport failure does still propagate, because it is not the overlay failing: swallowing it would hide a dead pipe. Note that a throw from here inside try-with-resources is suppressed when the block's own body already threw, so the WARN
flush()logs is the reliable record that the store may hold part of this frame.- Specified by:
closein interfaceAutoCloseable
-