1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
#ifndef TERMINAL_OVERLAY_HPP
#define TERMINAL_OVERLAY_HPP
#include "terminalframebuffer.hpp"
#include "network.hpp"
#include "parser.hpp"
#include <vector>
namespace Overlay {
using namespace Terminal;
using namespace Network;
using namespace std;
enum Validity {
Pending,
Correct,
CorrectNoCredit,
IncorrectOrExpired,
Inactive
};
class ConditionalOverlay {
public:
uint64_t expiration_frame;
uint64_t expiration_time; /* after frame is hit */
int col;
bool active; /* represents a prediction at all */
uint64_t tentative_until_epoch; /* when to show */
ConditionalOverlay( uint64_t s_exp, int s_col, uint64_t s_tentative )
: expiration_frame( s_exp ), expiration_time( -1 ), col( s_col ),
active( false ),
tentative_until_epoch( s_tentative )
{}
virtual ~ConditionalOverlay() {}
bool tentative( uint64_t confirmed_epoch ) const { return tentative_until_epoch > confirmed_epoch; }
void reset( void ) { expiration_frame = expiration_time = tentative_until_epoch = -1; active = false; }
bool start_clock( uint64_t local_frame_acked, uint64_t now, unsigned int send_interval );
void expire( uint64_t s_exp ) { expiration_frame = s_exp; expiration_time = uint64_t(-1); }
};
class ConditionalCursorMove : public ConditionalOverlay {
public:
int row;
void apply( Framebuffer &fb, uint64_t confirmed_epoch ) const;
Validity get_validity( const Framebuffer &fb, uint64_t sent_frame, uint64_t early_ack, uint64_t late_ack, uint64_t now ) const;
ConditionalCursorMove( uint64_t s_exp, int s_row, int s_col, uint64_t s_tentative )
: ConditionalOverlay( s_exp, s_col, s_tentative ), row( s_row )
{}
};
class ConditionalOverlayCell : public ConditionalOverlay {
public:
Cell replacement;
bool unknown;
vector<Cell> original_contents; /* we don't give credit for correct predictions
that match the original contents */
void apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const;
Validity get_validity( const Framebuffer &fb, int row, uint64_t sent_frame, uint64_t early_ack, uint64_t late_ack, uint64_t now ) const;
ConditionalOverlayCell( uint64_t s_exp, int s_col, uint64_t s_tentative )
: ConditionalOverlay( s_exp, s_col, s_tentative ),
replacement( 0 ),
unknown( false ),
original_contents()
{}
void reset( void ) { unknown = false; original_contents.clear(); ConditionalOverlay::reset(); }
void reset_with_orig( void ) {
if ( (!active) || unknown ) {
reset();
return;
}
vector<Cell> new_orig( original_contents );
new_orig.push_back( replacement );
reset();
original_contents = new_orig;
}
};
class ConditionalOverlayRow {
public:
int row_num;
vector<ConditionalOverlayCell> overlay_cells;
void apply( Framebuffer &fb, uint64_t confirmed_epoch, bool flag ) const;
ConditionalOverlayRow( int s_row_num ) : row_num( s_row_num ), overlay_cells() {}
};
/* the various overlays */
class NotificationEngine {
private:
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 ) { 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 {
private:
char last_byte;
Parser::UTF8Parser parser;
list<ConditionalOverlayRow> overlays;
list<ConditionalCursorMove> cursors;
uint64_t local_frame_sent, local_frame_acked, local_frame_late_acked;
ConditionalOverlayRow & get_or_make_row( int row_num, int num_cols );
uint64_t prediction_epoch;
uint64_t confirmed_epoch;
void become_tentative( void );
void newline_carriage_return( const Framebuffer &fb );
bool flagging;
ConditionalCursorMove & cursor( void ) { assert( !cursors.empty() ); return cursors.back(); }
void kill_epoch( uint64_t epoch, const Framebuffer &fb );
void init_cursor( const Framebuffer &fb );
uint64_t last_scheduled_timeout;
unsigned int send_interval;
public:
void apply( Framebuffer &fb ) const;
void new_user_byte( char the_byte, const Framebuffer &fb );
void cull( const Framebuffer &fb );
void reset( void );
bool active( void ) { return timestamp() <= last_scheduled_timeout; }
void set_local_frame_sent( uint64_t x ) { local_frame_sent = x; }
void set_local_frame_acked( uint64_t x ) { local_frame_acked = x; }
void set_local_frame_late_acked( uint64_t x ) { local_frame_late_acked = x; }
void set_send_interval( unsigned int x ) { send_interval = x; }
PredictionEngine( void ) : last_byte( 0 ), parser(), overlays(), cursors(),
local_frame_sent( 0 ), local_frame_acked( 0 ),
local_frame_late_acked( 0 ),
prediction_epoch( 1 ), confirmed_epoch( 0 ),
flagging( false ), last_scheduled_timeout( 0 ),
send_interval( 250 )
{
}
};
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 */
class OverlayManager {
private:
NotificationEngine notifications;
PredictionEngine predictions;
TitleEngine title;
public:
void apply( Framebuffer &fb );
NotificationEngine & get_notification_engine( void ) { return notifications; }
PredictionEngine & get_prediction_engine( void ) { return predictions; }
void set_title_prefix( const wstring s ) { title.set_prefix( s ); }
OverlayManager() : notifications(), predictions(), title() {}
int wait_time( void );
};
}
#endif
|