» branch_boygrouping
This site relies heavily on Javascript. You should enable it if you want the full experience. Learn more.

branch_boygrouping

acl(admin devvvv vvvvgroup)

Boygrouping Rework

ziele

  • relative pfade müssen auf clients funktionieren
  • renderfenster müssen auf den richtigen devices geöffnet werden
  • patch-hierarchisch-spezifische knoten wie patchalias/getpatch,setpatch,self etc. machen nun auch auf dem client sinn und führen zum erwünschten resultat

was erstmal nicht passiert

  • automatische medien-synchronisieren (hierzu mal das mirror.exe tool mit einem patch versehen?)
  • peer to peer boygrouping
  • permanente selektionen

...

kann passieren

  • clients/server werden ohne commandline gestartet. das anlegen der jeweiligen boygroup knoten initialisiert boygrouping

bisherige code struktur

GNet

  • ist eine Instanz von TMNetWorkSystem (NetworkObjects.pas)
  • wird immer(!) zu programmstart angelegt
  • hat TMNetworkCommander (i.e. Client oder Server aus ClientCommander.pas)
  • hat TMNetwork -> TMTCPIPNetwork (TCPIPNetwork.pas)
  • hat eine TCP connection für graph changes
  • hat eine UDP connection für value changes

TMTCPIPNetwork

  • vereint Server und Client, unterschieden nur durch FIsServer
  • hat eine liste von clients -> TMTCPIPNetworkMachine
  • erledigt die tatsächliche netzwerkkommunikation
  • OnReceiveData() ruft tatsächlich TMBasicNetworkCommander.ReceiveCB auf!

TMBasicNetworkCommander

  • .ReceiveCB empfängt die von TMTCPIPNetwork decodierten VVVV-Network Messages
  • reagiert auf die einzelnen Message-commands
  • unimplemented command: SubscribePinValueStream

Network Packet Layout

{CODE(ln=>0)}TMNetworkMessageHeader = record

 MagicNumber: longword;  // for identifying the beginning of a packet.
 MachineID: longword;    // the receiver id, is ALL=9999 for broadcast
 CommandID: longword;    // numbering of outgoing messages check for missing packets
 Command : TMCommandID;  // DATA, FLUSH
 Size : Longword;        // size of data structure
 Data: array of Byte;    // data

end;

Sample Flush Broadcast:

210 2 150 73 15 39 0 0 241 226 2 0 35 97 0 0 0 0 0 0 0 0 0 0
{CODE(ln=>0)}
210 2 150 73 -> MagicNumber: 1234567890

 15  39   0   0 -> MachineID: 9999 (all)

241 226 2 0 -> CommandID: DebugCounter (increasing number)

 35  97   0   0 -> Command: cmncFlush = $6123;
  0   0   0   0 -> Size: 0
  0   0   0   0 -> Data: 4 bytes of nothing

Sample Bridge Broadcast:

210 2 150 73 15 39 0 0 255 4 0 0 35 81 0 0 28 0 0 0 11 0 0 0 17 0 0 0 47 51 47 32 89 32 73 110 112 117 116 32 86 97 108 117 101 49 55 0
{CODE(ln=>0)}
210 2 150 73 -> MagicNumber

 15  39   0   0 -> MachineID

124 229 3 0 -> CommandID

 35  81   0   0 -> Command: cmncData = $5123;
 28   0   0   0 -> Size: 28 byte
 11   0   0   0 -> cmgncSetBridgeValueThroughHierarchie
 17   0   0   0 -> length(path)
 47  51  47  32 -> / 3 /   
 89  32  73 110 -> Y   I n

112 117 116 32 -> p u t

 86  97 108 117 -> V a l u

101 49 55 0 -> e 1 7 #0
^

Debugging Utils

With the Flush the Server sends its time and the number of all messages sent. From this number the client can check if it has missed a message.

Boygroup (Server)

Outputs:

  • Connected
  • Messages Sent
  • Bytes Sent
  • BridgeCount
  • Active Bridges

Boygroup (Client)

Outputs:

  • ClientID
  • Messages Received
  • Bytes Received
  • Messages Missed

new style

zur bisherigen struktur

  • GNet wird um 2 neue modi (client&server) erweitert. ansonsten: bleibt
  • TMTCPIPNetwork bleibt
  • TMBasicNetworkCommander bekommt einen vorfahr, der die messages cleargraph, requestdump und timestamp verarbeiten kann
  • von diesem vorfahr werden weitere ActionCommanders (name der unit) abgeleitet, die zusätzlich die neuen messages verarbeiten können (erklärungen zu diesen weiter unten):
    • PerformAction
    • SetBridgeValueThroughHierarchie ( "01/12/14/Filtertime", "14.000" )

bezeichnungen & strukturelles

  • der einzige knoten im superroot des servers ist der root des servers.
  • der superroot des clients enthält 2 knoten: den normalen root und den "clientroot" der ein abbild des superroots des servers darstellt.
  • logischer knoten: knoten einer patchklasse. abhängig von der patch-hierarchie über ihm ist dieser knoten einfach, mehrfach oder gar nicht instanziiert. er hat eine id, die sich auf die patchklasse bezieht. es wird sichergestellt, dass logische knoten auf client und server die gleichen ids haben.
  • server-node: logischer knoten, der nicht geboygroupt ist
  • client-node: logischer konten, der geboygroupt ist
  • flat-client-node: instanz eines client-nodes oder instanz eines server-nodes, die in einem flat-client-node liegt.
  • flat-server-node: not flat-client-node
  • brücke: link, der einen ausgang eines flat-server-nodes mit einem eingang eines flat-client-nodes verbindet

das prinzip

clients erhalten die kompletten patchklasses, wie sie auch am server existieren.
dazu wird als erste aktion auf einen client-request-dump mit einer server-cleargraph message und der anschliessenden übertragung aller patchklassen geantwortet.
als letzte reaktion auf den client-request-dump wird der client vom server aufgefordet den server-root-knoten in seinem dafür vorgesehenen clientroot anzulegen.
dadurch wird unter beachtung der boygroup-manager der gesamte graph aufgebaut.

änderungen werden als inkrementelle messages übertragen, wie das auch jetzt schon lokal geschieht.

patches laden

beim laden eines patches genügt es nicht nur geboygroupte teile zu übertragen. ein client muss die gesamte patchstruktur bis hin zum geboygroupten teil auch aufbauen, um einen geboygroupten knoten in allen instanzen des patches auf dem client anlegen zu können. nur wenn die gesamte patchstruktur des servers auf dem client abgebildet wird kann sichergestellt werden, dass alle instanzen des patches auf dem client vorliegen.

patches speichern

wird auf dem server ein patch unter anderem namen gespeichert muss die änderung des patchnamens dem client mitgeteilt werden, da die identifizierung einer action über den namen der patchklasse geregelt wird. hierfür muss eine neu action eingeführt werden.

implementierungsdetails

if you think of a patch as an instance of a patchclass which can be instanciated more than one time in a patchsystem, then you will notice that it is possible to have a patchclass which holds some boygrouped nodes and therefore is partly boygrouped in one scenario, but in another instance is completely boygrouped because itself is just boygrouped in its parent patch.

so two instances of the same patchclass can look differntly on a client.

however to keep the system simple the patchclasses are always transmitted completely, so that that there is no need to seperate between partly boygrouped patches and completely bougrouped patches. so always transmitting the whole patchclasses of the server just reflects that it is all about the global structure and not about the logical nodes within a patch.

since the patchclasses are maintained on the client in the same way as on the server, the only way to react on boygroup-specific actions is within the patch instances.

a boygrouped instance of a patch behaves like a patch on the server.

a not boygrouped instance reacts on all node (including their childs actions) and link actions (so all actions) if the involved nodes already exist.

a node within a non-boygrouped patch instance is created when a corresponding boygroup-manager action is attached.

a node is deleted if it is deleted on the server or when a node action comes with a local-manager action.

-
a patch class is renamed when the patch action comes with an attribute "saveme".

MEHR DETAILS:

boygroupen von patches:

auf dem client werden dadurch alle knoten innerhalb des patches angelegt. auch links werden gezogen und pins eingestellt. es wird also am besten die komplette currentdescription noch einmal auf der betroffenen instanz ausgeführt. knoten die im patch schon geboygrouped waren werden nicht belangt. werden durch die aktion weitere subpatches geboygrouped ist auch dies implizit zu tun. der server wird nicht alle patchklassen neu schicken. ein knoten sollte im allgemeinen nicht nur seinen logischen boygroup state kennen, sondern auch seinen physikalischen, der vom eigenen logischen und vom physikalischen boygroup state des nächst drüber liegenden parents abhängig ist. der physikalische boygroup state muss bei der impliziten reaktion gesetzt werden und zu möglichen weiteren impliziten reaktionen führen.
property Boygrouped : Boolean read FBoygrouped write SetBoygrouped;

unboygroupen von patches:
same as above.

old:
momentan werden knoten mit halben all ihren links gelöscht und dann mit neuem manager wieder angelegt.

exkurs: umbennenung von ioboxen:

kann eigentlich nur vereinzelt auftreten und kann in sofortiger reaktion münden, indem alle parent patches die betroffenen links ausfindig machen, die alten links löschen und neue ziehen. dies hat in allen patchclassen mit entsprechenden actions zu passieren. am besten wäre sicherlich die sammlung aller instanzen des patches in den jeweiligen parentpatchklassen um die aktionen dann gemeinsam zu verschicken. dazu könnte man sich alle parentpatchklassen ansehen und in eine liste stecken, versehen mit allen ids der jeweiligen instanzen der eigenen klasse innerhalb des parents. danach wird für jede parentklasse eine patchaction zusammengestellt die die links löscht bzw nach dem umbenennen der iobox die neuen links zieht...

frage nur wann genau das passieren soll. schon beim analysieren der aktion in der patchklasse?

boygroupen von ioboxen:

kann clientseitig dazu führen, dass ein link in einem oder mehreren parentpatches sinn macht, der in deren description gespeichert ist. (und zu dem neu hinzugekommenen pin des patches führt).

denkbar hierfür eine ähnliche aktion auszuführen wie beim exkurs (unabhängig vom boygrouping). sicher wäre dass dies hier implizit sein sollte, da der parent tatsächlich nicht verändert wird. eigentlich sollte es ausreichen auf aktionen komplett zu verzichten sondern direkt die currentdescription anzuschauen und entsprechende links zu bestätigen.

generell sollte nochmal das implizite löschen von fehlgeschlagenen aktionen gaanz genau durchgesehen werden, da ab jetzt viel mehr aktionen fehlschlagen können als bisher. AUSSER es werden alle physikalischen boygroupstates immer brav abgefragt bevor bspw versucht wird auf einem client einen link zu ziehen.

old:
wenn aber beim boygroupen der knoten komplett zerstört wird bricht auch serverseitig die verbindung auf (bzw. wird nicht neu gezogen). trifft auch aufs un-boygroupen zu.

current:
beim boygroupen werden die ungeboygroupten knoten nicht mehr entfernt und neu gebaut. deshalb bricht die verbindung serverseitig nicht mehr auf. deshalb ist es wichtig nun auch dafür zu sorgen auf dem client das gleiche verhalten zu bekommen. deshalb: (still todo)

new action: path

mehrere szenarios:

  • ein path existiert auf dem client nicht

oder

  • wird aus anderen gründen anders aufgelöst, weil der vvvv folder auf dem client andere module enthält als auf dem server etc.

relative pfade zu subpatches und modulen sollen nicht auf dem client neu aufgelöst werden, da der client sowieso nicht von dort lädt. unabhängig ob das jeweilige verzeichnis auf dem client existiert soll der client patch den gleichen pfad wie der server verwenden. immer.
dafür wird ab jetzt jede action zu einem subpatch oder module mit einem attribut für den absoluten pfad versehen. ein client nimmt dann diesen pfad. ein server oder standalone löst den pfad wie bisher relativ auf.

anlegen von modulen, subpatches

alle patches werden gleich behandelt. es gibt für den client keine module.

brücken

addressierung der pins

es sollte reichen dass sich ein rechner (der server) um die verwaltung von brücken kümmert. im einfachsten fall würden die messages die jedes frame geschickt werden einen pfad zum pin und die neuen werte enthalten. hat den nachteil, dass dieser pfad für jeden pin in jedem frame geparst werden muss.
optional wäre eine neue message, die bei jeder änderung der brücken die komplette liste von brücken-pfaden den clients übermittelt. in dem fall würde der client die brücken einmal parsen und dann jedes frame nur noch auf brücken-id + werte warten und die jeweiligen pins schon parat haben.

da jedoch

  • die anzahl der brücken erstmal gering eingeschätzt wird,
  • der per-frame parsing-aufwand doch sehr übersichtlich erscheint,
  • die verwaltung der brücken-ids probleme bergen kann (bei neuer vergabe von brücken-ids und langsamen udp messages könnte die zuordnung für ein frame mglw. schief gehen?!)
  • aus simplicity-gründen

wird erstmal der erstere einfachere ansatz umgesetzt.

die neue message auf commander-ebene:
SetBridgeValueThroughHierarchie ( "01/12/14/Filtertime"+"14.000" )

brückenbau

jede Aktion kann u.U. zu verschiebung von Brücken führen. Um nicht jede inkrementelle Änderung am Patchsystem unterscheiden zu müssen (e.g. subpatch boygroupen, link löschen ...), gibt es momentan nur eine Methode zum nachträglichen Erkennen eines Brückenfalls (gray to blue node), zum Löschen einer Brücke gibt es kein System. Wird die Notwendigkeit einer Brücke erkannt, wird diese an einen Manager geschickt (GBridgeFactory). Dieser Manager wird vor und nach inkrementellen Änderungen an Patchklassen (also PerformAction) benachrichtigt und kümmert sich um die "Garbagecollection" der Brücken...

jede performaction (auch undo und redo) ist so gekapselt:

  • Aktion local ausführen
  • Aktion an Clients schicken
  • Brücken updaten:
    • Vorbereiten auf Brückenbau (merke alte bridges)
    • Komplettes Patchsystem bitten die Bridges neu zu bauen (unter Beachtung, ob diese schon existeirten
    • Brückenbau abschliessen (Nicht mehr gebrauchte bridges löschen)

Erkennung eines Brückenschlags

UserConnection geht von grauem Knoten (flat-client-node) zu blauem Knoten (flat-server-node). Beschreibung oben. s/r nodes funktionieren mit diesem system momentan nur wenn auch der s node geboygroupet ist.

Brückensynchronisierung

Kommt ein request dump reagiert der server nicht nur mit "clear graph + send all patches", sondern schickt auch die momentan vorhandenen Brücken via TCP an den betreffenden Client.
In jedem Frame werden die Brücken über UDP gebroadcastet, falls sich deren Wert verändert hat.
Für den ValuePin wir eine optimierte Methode aufgerufen, die die Werte nachträglich vergleicht (Brücke hat eigenen Cache hierfür).
Für alle anderen Pins (inkl. DiffValuePin) wird das ObserverPinChanged abgefragt.

Current TODO

  • gui details
  • (allow users to patch on client patches and to store them, id management of nodes)
  • ioboxen boygroup fix
  • offtopic: undo link drawing results in a pin holding a new value instead of the old
  • think about a solution for s/r nodes when s is not boygrouped, but r is.

anonymous user login

Shoutbox

~4d ago

~7d ago

joreg: The Winter Season of vvvv workshops is now over but all recordings are still available for purchase: https://thenodeinstitute.org/ws23-vvvv-intermediates/

~14d ago

schlonzo: Love the new drag and drop functionality for links in latest previews!

~22d ago

joreg: Workshop on 29 02: Create Sequencers and Precise Clock Based Tools. Signup here: https://thenodeinstitute.org/courses/ws23-vvvv-08-create-sequencers-and-precise-clock-based-tools-in-vvvv-gamma/

~29d ago

joreg: Workshop on 22 02: Unlocking Shader Artistry: A Journey through ‘The Book of Shaders’ with FUSE. Signup here: https://thenodeinstitute.org/courses/ws23-vvvv-12-book-of-shaders/

~1mth ago

joreg: Talk and Workshop on February 15 & 16 in Frankfurt: https://visualprogramming.net/blog/vvvv-at-node-code-frankfurt/

~1mth ago

woei: @Joanie_AntiVJ: think so, looks doable

~1mth ago

xd_nitro: Anyone remember who increased projector brightness by removing some components that product the color?

~1mth ago

Joanie_AntiVJ: This looks super interesting (vectors over network) would anyone here know how to implement this in beta? https://github.com/madmappersoftware/Ponk