Better speculative local echo/editing. Also outputs debugging/timing info
This commit is contained in:
+103
-75
@@ -3,8 +3,9 @@
|
||||
|
||||
#include "terminalframebuffer.hpp"
|
||||
#include "network.hpp"
|
||||
#include "parser.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
namespace Overlay {
|
||||
using namespace Terminal;
|
||||
@@ -14,118 +15,142 @@ namespace Overlay {
|
||||
enum Validity {
|
||||
Pending,
|
||||
Correct,
|
||||
IncorrectOrExpired
|
||||
IncorrectOrExpired,
|
||||
Inactive
|
||||
};
|
||||
|
||||
/* The individual elements of an overlay -- cursor movements and replaced cells */
|
||||
class OverlayElement {
|
||||
class ConditionalOverlay {
|
||||
public:
|
||||
uint64_t prediction_time, expiration_time;
|
||||
bool flag; /* whether to bold for the user */
|
||||
uint64_t prediction_time, expiration_frame;
|
||||
int col;
|
||||
bool active; /* represents a prediction at all */
|
||||
bool tentative; /* whether to hide when score < 0 */
|
||||
|
||||
virtual void apply( Framebuffer &fb ) const = 0;
|
||||
virtual Validity get_validity( const Framebuffer & ) const;
|
||||
ConditionalOverlay( uint64_t s_exp, int s_col )
|
||||
: prediction_time( timestamp() ),
|
||||
expiration_frame( s_exp ), col( s_col ),
|
||||
active( false ),
|
||||
tentative( false )
|
||||
{}
|
||||
|
||||
OverlayElement( uint64_t s_expiration_time ) : prediction_time( timestamp() ),
|
||||
expiration_time( s_expiration_time ),
|
||||
flag( false ) {}
|
||||
virtual ~OverlayElement() {}
|
||||
virtual ~ConditionalOverlay() {}
|
||||
};
|
||||
|
||||
class OverlayCell : public OverlayElement {
|
||||
class ConditionalCursorMove : public ConditionalOverlay {
|
||||
public:
|
||||
int row;
|
||||
|
||||
int frozen_col, frozen_row; /* after a control character */
|
||||
|
||||
bool show_frozen_cursor;
|
||||
|
||||
void apply( Framebuffer &fb ) const;
|
||||
|
||||
Validity get_validity( const Framebuffer &fb, uint64_t current_frame ) const;
|
||||
|
||||
ConditionalCursorMove( uint64_t s_exp, int s_row, int s_col )
|
||||
: ConditionalOverlay( s_exp, s_col ), row( s_row ), frozen_col( -1 ), frozen_row( -1 ),
|
||||
show_frozen_cursor( false )
|
||||
{}
|
||||
|
||||
void freeze( void ) { if ( show_frozen_cursor ) { return; } frozen_col = col; frozen_row = row; show_frozen_cursor = true; }
|
||||
void thaw( void ) { show_frozen_cursor = false; }
|
||||
void reset( void ) { active = false; thaw(); }
|
||||
};
|
||||
|
||||
class ConditionalOverlayCell : public ConditionalOverlay {
|
||||
public:
|
||||
int row, col;
|
||||
Cell replacement;
|
||||
|
||||
OverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color );
|
||||
void apply( Framebuffer &fb ) const;
|
||||
};
|
||||
mutable uint64_t display_time;
|
||||
|
||||
class ConditionalOverlayCell : public OverlayCell {
|
||||
public:
|
||||
Cell original_contents;
|
||||
void apply( Framebuffer &fb, bool show_tentative, int row, bool flag ) const;
|
||||
Validity get_validity( const Framebuffer &fb, int row, uint64_t current_frame ) const;
|
||||
|
||||
Validity get_validity( const Framebuffer &fb ) const;
|
||||
|
||||
ConditionalOverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color,
|
||||
Cell s_original_contents )
|
||||
: OverlayCell( expiration_time, s_row, s_col, background_color ),
|
||||
original_contents( s_original_contents )
|
||||
ConditionalOverlayCell( int s_col )
|
||||
: ConditionalOverlay( 0, s_col ),
|
||||
replacement( 0 ),
|
||||
display_time( -1 )
|
||||
{}
|
||||
|
||||
void reset( void ) { active = false; display_time = -1; }
|
||||
};
|
||||
|
||||
class CursorMove : public OverlayElement {
|
||||
class ConditionalOverlayRow {
|
||||
public:
|
||||
int new_row, new_col;
|
||||
int row_num;
|
||||
vector<ConditionalOverlayCell> overlay_cells;
|
||||
|
||||
void apply( Framebuffer &fb ) const;
|
||||
void apply( Framebuffer &fb, bool show_tentative, bool flag ) const;
|
||||
|
||||
CursorMove( uint64_t expiration_time, int s_new_row, int s_new_col );
|
||||
ConditionalOverlayRow( int s_row_num ) : row_num( s_row_num ), overlay_cells() {}
|
||||
};
|
||||
|
||||
class ConditionalCursorMove : public CursorMove {
|
||||
public:
|
||||
Validity get_validity( const Framebuffer &fb ) const;
|
||||
|
||||
ConditionalCursorMove( uint64_t expiration_time, int s_new_row, int s_new_col )
|
||||
: CursorMove( expiration_time, s_new_row, s_new_col )
|
||||
{}
|
||||
};
|
||||
|
||||
/* the various overlays -- some predictive and some for local notifications */
|
||||
class OverlayEngine {
|
||||
protected:
|
||||
list<OverlayElement *> elements;
|
||||
|
||||
public:
|
||||
virtual void apply( Framebuffer &fb ) const;
|
||||
void clear( void );
|
||||
|
||||
typename list<OverlayElement *>::const_iterator begin( void ) { return elements.begin(); }
|
||||
typename list<OverlayElement *>::const_iterator end( void ) { return elements.end(); }
|
||||
|
||||
OverlayEngine() : elements() {}
|
||||
virtual ~OverlayEngine();
|
||||
};
|
||||
|
||||
class NotificationEngine : public OverlayEngine {
|
||||
/* the various overlays */
|
||||
class NotificationEngine {
|
||||
private:
|
||||
bool needs_render;
|
||||
|
||||
uint64_t last_word;
|
||||
uint64_t last_render;
|
||||
|
||||
uint64_t last_word_from_server;
|
||||
wstring message;
|
||||
uint64_t message_expiration;
|
||||
|
||||
public:
|
||||
bool need_countup( uint64_t ts ) const { return ts - last_word_from_server > 4500; }
|
||||
void adjust_message( void );
|
||||
void apply( Framebuffer &fb ) const;
|
||||
void set_notification_string( const wstring s_message );
|
||||
const wstring &get_notification_string( void ) { return message; }
|
||||
void server_ping( uint64_t s_last_word );
|
||||
void render_notification( void );
|
||||
void set_notification_string( const wstring s_message ) { message = s_message; message_expiration = timestamp() + 1000; }
|
||||
const wstring &get_notification_string( void ) const { return message; }
|
||||
void server_heard( uint64_t s_last_word ) { last_word_from_server = s_last_word; }
|
||||
uint64_t get_message_expiration( void ) const { return message_expiration; }
|
||||
|
||||
NotificationEngine();
|
||||
};
|
||||
|
||||
class PredictionEngine : public OverlayEngine {
|
||||
class PredictionEngine {
|
||||
private:
|
||||
Parser::UTF8Parser parser;
|
||||
|
||||
list<ConditionalOverlayRow> overlays;
|
||||
|
||||
ConditionalCursorMove cursor;
|
||||
|
||||
int score;
|
||||
|
||||
/* use the TCP timeout algorithm to measure appropriate echo prediction timeout */
|
||||
bool RTT_hit;
|
||||
double SRTT, RTTVAR;
|
||||
uint64_t local_frame_sent, local_frame_acked;
|
||||
|
||||
ConditionalOverlayRow & get_or_make_row( int row_num, int num_cols );
|
||||
|
||||
uint64_t prediction_checkpoint;
|
||||
|
||||
void become_tentative( void );
|
||||
|
||||
bool flagging;
|
||||
int prediction_len( void );
|
||||
|
||||
public:
|
||||
void cull( const Framebuffer &fb );
|
||||
void apply( Framebuffer &fb ) const;
|
||||
void new_user_byte( char the_byte, const Framebuffer &fb );
|
||||
void calculate_score( const Framebuffer &fb );
|
||||
void cull( const Framebuffer &fb );
|
||||
|
||||
PredictionEngine() : score( 0 ), RTT_hit( false ), SRTT( 1000 ), RTTVAR( 500 ), flagging( false ) {}
|
||||
void reset( void );
|
||||
|
||||
int get_score( void ) { return score; }
|
||||
void set_local_frame_sent( uint64_t x ) { local_frame_sent = x; }
|
||||
void set_local_frame_acked( uint64_t x ) { local_frame_acked = x; }
|
||||
|
||||
PredictionEngine( void ) : parser(), overlays(), cursor( 0, 0, 0 ), score( 0 ),
|
||||
local_frame_sent( 0 ), local_frame_acked( 0 ),
|
||||
prediction_checkpoint( timestamp() ), flagging( false )
|
||||
{
|
||||
become_tentative();
|
||||
}
|
||||
};
|
||||
|
||||
class TitleEngine {
|
||||
private:
|
||||
deque<wchar_t> prefix;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb ) const { fb.prefix_window_title( prefix ); }
|
||||
void set_prefix( const wstring s );
|
||||
TitleEngine() : prefix() {}
|
||||
};
|
||||
|
||||
/* the overlay manager */
|
||||
@@ -133,6 +158,7 @@ namespace Overlay {
|
||||
private:
|
||||
NotificationEngine notifications;
|
||||
PredictionEngine predictions;
|
||||
TitleEngine title;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb );
|
||||
@@ -140,7 +166,9 @@ namespace Overlay {
|
||||
NotificationEngine & get_notification_engine( void ) { return notifications; }
|
||||
PredictionEngine & get_prediction_engine( void ) { return predictions; }
|
||||
|
||||
OverlayManager() : notifications(), predictions() {}
|
||||
void set_title_prefix( const wstring s ) { title.set_prefix( s ); }
|
||||
|
||||
OverlayManager() : notifications(), predictions(), title() {}
|
||||
|
||||
int wait_time( void );
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user