340 likes | 466 Views
Tabula. Components. GUI. Chat. Board. Log. Network. Patterns in our final design. = Strategy. Singleton. Model View Controller. Factory. Board Subsystem. Problem: A click, drag, move on the canvas means different things in different contexts: Click in erase mode, delete an object.
E N D
Components GUI Chat Board Log Network
Patterns in our final design = Strategy Singleton Model View Controller Factory
Board Subsystem • Problem: • A click, drag, move on the canvas means different things in different contexts: • Click in erase mode, delete an object. • Click and drag in ellipse mode, creates and resizes an object. • Dragging in select mode, drags a noose about the canvas. • Need an elegant way to change behavior at runtime.
Solutions? Naive Approach Architectural Approach • Global ‘mode’ variable. • Switching implemented in code • If (mode = ‘draw’) then if (mode = ‘square’) then … else …else if (mode = ‘erase’)…….=select…=edit…=text…. • Use the strategy pattern, by creating Classes of Contexts. • Abstract Context • Well defined interface • Concrete Context • E.g. ContextSquare • Implements methods defined in abstract Context • BoardController • Has abstract Context* field • setContext(); getContext()
Strategy Pattern & Contexts • “…to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable…
Version/History Solution • Problem: • Need to be able to go back to previous instances of canvas. • Solution: • Some sort of logging system. • Maintain history of all happenings and Events • Drawing, modifications, deletions by who. • Needs to be independent of Qt implementation.
Internal Event Representation • Use classes to represent events. • Need to Draw, Modify, Delete shapes such as Ellipse, Line, Rect etc… • Want it to be extensible • Add new operations in the future. • Add new graphic widgets.
Initial thoughts – Class Explosion • Name classes by what they do. • DrawEllipse, ModifyRect, DeleteLine etc.. • But… • E Operations. (3+); G Graphical Items. (5+) • ExG Classes, at least 15 classes today! Tommorow?! • Class Explosion. • Addition of 1 operation requires 5 classes to be written.
Use the Bridge Pattern. • 3 Event classes, Draw, ModifyDelete • Each event contains a pointer to QGraphicItem. • Would send the graphical object. • Object would arrive and be instantiated. • Could be any of concrete QEllipseItem, Rect, Line, etc… • …but not independent of Qt.
Final Solution • Use bridge pattern. • Instead of events containing QGraphicsItems… • Describe the objects using separate classes. • Objects are described by their (x,y) and width, height • Not by Qt’s representation when instantiated.
Storing logs on disk. • Could write to a log? XML! <Event type=“draw” source=“bob” time=“…”> <Object type =“rect”> <data x=“1” y=“1” width=“10” height=“10”> </Object></Event> • Good for representing logs on disk. • Could compress in future to save space. • Logs will always be meaningful - Qt Independent.
Drawing A Rectangle User clicks ‘Square’ button. ‘Click’ signal is emitted from button. Corresponding SquareButtonClicked() slot* in BoardController catches signal. BoardController‘s Context is set to SquareContext. The context is now set: The behavior of mouse event depends on the code in the SquareContext. SquareButton Board Controller
Mouse Down (Release) Board Controller QGraphicsView BoardModel RectContext Network Log mouseDownEvent(Event) Desc=new Rect() mouseDownEvent(Event) Rect Event=new(Desc) true Temp SendEvent(event) Add(Event) Execute() AddItem(item) AddItem(Item) Publish()
Mouse Move (Rectangle) Board Controller QGraphicsView BoardModel RectContext Network Log mouseUpEvent(Event) Desc=new Rect() mouseUpEvent(Event) Rect Event=new(Desc) true Temp SendEvent(event) Add(Event) Execute() AddItem(item) AddItem(Item) Publish()
Mouse Release (Rectangle) Board Controller QGraphicsView BoardModel RectContext Network Log mouseUpEvent(Event) Desc=new Rect() mouseUpEvent(Event) Rect Event=new(Desc) true Draw SendEvent(event) Add(Event) Execute() AddItem(item) AddItem(Item) Publish()
Timestamps • Issues of a distributed system: • Compare creation time of events • Create a history • Efficiently search for events • Uniquely identify events: • Shapes to be modified • Parent and child events in the history • Solution: Vector clocks (F. Mattern)
Timestamps (1,0,0) P1 (0,0,0) clock tick P2 (0,0,0) P3 (0,0,0) time
Timestamps (1,0,0) P1 (0,0,0) (1,0,0) P2 (0,0,0) update (1,0,0) P3 (0,0,0) update time
Timestamps (1,0,0) < (1,0,1) (1,0,0) P1 (0,0,0) (1,0,0) P2 (0,0,0) (1,0,0) P3 (0,0,0) (1,0,1) time
Timestamps (2,0,0) || (1,0,1) (1,0,0) (2,0,0) (2,0,1) P1 (0,0,0) (1,0,0) P2 (0,0,0) (1,0,0) P3 (0,0,0) (1,0,1) time
Timestamps (1,0,0) (2,0,0) (2,0,1) P1 (0,0,0) (1,0,0) P2 (0,0,0) (1,0,0) P3 (0,0,0) (1,0,1) • clock ticks only modify their own component • timestamps are only increasing • thus, timestamps are unique time
Network • Decentralised: • New peers can connect to any peer in the network • Increases chance of a successful connect when behind a NAT • Robust: • Recovers from network splits caused by disconnected peers • Low response time: • Actions across the network get a result as quickly as possible
Joining A Session • Client A: Creates a new session • Client B: Connects to client A and attempts to authenticate • Client A assigns a unique ID to client B and accepts the authentication • The Unique ID is used as the vector index in timestamps. • It is thus optimal to have low value IDs in the network. A B
Simultaneous Join A B D C • Problem: How do we create a unique ID for each? • Solution: ‘Paxos’ inspired algorithm for consensus within the network • Proposers: A and B - Propose an ID to the network • Acceptors: Accept or reject this ID. • Once all responses are collected, A and B decide who gets the ID via “Conflict Resolution" • The loser of conflict resolution renegotiates with the network, proposing a different ID
Message Paths • Messages are relayed across the network • Topology of the network is decided by connection order • Latency and traffic load are determined by where users connect • Flexible connections allow for NAT punch-through functionality. • Future enhancement: Automatic optimisation of topology?
Reconnects A B D C E • Suppose peer B disconnects. • The network is split • E and D are separated from A and C. • Session failure?
Reconnects A D C E • E attempts to connect to D • D attempts to connect to A • If connection fails another will be attempted until all options are exhausted • If B rejoins the session it will be updated with all past events • No data is lost.
Tug of War • “Slow Connection” • Race condition applies when moving objects • Last to release wins • “Fast Connection” • Temp move events sent • Users continually updated on current position • Temp move events send difference from last position • Multiple movers results in vector sum of movements
Dropped Features • Audio Chat • Provides a more immersive experience • Highly useful for Tablet PC users • RakNet has a VOIP plugin • Problems • Plugin unmaintained • Dependencies support outdated • Cross platform support – just for several year old OS’s • How to combine into logging
Dropped Features • Line correction • Common problem for Tablet PC users • Also of benefit to mouse users • Shape detection • Too ambitious • Could be a project all of its own • Support for adding both through extensions • Hook into Preprocessor • Tabbed canvases • Clever use of versioning system • Multiple instances
Optimisations • Changed from Double Precision Float to Short • Reduced size: ~ 1/4 • Also allowed for RakNet compression: ~ 1/2 • Overall reduction in network traffic: ~1/8 • Adjusted Freeform drawing to send updates • Improved log insertion from O(log n) to O(1) After optimization the majority of our packets are below 256 bytes