Skip to content
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

Cryptographic chat support #303

Open
wants to merge 44 commits into
base: main
Choose a base branch
from
Open

Conversation

guac42
Copy link
Contributor

@guac42 guac42 commented Mar 24, 2023

Description

This adds full cryptographic chat support and all vanilla error checking in the form of an optional plugin called SecureChatPlugin. This means that if chat verification fails, clients are kicked with the proper translation keys. Commands remain to be unverified.

Suggestions to organize code are greatly appreciated, as the example is a bit of a mess at the moment.

closes #8

  • Updates chat example to cryptographically verify chat messages.
  • Create a chat type registry (necessary for sending chat messages).
  • Create PlayerSessionData struct (to prevent having 3 different structs representing the same data).
  • Fix the MessageSignature type definition in valence_protocol.
  • Fix the message filter definition in the ChatMessageS2c packet.
  • Rename the field message_count to message_index.

Test Plan

Note: Has been tested with two clients

Steps:

  1. Run the chat example

Things to consider

  • Notchian servers pass the core chat verification logic off to another thread. Should we do this too? Or is this out of the scope of the example?
  • Verifying the client's chat mode may seem a little out of scope, but it is important to consider that notchian servers do not verify chats sent by clients with hidden chat modes.
  • Where in the project should yggdrasil_session_pubkey.der be stored? Is it good where it is now?

guac42 added 6 commits March 10, 2023 20:54
Transferring progress
- added chat type registry (required for sending ChatMessageS2c packets)
- made some minor changes in valence_protocol (reworked how some types are structured in order to make invalid data states impossible)
- finished a very, very rough example implementation of chat verification (still needs to broadcast packets to all clients)
@rj00a rj00a linked an issue Mar 24, 2023 that may be closed by this pull request
@rj00a
Copy link
Member

rj00a commented Mar 24, 2023

Where in the project should yggdrasil_session_pubkey.der be stored? Is it good where it is now?

That should go in assets/.

Copy link
Collaborator

@dyc3 dyc3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chat example appears functional, but I don't think it's good ux for end users to write all that boilerplate. Is there anything preventing us from moving most of that logic into valence? Ideally, it should just be plug and play.

Notchian servers pass the core chat verification logic off to another thread. Should we do this too?

Let's hold off for now unless we notice it's an actual problem.

Also, like RJ said, move the example key to the assets folder.

crates/valence/src/player_list.rs Outdated Show resolved Hide resolved
crates/valence/src/chat_type.rs Outdated Show resolved Hide resolved
crates/valence/Cargo.toml Outdated Show resolved Hide resolved
guac42 added 2 commits March 24, 2023 17:56
Extracts cryptographic chat support to an optional plugin and adds some documentation to what a chat_type is.
@rj00a
Copy link
Member

rj00a commented Mar 30, 2023

In #302 I've changed the way the registry codec is set up. Once that's finished, I'll push some changes I have stashed for the player list so progress on this PR can be made.

@rj00a
Copy link
Member

rj00a commented Apr 10, 2023

The new player list was implemented in #317 :) I don't think there are any major blockers now.

@rj00a
Copy link
Member

rj00a commented Apr 21, 2023

I've just completed a large reorganization of the entire project in #321. Following that, it makes sense to put all things related to chat in an optional valence_chat crate. This includes the chat type registry, packet handlers, and cryptographic verification. If you can complete that we'll be able to get this merged 😃

@guac42
Copy link
Contributor Author

guac42 commented Apr 23, 2023

I've just completed a large reorganization of the entire project in #321. Following that, it makes sense to put all things related to chat in an optional valence_chat crate. This includes the chat type registry, packet handlers, and cryptographic verification. If you can complete that we'll be able to get this merged smiley

Sounds good! I found a bug right before I went on vacation so I'll get working on fixing it and the merge conflicts :)

@guac42
Copy link
Contributor Author

guac42 commented Sep 29, 2023

Not sure how this got closed but the PR is up to date now

@guac42 guac42 reopened this Sep 29, 2023
Copy link
Collaborator

@dyc3 dyc3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but I'll defer to @rj00a for the merge.

@JackCrumpLeys
Copy link
Contributor

You should probably remove the command bit as commands are likely getting merged very soon in either #351 or #446.

@guac42
Copy link
Contributor Author

guac42 commented Oct 2, 2023

You should probably remove the command bit as commands are likely getting merged very soon in either #351 or #446.

I was thinking of either doing that or waiting until #351 or #446 was merged and implementing verification for commands as well.

@rj00a rj00a self-requested a review October 3, 2023 00:19
@guac42
Copy link
Contributor Author

guac42 commented Oct 3, 2023

You should probably remove the command bit as commands are likely getting merged very soon in either #351 or #446.

I was thinking of either doing that or waiting until #351 or #446 was merged and implementing verification for commands as well.

Just found out that verification for commands is required for all verification otherwise it breaks the signed message chain. I'm working on implementing a barebones verification process for commands until #351 or #446 is merged with the proper process.

@JackCrumpLeys
Copy link
Contributor

JackCrumpLeys commented Nov 9, 2023

Heads up that #446 was merged. Feel free to ask me to explain any part of how the system works if you are unsure. The basics of my approach are explained in both the crate level docs and module level docs of valence_command.

Copy link

It looks like this pull request changed the workspace structure. Please replace assets/depgraph.svg with the following text:

depgraph.svg (Don't forget the trailing newline)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.43.0 (0)
 -->
<!-- Title: %3 Pages: 1 -->
<svg width="1309pt" height="692pt"
 viewBox="0.00 0.00 1309.14 692.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 688)">
<title>%3</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-688 1305.14,-688 1305.14,4 -4,4"/>
<!-- 0 -->
<g id="node1" class="node">
<title>0</title>
<polygon fill="none" stroke="black" points="479.5,-684 384.5,-684 384.5,-648 479.5,-648 479.5,-684"/>
<text text-anchor="middle" x="432" y="-662.3" font-family="Times,serif" font-size="14.00">java_string</text>
</g>
<!-- 1 -->
<g id="node2" class="node">
<title>1</title>
<polygon fill="none" stroke="black" points="1298.5,-468 1125.5,-468 1125.5,-432 1298.5,-432 1298.5,-468"/>
<text text-anchor="middle" x="1212" y="-446.3" font-family="Times,serif" font-size="14.00">valence_advancement</text>
</g>
<!-- 2 -->
<g id="node3" class="node">
<title>2</title>
<polygon fill="none" stroke="black" points="742.5,-396 619.5,-396 619.5,-360 742.5,-360 742.5,-396"/>
<text text-anchor="middle" x="681" y="-374.3" font-family="Times,serif" font-size="14.00">valence_server</text>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge">
<title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M1125.21,-437.56C1021.26,-423.86 849.11,-401.16 752.48,-388.42"/>
<polygon fill="black" stroke="black" points="752.88,-384.95 742.51,-387.11 751.96,-391.89 752.88,-384.95"/>
</g>
<!-- 3 -->
<g id="node4" class="node">
<title>3</title>
<polygon fill="none" stroke="black" points="668.5,-324 549.5,-324 549.5,-288 668.5,-288 668.5,-324"/>
<text text-anchor="middle" x="609" y="-302.3" font-family="Times,serif" font-size="14.00">valence_entity</text>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge">
<title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M663.2,-359.7C654.4,-351.14 643.62,-340.66 634,-331.3"/>
<polygon fill="black" stroke="black" points="636.2,-328.57 626.59,-324.1 631.32,-333.58 636.2,-328.57"/>
</g>
<!-- 12 -->
<g id="node5" class="node">
<title>12</title>
<polygon fill="none" stroke="black" points="821,-324 687,-324 687,-288 821,-288 821,-324"/>
<text text-anchor="middle" x="754" y="-302.3" font-family="Times,serif" font-size="14.00">valence_registry</text>
</g>
<!-- 2&#45;&gt;12 -->
<g id="edge3" class="edge">
<title>2&#45;&gt;12</title>
<path fill="none" stroke="black" d="M699.04,-359.7C708.06,-351.05 719.12,-340.45 728.94,-331.03"/>
<polygon fill="black" stroke="black" points="731.37,-333.55 736.16,-324.1 726.52,-328.5 731.37,-333.55"/>
</g>
<!-- 11 -->
<g id="node6" class="node">
<title>11</title>
<polygon fill="none" stroke="black" points="776,-252 586,-252 586,-216 776,-216 776,-252"/>
<text text-anchor="middle" x="681" y="-230.3" font-family="Times,serif" font-size="14.00">valence_server_common</text>
</g>
<!-- 3&#45;&gt;11 -->
<g id="edge4" class="edge">
<title>3&#45;&gt;11</title>
<path fill="none" stroke="black" d="M626.8,-287.7C635.6,-279.14 646.38,-268.66 656,-259.3"/>
<polygon fill="black" stroke="black" points="658.68,-261.58 663.41,-252.1 653.8,-256.57 658.68,-261.58"/>
</g>
<!-- 12&#45;&gt;11 -->
<g id="edge12" class="edge">
<title>12&#45;&gt;11</title>
<path fill="none" stroke="black" d="M735.96,-287.7C726.94,-279.05 715.88,-268.45 706.06,-259.03"/>
<polygon fill="black" stroke="black" points="708.48,-256.5 698.84,-252.1 703.63,-261.55 708.48,-256.5"/>
</g>
<!-- 7 -->
<g id="node10" class="node">
<title>7</title>
<polygon fill="none" stroke="black" points="598,-180 462,-180 462,-144 598,-144 598,-180"/>
<text text-anchor="middle" x="530" y="-158.3" font-family="Times,serif" font-size="14.00">valence_protocol</text>
</g>
<!-- 11&#45;&gt;7 -->
<g id="edge11" class="edge">
<title>11&#45;&gt;7</title>
<path fill="none" stroke="black" d="M644.06,-215.88C623.51,-206.35 597.75,-194.41 575.91,-184.28"/>
<polygon fill="black" stroke="black" points="577.36,-181.1 566.82,-180.07 574.42,-187.45 577.36,-181.1"/>
</g>
<!-- 4 -->
<g id="node7" class="node">
<title>4</title>
<polygon fill="none" stroke="black" points="458,-36 344,-36 344,0 458,0 458,-36"/>
<text text-anchor="middle" x="401" y="-14.3" font-family="Times,serif" font-size="14.00">valence_math</text>
</g>
<!-- 5 -->
<g id="node8" class="node">
<title>5</title>
<polygon fill="none" stroke="black" points="709.5,-36 608.5,-36 608.5,0 709.5,0 709.5,-36"/>
<text text-anchor="middle" x="659" y="-14.3" font-family="Times,serif" font-size="14.00">valence_nbt</text>
</g>
<!-- 6 -->
<g id="node9" class="node">
<title>6</title>
<polygon fill="none" stroke="black" points="590,-36 476,-36 476,0 590,0 590,-36"/>
<text text-anchor="middle" x="533" y="-14.3" font-family="Times,serif" font-size="14.00">valence_ident</text>
</g>
<!-- 8 -->
<g id="node11" class="node">
<title>8</title>
<polygon fill="none" stroke="black" points="532,-108 382,-108 382,-72 532,-72 532,-108"/>
<text text-anchor="middle" x="457" y="-86.3" font-family="Times,serif" font-size="14.00">valence_generated</text>
</g>
<!-- 7&#45;&gt;8 -->
<g id="edge5" class="edge">
<title>7&#45;&gt;8</title>
<path fill="none" stroke="black" d="M511.96,-143.7C502.94,-135.05 491.88,-124.45 482.06,-115.03"/>
<polygon fill="black" stroke="black" points="484.48,-112.5 474.84,-108.1 479.63,-117.55 484.48,-112.5"/>
</g>
<!-- 10 -->
<g id="node12" class="node">
<title>10</title>
<polygon fill="none" stroke="black" points="656,-108 550,-108 550,-72 656,-72 656,-108"/>
<text text-anchor="middle" x="603" y="-86.3" font-family="Times,serif" font-size="14.00">valence_text</text>
</g>
<!-- 7&#45;&gt;10 -->
<g id="edge6" class="edge">
<title>7&#45;&gt;10</title>
<path fill="none" stroke="black" d="M548.04,-143.7C557.06,-135.05 568.12,-124.45 577.94,-115.03"/>
<polygon fill="black" stroke="black" points="580.37,-117.55 585.16,-108.1 575.52,-112.5 580.37,-117.55"/>
</g>
<!-- 8&#45;&gt;4 -->
<g id="edge7" class="edge">
<title>8&#45;&gt;4</title>
<path fill="none" stroke="black" d="M443.16,-71.7C436.51,-63.39 428.42,-53.28 421.11,-44.14"/>
<polygon fill="black" stroke="black" points="423.66,-41.73 414.68,-36.1 418.2,-46.1 423.66,-41.73"/>
</g>
<!-- 8&#45;&gt;6 -->
<g id="edge8" class="edge">
<title>8&#45;&gt;6</title>
<path fill="none" stroke="black" d="M475.79,-71.7C485.17,-63.05 496.68,-52.45 506.91,-43.03"/>
<polygon fill="black" stroke="black" points="509.45,-45.45 514.43,-36.1 504.7,-40.3 509.45,-45.45"/>
</g>
<!-- 10&#45;&gt;5 -->
<g id="edge9" class="edge">
<title>10&#45;&gt;5</title>
<path fill="none" stroke="black" d="M616.84,-71.7C623.49,-63.39 631.58,-53.28 638.89,-44.14"/>
<polygon fill="black" stroke="black" points="641.8,-46.1 645.32,-36.1 636.34,-41.73 641.8,-46.1"/>
</g>
<!-- 10&#45;&gt;6 -->
<g id="edge10" class="edge">
<title>10&#45;&gt;6</title>
<path fill="none" stroke="black" d="M585.7,-71.7C577.14,-63.14 566.66,-52.66 557.3,-43.3"/>
<polygon fill="black" stroke="black" points="559.65,-40.7 550.1,-36.1 554.7,-45.65 559.65,-40.7"/>
</g>
<!-- 9 -->
<g id="node13" class="node">
<title>9</title>
<polygon fill="none" stroke="black" points="911,-684 759,-684 759,-648 911,-648 911,-684"/>
<text text-anchor="middle" x="835" y="-662.3" font-family="Times,serif" font-size="14.00">valence_build_utils</text>
</g>
<!-- 13 -->
<g id="node14" class="node">
<title>13</title>
<polygon fill="none" stroke="black" points="112,-468 0,-468 0,-432 112,-432 112,-468"/>
<text text-anchor="middle" x="56" y="-446.3" font-family="Times,serif" font-size="14.00">valence_anvil</text>
</g>
<!-- 13&#45;&gt;2 -->
<g id="edge13" class="edge">
<title>13&#45;&gt;2</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M112.25,-433.7C115.2,-433.08 118.13,-432.51 121,-432 294.74,-401.27 502.17,-387.51 609.2,-382.08"/>
<polygon fill="black" stroke="black" points="609.43,-385.58 619.24,-381.58 609.08,-378.58 609.43,-385.58"/>
</g>
<!-- 14 -->
<g id="node15" class="node">
<title>14</title>
<polygon fill="none" stroke="black" points="270,-468 130,-468 130,-432 270,-432 270,-468"/>
<text text-anchor="middle" x="200" y="-446.3" font-family="Times,serif" font-size="14.00">valence_boss_bar</text>
</g>
<!-- 14&#45;&gt;2 -->
<g id="edge14" class="edge">
<title>14&#45;&gt;2</title>
<path fill="none" stroke="black" d="M270.15,-433.6C273.14,-433.04 276.1,-432.5 279,-432 394.08,-412.07 528.83,-395.71 609.43,-386.67"/>
<polygon fill="black" stroke="black" points="609.92,-390.13 619.47,-385.55 609.14,-383.18 609.92,-390.13"/>
</g>
<!-- 15 -->
<g id="node16" class="node">
<title>15</title>
<polygon fill="none" stroke="black" points="610,-540 502,-540 502,-504 610,-504 610,-540"/>
<text text-anchor="middle" x="556" y="-518.3" font-family="Times,serif" font-size="14.00">valence_chat</text>
</g>
<!-- 16 -->
<g id="node17" class="node">
<title>16</title>
<polygon fill="none" stroke="black" points="768,-468 660,-468 660,-432 768,-432 768,-468"/>
<text text-anchor="middle" x="714" y="-446.3" font-family="Times,serif" font-size="14.00">valence_lang</text>
</g>
<!-- 15&#45;&gt;16 -->
<g id="edge15" class="edge">
<title>15&#45;&gt;16</title>
<path fill="none" stroke="black" d="M594.65,-503.88C616.25,-494.31 643.35,-482.3 666.27,-472.15"/>
<polygon fill="black" stroke="black" points="667.75,-475.32 675.47,-468.07 664.91,-468.92 667.75,-475.32"/>
</g>
<!-- 17 -->
<g id="node18" class="node">
<title>17</title>
<polygon fill="none" stroke="black" points="642,-468 490,-468 490,-432 642,-432 642,-468"/>
<text text-anchor="middle" x="566" y="-446.3" font-family="Times,serif" font-size="14.00">valence_player_list</text>
</g>
<!-- 15&#45;&gt;17 -->
<g id="edge16" class="edge">
<title>15&#45;&gt;17</title>
<path fill="none" stroke="black" d="M558.47,-503.7C559.57,-495.98 560.9,-486.71 562.13,-478.11"/>
<polygon fill="black" stroke="black" points="565.61,-478.5 563.56,-468.1 558.68,-477.51 565.61,-478.5"/>
</g>
<!-- 17&#45;&gt;2 -->
<g id="edge17" class="edge">
<title>17&#45;&gt;2</title>
<path fill="none" stroke="black" d="M594.13,-431.88C609.17,-422.72 627.87,-411.34 644.06,-401.48"/>
<polygon fill="black" stroke="black" points="646.04,-404.38 652.76,-396.19 642.4,-398.4 646.04,-404.38"/>
</g>
<!-- 18 -->
<g id="node19" class="node">
<title>18</title>
<polygon fill="none" stroke="black" points="434,-468 288,-468 288,-432 434,-432 434,-468"/>
<text text-anchor="middle" x="361" y="-446.3" font-family="Times,serif" font-size="14.00">valence_command</text>
</g>
<!-- 18&#45;&gt;2 -->
<g id="edge18" class="edge">
<title>18&#45;&gt;2</title>
<path fill="none" stroke="black" d="M434.01,-433.03C486.61,-421.52 557.22,-406.08 609.47,-394.65"/>
<polygon fill="black" stroke="black" points="610.31,-398.05 619.34,-392.49 608.82,-391.21 610.31,-398.05"/>
</g>
<!-- 19 -->
<g id="node20" class="node">
<title>19</title>
<polygon fill="none" stroke="black" points="484,-540 338,-540 338,-504 484,-504 484,-540"/>
<text text-anchor="middle" x="411" y="-518.3" font-family="Times,serif" font-size="14.00">valence_inventory</text>
</g>
<!-- 19&#45;&gt;2 -->
<g id="edge19" class="edge">
<title>19&#45;&gt;2</title>
<path fill="none" stroke="black" d="M419.94,-503.83C431.37,-483.58 453.08,-450.36 481,-432 519.18,-406.89 568.81,-393.65 609.07,-386.68"/>
<polygon fill="black" stroke="black" points="609.79,-390.11 619.09,-385.04 608.66,-383.2 609.79,-390.11"/>
</g>
<!-- 20 -->
<g id="node21" class="node">
<title>20</title>
<polygon fill="none" stroke="black" points="764,-540 628,-540 628,-504 764,-504 764,-540"/>
<text text-anchor="middle" x="696" y="-518.3" font-family="Times,serif" font-size="14.00">valence_network</text>
</g>
<!-- 20&#45;&gt;2 -->
<g id="edge20" class="edge">
<title>20&#45;&gt;2</title>
<path fill="none" stroke="black" d="M738.11,-503.87C753.18,-495.45 768.53,-483.67 777,-468 784.61,-453.93 785.13,-445.78 777,-432 769.14,-418.69 756.61,-408.48 743.16,-400.76"/>
<polygon fill="black" stroke="black" points="744.7,-397.62 734.22,-396.04 741.43,-403.81 744.7,-397.62"/>
</g>
<!-- 20&#45;&gt;16 -->
<g id="edge21" class="edge">
<title>20&#45;&gt;16</title>
<path fill="none" stroke="black" d="M700.45,-503.7C702.45,-495.9 704.87,-486.51 707.1,-477.83"/>
<polygon fill="black" stroke="black" points="710.5,-478.66 709.6,-468.1 703.72,-476.92 710.5,-478.66"/>
</g>
<!-- 21 -->
<g id="node22" class="node">
<title>21</title>
<polygon fill="none" stroke="black" points="939.5,-540 782.5,-540 782.5,-504 939.5,-504 939.5,-540"/>
<text text-anchor="middle" x="861" y="-518.3" font-family="Times,serif" font-size="14.00">valence_scoreboard</text>
</g>
<!-- 21&#45;&gt;2 -->
<g id="edge22" class="edge">
<title>21&#45;&gt;2</title>
<path fill="none" stroke="black" d="M851.63,-503.94C840.2,-484.41 819.22,-452.48 794,-432 777.96,-418.97 758.18,-408.29 739.68,-400.02"/>
<polygon fill="black" stroke="black" points="741.01,-396.78 730.44,-396.04 738.23,-403.21 741.01,-396.78"/>
</g>
<!-- 22 -->
<g id="node23" class="node">
<title>22</title>
<polygon fill="none" stroke="black" points="1054.5,-684 929.5,-684 929.5,-648 1054.5,-648 1054.5,-684"/>
<text text-anchor="middle" x="992" y="-662.3" font-family="Times,serif" font-size="14.00">valence_spatial</text>
</g>
<!-- 23 -->
<g id="node24" class="node">
<title>23</title>
<polygon fill="none" stroke="black" points="1094,-540 958,-540 958,-504 1094,-504 1094,-540"/>
<text text-anchor="middle" x="1026" y="-518.3" font-family="Times,serif" font-size="14.00">valence_weather</text>
</g>
<!-- 23&#45;&gt;2 -->
<g id="edge23" class="edge">
<title>23&#45;&gt;2</title>
<path fill="none" stroke="black" d="M989.26,-503.88C949.19,-485.41 883.01,-455.49 825,-432 796.96,-420.65 765.46,-408.94 739.09,-399.42"/>
<polygon fill="black" stroke="black" points="740.22,-396.11 729.63,-396.02 737.85,-402.69 740.22,-396.11"/>
</g>
<!-- 24 -->
<g id="node25" class="node">
<title>24</title>
<polygon fill="none" stroke="black" points="1285.5,-540 1112.5,-540 1112.5,-504 1285.5,-504 1285.5,-540"/>
<text text-anchor="middle" x="1199" y="-518.3" font-family="Times,serif" font-size="14.00">valence_world_border</text>
</g>
<!-- 24&#45;&gt;2 -->
<g id="edge24" class="edge">
<title>24&#45;&gt;2</title>
<path fill="none" stroke="black" d="M1138.99,-503.94C1075.11,-485.84 971.02,-456.52 881,-432 838.53,-420.43 790.89,-407.79 752.76,-397.76"/>
<polygon fill="black" stroke="black" points="753.34,-394.29 742.78,-395.13 751.56,-401.06 753.34,-394.29"/>
</g>
<!-- 25 -->
<g id="node26" class="node">
<title>25</title>
<polygon fill="none" stroke="black" points="624.5,-684 497.5,-684 497.5,-648 624.5,-648 624.5,-684"/>
<text text-anchor="middle" x="561" y="-662.3" font-family="Times,serif" font-size="14.00">dump_schedule</text>
</g>
<!-- 26 -->
<g id="node27" class="node">
<title>26</title>
<polygon fill="none" stroke="black" points="661.5,-612 590.5,-612 590.5,-576 661.5,-576 661.5,-612"/>
<text text-anchor="middle" x="626" y="-590.3" font-family="Times,serif" font-size="14.00">valence</text>
</g>
<!-- 25&#45;&gt;26 -->
<g id="edge25" class="edge">
<title>25&#45;&gt;26</title>
<path fill="none" stroke="black" d="M577.07,-647.7C584.94,-639.22 594.56,-628.86 603.17,-619.58"/>
<polygon fill="black" stroke="black" points="605.88,-621.81 610.12,-612.1 600.75,-617.05 605.88,-621.81"/>
</g>
<!-- 26&#45;&gt;1 -->
<g id="edge26" class="edge">
<title>26&#45;&gt;1</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.57,-592.93C793.69,-592.3 1250.83,-586.73 1294,-540 1304.86,-528.25 1301.65,-518.05 1294,-504 1287.09,-491.3 1275.68,-481.18 1263.54,-473.33"/>
<polygon fill="black" stroke="black" points="1265,-470.13 1254.62,-468.01 1261.41,-476.14 1265,-470.13"/>
</g>
<!-- 26&#45;&gt;13 -->
<g id="edge27" class="edge">
<title>26&#45;&gt;13</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.37,-591.17C523.6,-587.02 375.57,-574.44 256,-540 198.36,-523.39 135.76,-493.43 96.24,-472.89"/>
<polygon fill="black" stroke="black" points="97.67,-469.69 87.19,-468.15 94.42,-475.89 97.67,-469.69"/>
</g>
<!-- 26&#45;&gt;14 -->
<g id="edge28" class="edge">
<title>26&#45;&gt;14</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.28,-592.27C531.24,-589.89 410.62,-580.07 318,-540 281.98,-524.42 246.87,-495.68 224.45,-475.07"/>
<polygon fill="black" stroke="black" points="226.76,-472.44 217.07,-468.16 221.97,-477.55 226.76,-472.44"/>
</g>
<!-- 26&#45;&gt;15 -->
<g id="edge29" class="edge">
<title>26&#45;&gt;15</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M608.7,-575.7C600.14,-567.14 589.66,-556.66 580.3,-547.3"/>
<polygon fill="black" stroke="black" points="582.65,-544.7 573.1,-540.1 577.7,-549.65 582.65,-544.7"/>
</g>
<!-- 26&#45;&gt;18 -->
<g id="edge30" class="edge">
<title>26&#45;&gt;18</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.41,-592.13C518.94,-589.54 362,-579.4 329,-540 313.67,-521.69 326.09,-495.45 339.68,-476.2"/>
<polygon fill="black" stroke="black" points="342.51,-478.27 345.7,-468.17 336.9,-474.07 342.51,-478.27"/>
</g>
<!-- 26&#45;&gt;19 -->
<g id="edge31" class="edge">
<title>26&#45;&gt;19</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.5,-581.44C558.75,-571.1 511.49,-555.72 473.43,-543.33"/>
<polygon fill="black" stroke="black" points="474.06,-539.85 463.47,-540.08 471.89,-546.51 474.06,-539.85"/>
</g>
<!-- 26&#45;&gt;20 -->
<g id="edge32" class="edge">
<title>26&#45;&gt;20</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M643.3,-575.7C651.86,-567.14 662.34,-556.66 671.7,-547.3"/>
<polygon fill="black" stroke="black" points="674.3,-549.65 678.9,-540.1 669.35,-544.7 674.3,-549.65"/>
</g>
<!-- 26&#45;&gt;21 -->
<g id="edge33" class="edge">
<title>26&#45;&gt;21</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.69,-582.37C696.71,-571.94 750.98,-555.77 794.06,-542.94"/>
<polygon fill="black" stroke="black" points="795.32,-546.22 803.9,-540.01 793.32,-539.51 795.32,-546.22"/>
</g>
<!-- 26&#45;&gt;23 -->
<g id="edge34" class="edge">
<title>26&#45;&gt;23</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.84,-587.72C721.41,-578.8 844.5,-559.78 948,-540 948.1,-539.98 948.2,-539.96 948.31,-539.94"/>
<polygon fill="black" stroke="black" points="948.84,-543.4 957.98,-538.04 947.49,-536.53 948.84,-543.4"/>
</g>
<!-- 26&#45;&gt;24 -->
<g id="edge35" class="edge">
<title>26&#45;&gt;24</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.7,-589.83C739.67,-582.73 931.2,-564.37 1102.48,-540.02"/>
<polygon fill="black" stroke="black" points="1103.03,-543.48 1112.43,-538.59 1102.04,-536.55 1103.03,-543.48"/>
</g>
<!-- 27 -->
<g id="node28" class="node">
<title>27</title>
<polygon fill="none" stroke="black" points="474.5,-252 337.5,-252 337.5,-216 474.5,-216 474.5,-252"/>
<text text-anchor="middle" x="406" y="-230.3" font-family="Times,serif" font-size="14.00">packet_inspector</text>
</g>
<!-- 27&#45;&gt;7 -->
<g id="edge36" class="edge">
<title>27&#45;&gt;7</title>
<path fill="none" stroke="black" d="M436.33,-215.88C452.7,-206.64 473.08,-195.13 490.65,-185.21"/>
<polygon fill="black" stroke="black" points="492.56,-188.15 499.55,-180.19 489.12,-182.06 492.56,-188.15"/>
</g>
<!-- 28 -->
<g id="node29" class="node">
<title>28</title>
<polygon fill="none" stroke="black" points="741,-684 643,-684 643,-648 741,-648 741,-684"/>
<text text-anchor="middle" x="692" y="-662.3" font-family="Times,serif" font-size="14.00">playground</text>
</g>
<!-- 28&#45;&gt;26 -->
<g id="edge37" class="edge">
<title>28&#45;&gt;26</title>
<path fill="none" stroke="black" d="M675.69,-647.7C667.69,-639.22 657.93,-628.86 649.18,-619.58"/>
<polygon fill="black" stroke="black" points="651.53,-616.98 642.13,-612.1 646.44,-621.78 651.53,-616.98"/>
</g>
<!-- 29 -->
<g id="node30" class="node">
<title>29</title>
<polygon fill="none" stroke="black" points="567.5,-252 492.5,-252 492.5,-216 567.5,-216 567.5,-252"/>
<text text-anchor="middle" x="530" y="-230.3" font-family="Times,serif" font-size="14.00">stresser</text>
</g>
<!-- 29&#45;&gt;7 -->
<g id="edge38" class="edge">
<title>29&#45;&gt;7</title>
<path fill="none" stroke="black" d="M530,-215.7C530,-207.98 530,-198.71 530,-190.11"/>
<polygon fill="black" stroke="black" points="533.5,-190.1 530,-180.1 526.5,-190.1 533.5,-190.1"/>
</g>
</g>
</svg>

For reference, here is a diff against the old depgraph.svg:

diff --git a/assets/depgraph.svg b/assets/depgraph.svg
index 4cb26c5..f45ea37 100644
--- a/assets/depgraph.svg
+++ b/assets/depgraph.svg
@@ -1,420 +1,421 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 9.0.0 (0)
+<!-- Generated by graphviz version 2.43.0 (0)
  -->
-<!-- Pages: 1 -->
-<svg width="1306pt" height="692pt"
- viewBox="0.00 0.00 1305.76 692.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<!-- Title: %3 Pages: 1 -->
+<svg width="1309pt" height="692pt"
+ viewBox="0.00 0.00 1309.14 692.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 688)">
-<polygon fill="white" stroke="none" points="-4,4 -4,-688 1301.76,-688 1301.76,4 -4,4"/>
+<title>%3</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-688 1305.14,-688 1305.14,4 -4,4"/>
 <!-- 0 -->
 <g id="node1" class="node">
 <title>0</title>
-<polygon fill="none" stroke="black" points="479,-684 384.25,-684 384.25,-648 479,-648 479,-684"/>
-<text text-anchor="middle" x="431.62" y="-661.33" font-family="Times,serif" font-size="14.00">java_string</text>
+<polygon fill="none" stroke="black" points="479.5,-684 384.5,-684 384.5,-648 479.5,-648 479.5,-684"/>
+<text text-anchor="middle" x="432" y="-662.3" font-family="Times,serif" font-size="14.00">java_string</text>
 </g>
 <!-- 1 -->
 <g id="node2" class="node">
 <title>1</title>
-<polygon fill="none" stroke="black" points="1294.62,-468 1122.62,-468 1122.62,-432 1294.62,-432 1294.62,-468"/>
-<text text-anchor="middle" x="1208.62" y="-445.32" font-family="Times,serif" font-size="14.00">valence_advancement</text>
+<polygon fill="none" stroke="black" points="1298.5,-468 1125.5,-468 1125.5,-432 1298.5,-432 1298.5,-468"/>
+<text text-anchor="middle" x="1212" y="-446.3" font-family="Times,serif" font-size="14.00">valence_advancement</text>
 </g>
 <!-- 2 -->
 <g id="node3" class="node">
 <title>2</title>
-<polygon fill="none" stroke="black" points="740.88,-396 618.38,-396 618.38,-360 740.88,-360 740.88,-396"/>
-<text text-anchor="middle" x="679.62" y="-373.32" font-family="Times,serif" font-size="14.00">valence_server</text>
+<polygon fill="none" stroke="black" points="742.5,-396 619.5,-396 619.5,-360 742.5,-360 742.5,-396"/>
+<text text-anchor="middle" x="681" y="-374.3" font-family="Times,serif" font-size="14.00">valence_server</text>
 </g>
 <!-- 1&#45;&gt;2 -->
 <g id="edge1" class="edge">
 <title>1&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M1122.16,-437.56C1019.27,-423.94 849.3,-401.45 752.69,-388.67"/>
-<polygon fill="black" stroke="black" points="753.16,-385.2 742.79,-387.36 752.24,-392.14 753.16,-385.2"/>
+<path fill="none" stroke="black" d="M1125.21,-437.56C1021.26,-423.86 849.11,-401.16 752.48,-388.42"/>
+<polygon fill="black" stroke="black" points="752.88,-384.95 742.51,-387.11 751.96,-391.89 752.88,-384.95"/>
 </g>
 <!-- 3 -->
 <g id="node4" class="node">
 <title>3</title>
-<polygon fill="none" stroke="black" points="667,-324 548.25,-324 548.25,-288 667,-288 667,-324"/>
-<text text-anchor="middle" x="607.62" y="-301.32" font-family="Times,serif" font-size="14.00">valence_entity</text>
+<polygon fill="none" stroke="black" points="668.5,-324 549.5,-324 549.5,-288 668.5,-288 668.5,-324"/>
+<text text-anchor="middle" x="609" y="-302.3" font-family="Times,serif" font-size="14.00">valence_entity</text>
 </g>
 <!-- 2&#45;&gt;3 -->
 <g id="edge2" class="edge">
 <title>2&#45;&gt;3</title>
-<path fill="none" stroke="black" d="M661.83,-359.7C653.35,-351.45 643.04,-341.43 633.69,-332.35"/>
-<polygon fill="black" stroke="black" points="636.16,-329.86 626.55,-325.4 631.28,-334.88 636.16,-329.86"/>
+<path fill="none" stroke="black" d="M663.2,-359.7C654.4,-351.14 643.62,-340.66 634,-331.3"/>
+<polygon fill="black" stroke="black" points="636.2,-328.57 626.59,-324.1 631.32,-333.58 636.2,-328.57"/>
 </g>
 <!-- 12 -->
 <g id="node5" class="node">
 <title>12</title>
-<polygon fill="none" stroke="black" points="818.5,-324 684.75,-324 684.75,-288 818.5,-288 818.5,-324"/>
-<text text-anchor="middle" x="751.62" y="-301.32" font-family="Times,serif" font-size="14.00">valence_registry</text>
+<polygon fill="none" stroke="black" points="821,-324 687,-324 687,-288 821,-288 821,-324"/>
+<text text-anchor="middle" x="754" y="-302.3" font-family="Times,serif" font-size="14.00">valence_registry</text>
 </g>
 <!-- 2&#45;&gt;12 -->
 <g id="edge3" class="edge">
 <title>2&#45;&gt;12</title>
-<path fill="none" stroke="black" d="M697.42,-359.7C705.9,-351.45 716.21,-341.43 725.56,-332.35"/>
-<polygon fill="black" stroke="black" points="727.97,-334.88 732.7,-325.4 723.09,-329.86 727.97,-334.88"/>
+<path fill="none" stroke="black" d="M699.04,-359.7C708.06,-351.05 719.12,-340.45 728.94,-331.03"/>
+<polygon fill="black" stroke="black" points="731.37,-333.55 736.16,-324.1 726.52,-328.5 731.37,-333.55"/>
 </g>
 <!-- 11 -->
 <g id="node6" class="node">
 <title>11</title>
-<polygon fill="none" stroke="black" points="774.25,-252 585,-252 585,-216 774.25,-216 774.25,-252"/>
-<text text-anchor="middle" x="679.62" y="-229.32" font-family="Times,serif" font-size="14.00">valence_server_common</text>
+<polygon fill="none" stroke="black" points="776,-252 586,-252 586,-216 776,-216 776,-252"/>
+<text text-anchor="middle" x="681" y="-230.3" font-family="Times,serif" font-size="14.00">valence_server_common</text>
 </g>
 <!-- 3&#45;&gt;11 -->
 <g id="edge4" class="edge">
 <title>3&#45;&gt;11</title>
-<path fill="none" stroke="black" d="M625.42,-287.7C633.9,-279.45 644.21,-269.43 653.56,-260.35"/>
-<polygon fill="black" stroke="black" points="655.97,-262.88 660.7,-253.4 651.09,-257.86 655.97,-262.88"/>
+<path fill="none" stroke="black" d="M626.8,-287.7C635.6,-279.14 646.38,-268.66 656,-259.3"/>
+<polygon fill="black" stroke="black" points="658.68,-261.58 663.41,-252.1 653.8,-256.57 658.68,-261.58"/>
 </g>
 <!-- 12&#45;&gt;11 -->
 <g id="edge12" class="edge">
 <title>12&#45;&gt;11</title>
-<path fill="none" stroke="black" d="M733.83,-287.7C725.35,-279.45 715.04,-269.43 705.69,-260.35"/>
-<polygon fill="black" stroke="black" points="708.16,-257.86 698.55,-253.4 703.28,-262.88 708.16,-257.86"/>
+<path fill="none" stroke="black" d="M735.96,-287.7C726.94,-279.05 715.88,-268.45 706.06,-259.03"/>
+<polygon fill="black" stroke="black" points="708.48,-256.5 698.84,-252.1 703.63,-261.55 708.48,-256.5"/>
 </g>
 <!-- 7 -->
 <g id="node10" class="node">
 <title>7</title>
-<polygon fill="none" stroke="black" points="597.25,-180 462,-180 462,-144 597.25,-144 597.25,-180"/>
-<text text-anchor="middle" x="529.62" y="-157.32" font-family="Times,serif" font-size="14.00">valence_protocol</text>
+<polygon fill="none" stroke="black" points="598,-180 462,-180 462,-144 598,-144 598,-180"/>
+<text text-anchor="middle" x="530" y="-158.3" font-family="Times,serif" font-size="14.00">valence_protocol</text>
 </g>
 <!-- 11&#45;&gt;7 -->
 <g id="edge11" class="edge">
 <title>11&#45;&gt;7</title>
-<path fill="none" stroke="black" d="M642.16,-215.52C622.49,-206.34 598.17,-194.99 577.19,-185.2"/>
-<polygon fill="black" stroke="black" points="578.79,-182.08 568.24,-181.02 575.82,-188.42 578.79,-182.08"/>
+<path fill="none" stroke="black" d="M644.06,-215.88C623.51,-206.35 597.75,-194.41 575.91,-184.28"/>
+<polygon fill="black" stroke="black" points="577.36,-181.1 566.82,-180.07 574.42,-187.45 577.36,-181.1"/>
 </g>
 <!-- 4 -->
 <g id="node7" class="node">
 <title>4</title>
-<polygon fill="none" stroke="black" points="458.38,-36 344.88,-36 344.88,0 458.38,0 458.38,-36"/>
-<text text-anchor="middle" x="401.62" y="-13.32" font-family="Times,serif" font-size="14.00">valence_math</text>
+<polygon fill="none" stroke="black" points="458,-36 344,-36 344,0 458,0 458,-36"/>
+<text text-anchor="middle" x="401" y="-14.3" font-family="Times,serif" font-size="14.00">valence_math</text>
 </g>
 <!-- 5 -->
 <g id="node8" class="node">
 <title>5</title>
-<polygon fill="none" stroke="black" points="709,-36 608.25,-36 608.25,0 709,0 709,-36"/>
-<text text-anchor="middle" x="658.62" y="-13.32" font-family="Times,serif" font-size="14.00">valence_nbt</text>
+<polygon fill="none" stroke="black" points="709.5,-36 608.5,-36 608.5,0 709.5,0 709.5,-36"/>
+<text text-anchor="middle" x="659" y="-14.3" font-family="Times,serif" font-size="14.00">valence_nbt</text>
 </g>
 <!-- 6 -->
 <g id="node9" class="node">
 <title>6</title>
-<polygon fill="none" stroke="black" points="590.38,-36 476.88,-36 476.88,0 590.38,0 590.38,-36"/>
-<text text-anchor="middle" x="533.62" y="-13.32" font-family="Times,serif" font-size="14.00">valence_ident</text>
+<polygon fill="none" stroke="black" points="590,-36 476,-36 476,0 590,0 590,-36"/>
+<text text-anchor="middle" x="533" y="-14.3" font-family="Times,serif" font-size="14.00">valence_ident</text>
 </g>
 <!-- 8 -->
 <g id="node11" class="node">
 <title>8</title>
-<polygon fill="none" stroke="black" points="532.38,-108 382.88,-108 382.88,-72 532.38,-72 532.38,-108"/>
-<text text-anchor="middle" x="457.62" y="-85.33" font-family="Times,serif" font-size="14.00">valence_generated</text>
+<polygon fill="none" stroke="black" points="532,-108 382,-108 382,-72 532,-72 532,-108"/>
+<text text-anchor="middle" x="457" y="-86.3" font-family="Times,serif" font-size="14.00">valence_generated</text>
 </g>
 <!-- 7&#45;&gt;8 -->
 <g id="edge5" class="edge">
 <title>7&#45;&gt;8</title>
-<path fill="none" stroke="black" d="M511.83,-143.7C503.35,-135.45 493.04,-125.43 483.69,-116.35"/>
-<polygon fill="black" stroke="black" points="486.16,-113.86 476.55,-109.4 481.28,-118.88 486.16,-113.86"/>
+<path fill="none" stroke="black" d="M511.96,-143.7C502.94,-135.05 491.88,-124.45 482.06,-115.03"/>
+<polygon fill="black" stroke="black" points="484.48,-112.5 474.84,-108.1 479.63,-117.55 484.48,-112.5"/>
 </g>
 <!-- 10 -->
 <g id="node12" class="node">
 <title>10</title>
-<polygon fill="none" stroke="black" points="655.25,-108 550,-108 550,-72 655.25,-72 655.25,-108"/>
-<text text-anchor="middle" x="602.62" y="-85.33" font-family="Times,serif" font-size="14.00">valence_text</text>
+<polygon fill="none" stroke="black" points="656,-108 550,-108 550,-72 656,-72 656,-108"/>
+<text text-anchor="middle" x="603" y="-86.3" font-family="Times,serif" font-size="14.00">valence_text</text>
 </g>
 <!-- 7&#45;&gt;10 -->
 <g id="edge6" class="edge">
 <title>7&#45;&gt;10</title>
-<path fill="none" stroke="black" d="M547.67,-143.7C556.36,-135.37 566.94,-125.22 576.48,-116.07"/>
-<polygon fill="black" stroke="black" points="578.65,-118.84 583.44,-109.39 573.8,-113.79 578.65,-118.84"/>
+<path fill="none" stroke="black" d="M548.04,-143.7C557.06,-135.05 568.12,-124.45 577.94,-115.03"/>
+<polygon fill="black" stroke="black" points="580.37,-117.55 585.16,-108.1 575.52,-112.5 580.37,-117.55"/>
 </g>
 <!-- 8&#45;&gt;4 -->
 <g id="edge7" class="edge">
 <title>8&#45;&gt;4</title>
-<path fill="none" stroke="black" d="M443.78,-71.7C437.34,-63.64 429.54,-53.89 422.41,-44.98"/>
-<polygon fill="black" stroke="black" points="425.23,-42.91 416.25,-37.29 419.77,-47.28 425.23,-42.91"/>
+<path fill="none" stroke="black" d="M443.16,-71.7C436.51,-63.39 428.42,-53.28 421.11,-44.14"/>
+<polygon fill="black" stroke="black" points="423.66,-41.73 414.68,-36.1 418.2,-46.1 423.66,-41.73"/>
 </g>
 <!-- 8&#45;&gt;6 -->
 <g id="edge8" class="edge">
 <title>8&#45;&gt;6</title>
-<path fill="none" stroke="black" d="M476.41,-71.7C485.45,-63.37 496.47,-53.22 506.41,-44.07"/>
-<polygon fill="black" stroke="black" points="508.69,-46.72 513.68,-37.37 503.95,-41.57 508.69,-46.72"/>
+<path fill="none" stroke="black" d="M475.79,-71.7C485.17,-63.05 496.68,-52.45 506.91,-43.03"/>
+<polygon fill="black" stroke="black" points="509.45,-45.45 514.43,-36.1 504.7,-40.3 509.45,-45.45"/>
 </g>
 <!-- 10&#45;&gt;5 -->
 <g id="edge9" class="edge">
 <title>10&#45;&gt;5</title>
-<path fill="none" stroke="black" d="M616.47,-71.7C622.91,-63.64 630.71,-53.89 637.84,-44.98"/>
-<polygon fill="black" stroke="black" points="640.48,-47.28 644,-37.29 635.02,-42.91 640.48,-47.28"/>
+<path fill="none" stroke="black" d="M616.84,-71.7C623.49,-63.39 631.58,-53.28 638.89,-44.14"/>
+<polygon fill="black" stroke="black" points="641.8,-46.1 645.32,-36.1 636.34,-41.73 641.8,-46.1"/>
 </g>
 <!-- 10&#45;&gt;6 -->
 <g id="edge10" class="edge">
 <title>10&#45;&gt;6</title>
-<path fill="none" stroke="black" d="M585.57,-71.7C577.38,-63.39 567.41,-53.28 558.41,-44.14"/>
-<polygon fill="black" stroke="black" points="561.06,-41.85 551.55,-37.18 556.07,-46.76 561.06,-41.85"/>
+<path fill="none" stroke="black" d="M585.7,-71.7C577.14,-63.14 566.66,-52.66 557.3,-43.3"/>
+<polygon fill="black" stroke="black" points="559.65,-40.7 550.1,-36.1 554.7,-45.65 559.65,-40.7"/>
 </g>
 <!-- 9 -->
 <g id="node13" class="node">
 <title>9</title>
-<polygon fill="none" stroke="black" points="908.12,-684 757.12,-684 757.12,-648 908.12,-648 908.12,-684"/>
-<text text-anchor="middle" x="832.62" y="-661.33" font-family="Times,serif" font-size="14.00">valence_build_utils</text>
+<polygon fill="none" stroke="black" points="911,-684 759,-684 759,-648 911,-648 911,-684"/>
+<text text-anchor="middle" x="835" y="-662.3" font-family="Times,serif" font-size="14.00">valence_build_utils</text>
 </g>
 <!-- 13 -->
 <g id="node14" class="node">
 <title>13</title>
-<polygon fill="none" stroke="black" points="111.25,-468 0,-468 0,-432 111.25,-432 111.25,-468"/>
-<text text-anchor="middle" x="55.62" y="-445.32" font-family="Times,serif" font-size="14.00">valence_anvil</text>
+<polygon fill="none" stroke="black" points="112,-468 0,-468 0,-432 112,-432 112,-468"/>
+<text text-anchor="middle" x="56" y="-446.3" font-family="Times,serif" font-size="14.00">valence_anvil</text>
 </g>
 <!-- 13&#45;&gt;2 -->
 <g id="edge13" class="edge">
 <title>13&#45;&gt;2</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M111.52,-433.77C114.59,-433.13 117.64,-432.53 120.62,-432 293.36,-401.43 499.45,-387.65 606.66,-382.16"/>
-<polygon fill="black" stroke="black" points="606.65,-385.66 616.47,-381.67 606.3,-378.67 606.65,-385.66"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M112.25,-433.7C115.2,-433.08 118.13,-432.51 121,-432 294.74,-401.27 502.17,-387.51 609.2,-382.08"/>
+<polygon fill="black" stroke="black" points="609.43,-385.58 619.24,-381.58 609.08,-378.58 609.43,-385.58"/>
 </g>
 <!-- 14 -->
 <g id="node15" class="node">
 <title>14</title>
-<polygon fill="none" stroke="black" points="269.5,-468 129.75,-468 129.75,-432 269.5,-432 269.5,-468"/>
-<text text-anchor="middle" x="199.62" y="-445.32" font-family="Times,serif" font-size="14.00">valence_boss_bar</text>
+<polygon fill="none" stroke="black" points="270,-468 130,-468 130,-432 270,-432 270,-468"/>
+<text text-anchor="middle" x="200" y="-446.3" font-family="Times,serif" font-size="14.00">valence_boss_bar</text>
 </g>
 <!-- 14&#45;&gt;2 -->
 <g id="edge14" class="edge">
 <title>14&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M269.78,-433.6C272.76,-433.04 275.72,-432.5 278.62,-432 392.78,-412.21 526.36,-395.91 606.9,-386.83"/>
-<polygon fill="black" stroke="black" points="606.86,-390.35 616.4,-385.76 606.08,-383.4 606.86,-390.35"/>
+<path fill="none" stroke="black" d="M270.15,-433.6C273.14,-433.04 276.1,-432.5 279,-432 394.08,-412.07 528.83,-395.71 609.43,-386.67"/>
+<polygon fill="black" stroke="black" points="609.92,-390.13 619.47,-385.55 609.14,-383.18 609.92,-390.13"/>
 </g>
 <!-- 15 -->
 <g id="node16" class="node">
 <title>15</title>
-<polygon fill="none" stroke="black" points="610.38,-540 502.88,-540 502.88,-504 610.38,-504 610.38,-540"/>
-<text text-anchor="middle" x="556.62" y="-517.33" font-family="Times,serif" font-size="14.00">valence_chat</text>
+<polygon fill="none" stroke="black" points="610,-540 502,-540 502,-504 610,-504 610,-540"/>
+<text text-anchor="middle" x="556" y="-518.3" font-family="Times,serif" font-size="14.00">valence_chat</text>
 </g>
 <!-- 16 -->
 <g id="node17" class="node">
 <title>16</title>
-<polygon fill="none" stroke="black" points="766.38,-468 658.88,-468 658.88,-432 766.38,-432 766.38,-468"/>
-<text text-anchor="middle" x="712.62" y="-445.32" font-family="Times,serif" font-size="14.00">valence_lang</text>
+<polygon fill="none" stroke="black" points="768,-468 660,-468 660,-432 768,-432 768,-468"/>
+<text text-anchor="middle" x="714" y="-446.3" font-family="Times,serif" font-size="14.00">valence_lang</text>
 </g>
 <!-- 15&#45;&gt;16 -->
 <g id="edge15" class="edge">
 <title>15&#45;&gt;16</title>
-<path fill="none" stroke="black" d="M595.59,-503.52C616.14,-494.29 641.56,-482.89 663.46,-473.06"/>
-<polygon fill="black" stroke="black" points="664.82,-476.29 672.51,-469 661.95,-469.9 664.82,-476.29"/>
+<path fill="none" stroke="black" d="M594.65,-503.88C616.25,-494.31 643.35,-482.3 666.27,-472.15"/>
+<polygon fill="black" stroke="black" points="667.75,-475.32 675.47,-468.07 664.91,-468.92 667.75,-475.32"/>
 </g>
 <!-- 17 -->
 <g id="node18" class="node">
 <title>17</title>
-<polygon fill="none" stroke="black" points="641.12,-468 490.12,-468 490.12,-432 641.12,-432 641.12,-468"/>
-<text text-anchor="middle" x="565.62" y="-445.32" font-family="Times,serif" font-size="14.00">valence_player_list</text>
+<polygon fill="none" stroke="black" points="642,-468 490,-468 490,-432 642,-432 642,-468"/>
+<text text-anchor="middle" x="566" y="-446.3" font-family="Times,serif" font-size="14.00">valence_player_list</text>
 </g>
 <!-- 15&#45;&gt;17 -->
 <g id="edge16" class="edge">
 <title>15&#45;&gt;17</title>
-<path fill="none" stroke="black" d="M558.85,-503.7C559.8,-496.32 560.93,-487.52 561.99,-479.25"/>
-<polygon fill="black" stroke="black" points="565.43,-479.97 563.23,-469.61 558.49,-479.08 565.43,-479.97"/>
+<path fill="none" stroke="black" d="M558.47,-503.7C559.57,-495.98 560.9,-486.71 562.13,-478.11"/>
+<polygon fill="black" stroke="black" points="565.61,-478.5 563.56,-468.1 558.68,-477.51 565.61,-478.5"/>
 </g>
 <!-- 17&#45;&gt;2 -->
 <g id="edge17" class="edge">
 <title>17&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M594.1,-431.52C608.63,-422.6 626.48,-411.63 642.12,-402.03"/>
-<polygon fill="black" stroke="black" points="643.53,-405.27 650.23,-397.05 639.87,-399.3 643.53,-405.27"/>
+<path fill="none" stroke="black" d="M594.13,-431.88C609.17,-422.72 627.87,-411.34 644.06,-401.48"/>
+<polygon fill="black" stroke="black" points="646.04,-404.38 652.76,-396.19 642.4,-398.4 646.04,-404.38"/>
 </g>
 <!-- 18 -->
 <g id="node19" class="node">
 <title>18</title>
-<polygon fill="none" stroke="black" points="433.5,-468 287.75,-468 287.75,-432 433.5,-432 433.5,-468"/>
-<text text-anchor="middle" x="360.62" y="-445.32" font-family="Times,serif" font-size="14.00">valence_command</text>
+<polygon fill="none" stroke="black" points="434,-468 288,-468 288,-432 434,-432 434,-468"/>
+<text text-anchor="middle" x="361" y="-446.3" font-family="Times,serif" font-size="14.00">valence_command</text>
 </g>
 <!-- 18&#45;&gt;2 -->
 <g id="edge18" class="edge">
 <title>18&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M433.81,-432.94C485.74,-421.55 555.13,-406.32 606.94,-394.95"/>
-<polygon fill="black" stroke="black" points="607.55,-398.4 616.57,-392.84 606.05,-391.56 607.55,-398.4"/>
+<path fill="none" stroke="black" d="M434.01,-433.03C486.61,-421.52 557.22,-406.08 609.47,-394.65"/>
+<polygon fill="black" stroke="black" points="610.31,-398.05 619.34,-392.49 608.82,-391.21 610.31,-398.05"/>
 </g>
 <!-- 19 -->
 <g id="node20" class="node">
 <title>19</title>
-<polygon fill="none" stroke="black" points="485.12,-540 340.12,-540 340.12,-504 485.12,-504 485.12,-540"/>
-<text text-anchor="middle" x="412.62" y="-517.33" font-family="Times,serif" font-size="14.00">valence_inventory</text>
+<polygon fill="none" stroke="black" points="484,-540 338,-540 338,-504 484,-504 484,-540"/>
+<text text-anchor="middle" x="411" y="-518.3" font-family="Times,serif" font-size="14.00">valence_inventory</text>
 </g>
 <!-- 19&#45;&gt;2 -->
 <g id="edge19" class="edge">
 <title>19&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M421.19,-503.84C432.17,-483.59 453.14,-450.37 480.62,-432 518.04,-406.99 566.77,-393.76 606.64,-386.77"/>
-<polygon fill="black" stroke="black" points="607.11,-390.24 616.41,-385.17 605.98,-383.34 607.11,-390.24"/>
+<path fill="none" stroke="black" d="M419.94,-503.83C431.37,-483.58 453.08,-450.36 481,-432 519.18,-406.89 568.81,-393.65 609.07,-386.68"/>
+<polygon fill="black" stroke="black" points="609.79,-390.11 619.09,-385.04 608.66,-383.2 609.79,-390.11"/>
 </g>
 <!-- 20 -->
 <g id="node21" class="node">
 <title>20</title>
-<polygon fill="none" stroke="black" points="763.25,-540 628,-540 628,-504 763.25,-504 763.25,-540"/>
-<text text-anchor="middle" x="695.62" y="-517.33" font-family="Times,serif" font-size="14.00">valence_network</text>
+<polygon fill="none" stroke="black" points="764,-540 628,-540 628,-504 764,-504 764,-540"/>
+<text text-anchor="middle" x="696" y="-518.3" font-family="Times,serif" font-size="14.00">valence_network</text>
 </g>
 <!-- 20&#45;&gt;2 -->
 <g id="edge20" class="edge">
 <title>20&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M737.65,-503.52C752.4,-495.1 767.35,-483.41 775.62,-468 783.2,-453.9 783.76,-445.78 775.62,-432 768.11,-419.26 756.31,-409.37 743.52,-401.78"/>
-<polygon fill="black" stroke="black" points="745.4,-398.81 734.94,-397.13 742.06,-404.97 745.4,-398.81"/>
+<path fill="none" stroke="black" d="M738.11,-503.87C753.18,-495.45 768.53,-483.67 777,-468 784.61,-453.93 785.13,-445.78 777,-432 769.14,-418.69 756.61,-408.48 743.16,-400.76"/>
+<polygon fill="black" stroke="black" points="744.7,-397.62 734.22,-396.04 741.43,-403.81 744.7,-397.62"/>
 </g>
 <!-- 20&#45;&gt;16 -->
 <g id="edge21" class="edge">
 <title>20&#45;&gt;16</title>
-<path fill="none" stroke="black" d="M699.83,-503.7C701.62,-496.32 703.75,-487.52 705.76,-479.25"/>
-<polygon fill="black" stroke="black" points="709.15,-480.12 708.11,-469.58 702.35,-478.47 709.15,-480.12"/>
+<path fill="none" stroke="black" d="M700.45,-503.7C702.45,-495.9 704.87,-486.51 707.1,-477.83"/>
+<polygon fill="black" stroke="black" points="710.5,-478.66 709.6,-468.1 703.72,-476.92 710.5,-478.66"/>
 </g>
 <!-- 21 -->
 <g id="node22" class="node">
 <title>21</title>
-<polygon fill="none" stroke="black" points="937.75,-540 781.5,-540 781.5,-504 937.75,-504 937.75,-540"/>
-<text text-anchor="middle" x="859.62" y="-517.33" font-family="Times,serif" font-size="14.00">valence_scoreboard</text>
+<polygon fill="none" stroke="black" points="939.5,-540 782.5,-540 782.5,-504 939.5,-504 939.5,-540"/>
+<text text-anchor="middle" x="861" y="-518.3" font-family="Times,serif" font-size="14.00">valence_scoreboard</text>
 </g>
 <!-- 21&#45;&gt;2 -->
 <g id="edge22" class="edge">
 <title>21&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M850.05,-503.59C838.57,-484.03 817.7,-452.36 792.62,-432 777.16,-419.44 758.22,-409.06 740.31,-400.93"/>
-<polygon fill="black" stroke="black" points="741.86,-397.79 731.3,-397 739.06,-404.2 741.86,-397.79"/>
+<path fill="none" stroke="black" d="M851.63,-503.94C840.2,-484.41 819.22,-452.48 794,-432 777.96,-418.97 758.18,-408.29 739.68,-400.02"/>
+<polygon fill="black" stroke="black" points="741.01,-396.78 730.44,-396.04 738.23,-403.21 741.01,-396.78"/>
 </g>
 <!-- 22 -->
 <g id="node23" class="node">
 <title>22</title>
-<polygon fill="none" stroke="black" points="1051,-684 926.25,-684 926.25,-648 1051,-648 1051,-684"/>
-<text text-anchor="middle" x="988.62" y="-661.33" font-family="Times,serif" font-size="14.00">valence_spatial</text>
+<polygon fill="none" stroke="black" points="1054.5,-684 929.5,-684 929.5,-648 1054.5,-648 1054.5,-684"/>
+<text text-anchor="middle" x="992" y="-662.3" font-family="Times,serif" font-size="14.00">valence_spatial</text>
 </g>
 <!-- 23 -->
 <g id="node24" class="node">
 <title>23</title>
-<polygon fill="none" stroke="black" points="1091.25,-540 956,-540 956,-504 1091.25,-504 1091.25,-540"/>
-<text text-anchor="middle" x="1023.62" y="-517.33" font-family="Times,serif" font-size="14.00">valence_weather</text>
+<polygon fill="none" stroke="black" points="1094,-540 958,-540 958,-504 1094,-504 1094,-540"/>
+<text text-anchor="middle" x="1026" y="-518.3" font-family="Times,serif" font-size="14.00">valence_weather</text>
 </g>
 <!-- 23&#45;&gt;2 -->
 <g id="edge23" class="edge">
 <title>23&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M986.34,-503.52C946.41,-485.01 881.02,-455.3 823.62,-432 796.52,-421 766.17,-409.68 740.35,-400.34"/>
-<polygon fill="black" stroke="black" points="741.6,-397.08 731.01,-396.98 739.23,-403.66 741.6,-397.08"/>
+<path fill="none" stroke="black" d="M989.26,-503.88C949.19,-485.41 883.01,-455.49 825,-432 796.96,-420.65 765.46,-408.94 739.09,-399.42"/>
+<polygon fill="black" stroke="black" points="740.22,-396.11 729.63,-396.02 737.85,-402.69 740.22,-396.11"/>
 </g>
 <!-- 24 -->
 <g id="node25" class="node">
 <title>24</title>
-<polygon fill="none" stroke="black" points="1281.62,-540 1109.62,-540 1109.62,-504 1281.62,-504 1281.62,-540"/>
-<text text-anchor="middle" x="1195.62" y="-517.33" font-family="Times,serif" font-size="14.00">valence_world_border</text>
+<polygon fill="none" stroke="black" points="1285.5,-540 1112.5,-540 1112.5,-504 1285.5,-504 1285.5,-540"/>
+<text text-anchor="middle" x="1199" y="-518.3" font-family="Times,serif" font-size="14.00">valence_world_border</text>
 </g>
 <!-- 24&#45;&gt;2 -->
 <g id="edge24" class="edge">
 <title>24&#45;&gt;2</title>
-<path fill="none" stroke="black" d="M1134.83,-503.58C1071.26,-485.43 968.55,-456.3 879.62,-432 837.37,-420.45 789.98,-407.88 751.94,-397.88"/>
-<polygon fill="black" stroke="black" points="752.99,-394.53 742.43,-395.38 751.21,-401.3 752.99,-394.53"/>
+<path fill="none" stroke="black" d="M1138.99,-503.94C1075.11,-485.84 971.02,-456.52 881,-432 838.53,-420.43 790.89,-407.79 752.76,-397.76"/>
+<polygon fill="black" stroke="black" points="753.34,-394.29 742.78,-395.13 751.56,-401.06 753.34,-394.29"/>
 </g>
 <!-- 25 -->
 <g id="node26" class="node">
 <title>25</title>
-<polygon fill="none" stroke="black" points="623.75,-684 497.5,-684 497.5,-648 623.75,-648 623.75,-684"/>
-<text text-anchor="middle" x="560.62" y="-661.33" font-family="Times,serif" font-size="14.00">dump_schedule</text>
+<polygon fill="none" stroke="black" points="624.5,-684 497.5,-684 497.5,-648 624.5,-648 624.5,-684"/>
+<text text-anchor="middle" x="561" y="-662.3" font-family="Times,serif" font-size="14.00">dump_schedule</text>
 </g>
 <!-- 26 -->
 <g id="node27" class="node">
 <title>26</title>
-<polygon fill="none" stroke="black" points="660.62,-612 590.62,-612 590.62,-576 660.62,-576 660.62,-612"/>
-<text text-anchor="middle" x="625.62" y="-589.33" font-family="Times,serif" font-size="14.00">valence</text>
+<polygon fill="none" stroke="black" points="661.5,-612 590.5,-612 590.5,-576 661.5,-576 661.5,-612"/>
+<text text-anchor="middle" x="626" y="-590.3" font-family="Times,serif" font-size="14.00">valence</text>
 </g>
 <!-- 25&#45;&gt;26 -->
 <g id="edge25" class="edge">
 <title>25&#45;&gt;26</title>
-<path fill="none" stroke="black" d="M576.69,-647.7C584.33,-639.47 593.6,-629.48 602.02,-620.42"/>
-<polygon fill="black" stroke="black" points="604.47,-622.92 608.71,-613.21 599.34,-618.16 604.47,-622.92"/>
+<path fill="none" stroke="black" d="M577.07,-647.7C584.94,-639.22 594.56,-628.86 603.17,-619.58"/>
+<polygon fill="black" stroke="black" points="605.88,-621.81 610.12,-612.1 600.75,-617.05 605.88,-621.81"/>
 </g>
 <!-- 26&#45;&gt;1 -->
 <g id="edge26" class="edge">
 <title>26&#45;&gt;1</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.04,-592.92C792.57,-592.24 1247.65,-586.53 1290.62,-540 1301.48,-528.25 1298.27,-518.05 1290.62,-504 1284.04,-491.9 1273.38,-482.15 1261.88,-474.46"/>
-<polygon fill="black" stroke="black" points="1263.76,-471.51 1253.4,-469.28 1260.11,-477.48 1263.76,-471.51"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.57,-592.93C793.69,-592.3 1250.83,-586.73 1294,-540 1304.86,-528.25 1301.65,-518.05 1294,-504 1287.09,-491.3 1275.68,-481.18 1263.54,-473.33"/>
+<polygon fill="black" stroke="black" points="1265,-470.13 1254.62,-468.01 1261.41,-476.14 1265,-470.13"/>
 </g>
 <!-- 26&#45;&gt;13 -->
 <g id="edge27" class="edge">
 <title>26&#45;&gt;13</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.36,-591.15C523.9,-586.97 376.06,-574.31 256.62,-540 199.55,-523.6 137.6,-494.26 97.79,-473.77"/>
-<polygon fill="black" stroke="black" points="99.5,-470.71 89.01,-469.2 96.27,-476.92 99.5,-470.71"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.37,-591.17C523.6,-587.02 375.57,-574.44 256,-540 198.36,-523.39 135.76,-493.43 96.24,-472.89"/>
+<polygon fill="black" stroke="black" points="97.67,-469.69 87.19,-468.15 94.42,-475.89 97.67,-469.69"/>
 </g>
 <!-- 26&#45;&gt;14 -->
 <g id="edge28" class="edge">
 <title>26&#45;&gt;14</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.18,-592.14C531.57,-589.58 411.8,-579.5 319.62,-540 283.63,-524.58 248.36,-496.4 225.48,-475.87"/>
-<polygon fill="black" stroke="black" points="227.9,-473.34 218.16,-469.16 223.17,-478.5 227.9,-473.34"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.28,-592.27C531.24,-589.89 410.62,-580.07 318,-540 281.98,-524.42 246.87,-495.68 224.45,-475.07"/>
+<polygon fill="black" stroke="black" points="226.76,-472.44 217.07,-468.16 221.97,-477.55 226.76,-472.44"/>
 </g>
 <!-- 26&#45;&gt;15 -->
 <g id="edge29" class="edge">
 <title>26&#45;&gt;15</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M608.57,-575.7C600.38,-567.39 590.41,-557.28 581.41,-548.14"/>
-<polygon fill="black" stroke="black" points="584.06,-545.85 574.55,-541.18 579.07,-550.76 584.06,-545.85"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M608.7,-575.7C600.14,-567.14 589.66,-556.66 580.3,-547.3"/>
+<polygon fill="black" stroke="black" points="582.65,-544.7 573.1,-540.1 577.7,-549.65 582.65,-544.7"/>
 </g>
 <!-- 26&#45;&gt;18 -->
 <g id="edge30" class="edge">
 <title>26&#45;&gt;18</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.27,-592.09C519.28,-589.43 363.38,-579.17 330.62,-540 315.75,-522.21 326.66,-496.72 339.3,-477.58"/>
-<polygon fill="black" stroke="black" points="342.13,-479.63 345.06,-469.45 336.42,-475.58 342.13,-479.63"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.41,-592.13C518.94,-589.54 362,-579.4 329,-540 313.67,-521.69 326.09,-495.45 339.68,-476.2"/>
+<polygon fill="black" stroke="black" points="342.51,-478.27 345.7,-468.17 336.9,-474.07 342.51,-478.27"/>
 </g>
 <!-- 26&#45;&gt;19 -->
 <g id="edge31" class="edge">
 <title>26&#45;&gt;19</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.45,-581.44C559.59,-571.3 513.93,-556.29 476.61,-544.03"/>
-<polygon fill="black" stroke="black" points="477.85,-540.75 467.26,-540.95 475.67,-547.4 477.85,-540.75"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M590.5,-581.44C558.75,-571.1 511.49,-555.72 473.43,-543.33"/>
+<polygon fill="black" stroke="black" points="474.06,-539.85 463.47,-540.08 471.89,-546.51 474.06,-539.85"/>
 </g>
 <!-- 26&#45;&gt;20 -->
 <g id="edge32" class="edge">
 <title>26&#45;&gt;20</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M642.93,-575.7C651.24,-567.39 661.35,-557.28 670.48,-548.14"/>
-<polygon fill="black" stroke="black" points="672.85,-550.72 677.45,-541.17 667.9,-545.77 672.85,-550.72"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M643.3,-575.7C651.86,-567.14 662.34,-556.66 671.7,-547.3"/>
+<polygon fill="black" stroke="black" points="674.3,-549.65 678.9,-540.1 669.35,-544.7 674.3,-549.65"/>
 </g>
 <!-- 26&#45;&gt;21 -->
 <g id="edge33" class="edge">
 <title>26&#45;&gt;21</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M660.91,-582.44C695.09,-572.22 747.85,-556.44 790.42,-543.7"/>
-<polygon fill="black" stroke="black" points="791.26,-547.11 799.83,-540.89 789.25,-540.4 791.26,-547.11"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.69,-582.37C696.71,-571.94 750.98,-555.77 794.06,-542.94"/>
+<polygon fill="black" stroke="black" points="795.32,-546.22 803.9,-540.01 793.32,-539.51 795.32,-546.22"/>
 </g>
 <!-- 26&#45;&gt;23 -->
 <g id="edge34" class="edge">
 <title>26&#45;&gt;23</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M660.88,-587.81C718.13,-579.25 835.08,-561.19 944.41,-540.37"/>
-<polygon fill="black" stroke="black" points="945,-543.82 954.16,-538.5 943.68,-536.95 945,-543.82"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.84,-587.72C721.41,-578.8 844.5,-559.78 948,-540 948.1,-539.98 948.2,-539.96 948.31,-539.94"/>
+<polygon fill="black" stroke="black" points="948.84,-543.4 957.98,-538.04 947.49,-536.53 948.84,-543.4"/>
 </g>
 <!-- 26&#45;&gt;24 -->
 <g id="edge35" class="edge">
 <title>26&#45;&gt;24</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M660.88,-589.87C738.15,-582.83 928.39,-564.58 1098.05,-540.32"/>
-<polygon fill="black" stroke="black" points="1098.3,-543.82 1107.7,-538.93 1097.3,-536.89 1098.3,-543.82"/>
+<path fill="none" stroke="black" stroke-dasharray="1,5" d="M661.7,-589.83C739.67,-582.73 931.2,-564.37 1102.48,-540.02"/>
+<polygon fill="black" stroke="black" points="1103.03,-543.48 1112.43,-538.59 1102.04,-536.55 1103.03,-543.48"/>
 </g>
 <!-- 27 -->
 <g id="node28" class="node">
 <title>27</title>
-<polygon fill="none" stroke="black" points="474,-252 337.25,-252 337.25,-216 474,-216 474,-252"/>
-<text text-anchor="middle" x="405.62" y="-229.32" font-family="Times,serif" font-size="14.00">packet_inspector</text>
+<polygon fill="none" stroke="black" points="474.5,-252 337.5,-252 337.5,-216 474.5,-216 474.5,-252"/>
+<text text-anchor="middle" x="406" y="-230.3" font-family="Times,serif" font-size="14.00">packet_inspector</text>
 </g>
 <!-- 27&#45;&gt;7 -->
 <g id="edge36" class="edge">
 <title>27&#45;&gt;7</title>
-<path fill="none" stroke="black" d="M436.6,-215.52C452.55,-206.51 472.19,-195.42 489.31,-185.76"/>
-<polygon fill="black" stroke="black" points="490.74,-188.97 497.73,-181 487.3,-182.87 490.74,-188.97"/>
+<path fill="none" stroke="black" d="M436.33,-215.88C452.7,-206.64 473.08,-195.13 490.65,-185.21"/>
+<polygon fill="black" stroke="black" points="492.56,-188.15 499.55,-180.19 489.12,-182.06 492.56,-188.15"/>
 </g>
 <!-- 28 -->
 <g id="node29" class="node">
 <title>28</title>
-<polygon fill="none" stroke="black" points="739.12,-684 642.12,-684 642.12,-648 739.12,-648 739.12,-684"/>
-<text text-anchor="middle" x="690.62" y="-661.33" font-family="Times,serif" font-size="14.00">playground</text>
+<polygon fill="none" stroke="black" points="741,-684 643,-684 643,-648 741,-648 741,-684"/>
+<text text-anchor="middle" x="692" y="-662.3" font-family="Times,serif" font-size="14.00">playground</text>
 </g>
 <!-- 28&#45;&gt;26 -->
 <g id="edge37" class="edge">
 <title>28&#45;&gt;26</title>
-<path fill="none" stroke="black" d="M674.56,-647.7C666.92,-639.47 657.65,-629.48 649.23,-620.42"/>
-<polygon fill="black" stroke="black" points="651.91,-618.16 642.54,-613.21 646.78,-622.92 651.91,-618.16"/>
+<path fill="none" stroke="black" d="M675.69,-647.7C667.69,-639.22 657.93,-628.86 649.18,-619.58"/>
+<polygon fill="black" stroke="black" points="651.53,-616.98 642.13,-612.1 646.44,-621.78 651.53,-616.98"/>
 </g>
 <!-- 29 -->
 <g id="node30" class="node">
 <title>29</title>
-<polygon fill="none" stroke="black" points="566.88,-252 492.38,-252 492.38,-216 566.88,-216 566.88,-252"/>
-<text text-anchor="middle" x="529.62" y="-229.32" font-family="Times,serif" font-size="14.00">stresser</text>
+<polygon fill="none" stroke="black" points="567.5,-252 492.5,-252 492.5,-216 567.5,-216 567.5,-252"/>
+<text text-anchor="middle" x="530" y="-230.3" font-family="Times,serif" font-size="14.00">stresser</text>
 </g>
 <!-- 29&#45;&gt;7 -->
 <g id="edge38" class="edge">
 <title>29&#45;&gt;7</title>
-<path fill="none" stroke="black" d="M529.62,-215.7C529.62,-208.41 529.62,-199.73 529.62,-191.54"/>
-<polygon fill="black" stroke="black" points="533.13,-191.62 529.63,-181.62 526.13,-191.62 533.13,-191.62"/>
+<path fill="none" stroke="black" d="M530,-215.7C530,-207.98 530,-198.71 530,-190.11"/>
+<polygon fill="black" stroke="black" points="533.5,-190.1 530,-180.1 526.5,-190.1 533.5,-190.1"/>
 </g>
 </g>
 </svg>

@ajh123
Copy link

ajh123 commented Jul 6, 2024

The chat signing system allows servers to be modify chat messages.

On my Paper based server I'm using a chat modification plugin called Carbon which can produce the following output (once configured properly)
image

Would this PR support it? I know I would need to make my own code to make the formatting I want.

Also, has this PR been tested behind a proxy like Velocity? If not, I can do the testing.

@ajh123
Copy link

ajh123 commented Jul 6, 2024

On my Paper based server I'm using a chat modification plugin called Carbon which ...
Would this PR support it? I know I would need to make my own code to make the formatting I want.

I think I've found my answer.

On this line https://github.com/guac42/valence/blob/7ac1f2b45c22a6b94da5bd8acbce55b88910caae/examples/chat.rs#L99 would I just need to modify what sender_name and message are based on what I want?

Edit:

send_chat_message should probably have another version that supports Text objects. This will use the Chat Formatting section of the Player Chat Message packet. Not sure which chat type Carbon uses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cryptographic chat support
6 participants