This repository has been archived by the owner on Jul 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathwatermark.lua
643 lines (547 loc) · 28.3 KB
/
watermark.lua
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
-- local variables for API functions. any changes to the line below will be lost on re-generation
local client_latency, client_screen_size, client_set_event_callback, client_system_time, entity_get_local_player, entity_get_player_resource, entity_get_prop, globals_absoluteframetime, globals_tickinterval, math_ceil, math_floor, math_min, math_sqrt, renderer_measure_text, ui_reference, pcall, renderer_gradient, renderer_rectangle, renderer_text, string_format, table_insert, ui_get, ui_new_checkbox, ui_new_color_picker, ui_new_multiselect, ui_new_textbox, ui_set, ui_set_callback, ui_set_visible = client.latency, client.screen_size, client.set_event_callback, client.system_time, entity.get_local_player, entity.get_player_resource, entity.get_prop, globals.absoluteframetime, globals.tickinterval, math.ceil, math.floor, math.min, math.sqrt, renderer.measure_text, ui.reference, pcall, renderer.gradient, renderer.rectangle, renderer.text, string.format, table.insert, ui.get, ui.new_checkbox, ui.new_color_picker, ui.new_multiselect, ui.new_textbox, ui.set, ui.set_callback, ui.set_visible
local flag, old_renderer_text, old_renderer_measure_text = "d", renderer_text, renderer_measure_text
function renderer_text(x, y, r, g, b, a, flags, max_width, ...)
return old_renderer_text(x, y, r, g, b, a, flags == nil and flag or flag .. flags, max_width, ...)
end
function renderer_measure_text(flags, ...)
return old_renderer_measure_text(flags == nil and flag or flag .. flags, ...)
end
local allow_unsafe_scripts = pcall(client.create_interface)
local FLOW_OUTGOING, FLOW_INCOMING = 0, 1
local native_GetNetChannelInfo, GetRemoteFramerate, native_GetTimeSinceLastReceived, native_GetAvgChoke, native_GetAvgLoss, native_IsLoopback, GetAddress
if allow_unsafe_scripts then
local ffi = require "ffi"
local function vmt_entry(instance, index, type)
return ffi.cast(type, (ffi.cast("void***", instance)[0])[index])
end
local function vmt_thunk(index, typestring)
local t = ffi.typeof(typestring)
return function(instance, ...)
assert(instance ~= nil)
if instance then
return vmt_entry(instance, index, t)(instance, ...)
end
end
end
local function vmt_bind(module, interface, index, typestring)
local instance = client.create_interface(module, interface) or error("invalid interface")
local fnptr = vmt_entry(instance, index, ffi.typeof(typestring)) or error("invalid vtable")
return function(...)
return fnptr(instance, ...)
end
end
native_GetNetChannelInfo = vmt_bind("engine.dll", "VEngineClient014", 78, "void*(__thiscall*)(void*)")
local native_GetName = vmt_thunk(0, "const char*(__thiscall*)(void*)")
local native_GetAddress = vmt_thunk(1, "const char*(__thiscall*)(void*)")
native_IsLoopback = vmt_thunk(6, "bool(__thiscall*)(void*)")
local native_IsTimingOut = vmt_thunk(7, "bool(__thiscall*)(void*)")
native_GetAvgLoss = vmt_thunk(11, "float(__thiscall*)(void*, int)")
native_GetAvgChoke = vmt_thunk(12, "float(__thiscall*)(void*, int)")
native_GetTimeSinceLastReceived = vmt_thunk(22, "float(__thiscall*)(void*)")
local native_GetRemoteFramerate = vmt_thunk(25, "void(__thiscall*)(void*, float*, float*, float*)")
local native_GetTimeoutSeconds = vmt_thunk(26, "float(__thiscall*)(void*)")
local pflFrameTime = ffi.new("float[1]")
local pflFrameTimeStdDeviation = ffi.new("float[1]")
local pflFrameStartTimeStdDeviation = ffi.new("float[1]")
function GetRemoteFramerate(netchannelinfo)
native_GetRemoteFramerate(netchannelinfo, pflFrameTime, pflFrameTimeStdDeviation, pflFrameStartTimeStdDeviation)
if pflFrameTime ~= nil and pflFrameTimeStdDeviation ~= nil and pflFrameStartTimeStdDeviation ~= nil then
return pflFrameTime[0], pflFrameTimeStdDeviation[0], pflFrameStartTimeStdDeviation[0]
end
end
function GetAddress(netchannelinfo)
local addr = native_GetAddress(netchannelinfo)
if addr ~= nil then
return ffi.string(addr)
end
end
local function GetName(netchannelinfo)
local name = native_GetName(netchannelinfo)
if name ~= nil then
return ffi.string(name)
end
end
end
local cvar_game_mode, cvar_game_type, cvar_fps_max, cvar_fps_max_menu = cvar.game_mode, cvar.game_type, cvar.fps_max, cvar.fps_max_menu
local table_clear = require "table.clear"
-- initialize window
local window = ((function() local a={}local b,c,d,e,f=renderer.rectangle,renderer.gradient,renderer.texture,math.floor,math.ceil;local function g(h,i,j,k,l,m,n,o,p)p=p or 1;b(h,i,j,p,l,m,n,o)b(h,i+k-p,j,p,l,m,n,o)b(h,i+p,p,k-p*2,l,m,n,o)b(h+j-p,i+p,p,k-p*2,l,m,n,o)end;local function q(h,i,j,k,r,s,t,u,v,w,x,y,z,p)p=p or 1;if z then b(h,i,p,k,r,s,t,u)b(h+j-p,i,p,k,v,w,x,y)c(h+p,i,j-p*2,p,r,s,t,u,v,w,x,u,true)c(h+p,i+k-p,j-p*2,p,r,s,t,u,v,w,x,u,true)else b(h,i,j,p,r,s,t,u)b(h,i+k-p,j,p,v,w,x,y)c(h,i+p,p,k-p*2,r,s,t,u,v,w,x,y,false)c(h+j-p,i+p,p,k-p*2,r,s,t,u,v,w,x,y,false)end end;local A;do local B="\x14\x14\x14\xFF"local C="\x0c\x0c\x0c\xFF"A=renderer.load_rgba(table.concat({B,B,B,C,B,C,B,C,B,C,B,B,B,C,B,C}),4,4)end;local function D(E,F)if F~=nil and type(E)=="string"and E:sub(-1,-1)=="%"then E=math.floor(tonumber(E:sub(1,-2))/100*F)end;return E end;local function G(H)if H.position=="fixed"then local I,J=client.screen_size()if H.left~=nil then H.x=D(H.left,I)elseif H.right~=nil then H.x=I-(H.w or 0)-D(H.right,I)end;if H.top~=nil then H.y=D(H.top,J)elseif H.bottom~=nil then H.y=J-(H.h or 0)-D(H.bottom,J)end end;local h,i,j,k,o=H.x,H.y,H.w,H.h,H.a or 255;local K=1;if h==nil or i==nil or j==nil or o==nil then return end;H.i_x,H.i_y,H.i_w,H.i_h=H.x,H.y,H.w,H.h;if H.title_bar then K=(H.title~=nil and select(2,renderer.measure_text(H.title_text_size,H.title))or 13)+2;H.t_x,H.t_y,H.t_w,H.t_h=H.x,H.y,H.w,K end;if H.border then g(h,i,j,k,18,18,18,o)g(h+1,i+1,j-2,k-2,62,62,62,o)g(h+2,i+K+1,j-4,k-K-3,44,44,44,o,H.border_width)g(h+H.border_width+2,i+K+H.border_width+1,j-H.border_width*2-4,k-K-H.border_width*2-3,62,62,62,o)H.i_x=H.i_x+H.border_width+3;H.i_y=H.i_y+H.border_width+3;H.i_w=H.i_w-(H.border_width+3)*2;H.i_h=H.i_h-(H.border_width+3)*2;H.t_x,H.t_y,H.t_w=H.x+2,H.y+2,H.w-4;K=K-1 end;if K>1 then c(H.t_x,H.t_y,H.t_w,K,56,56,56,o,44,44,44,o,false)if H.title~=nil then local l,m,n,o=unpack(H.title_text_color)o=o*H.a/255;renderer.text(H.t_x+3,H.t_y+2,l or 255,m or 255,n or 255,o or 255,(H.title_text_size or"")..(H.title_text_flags or""),0,tostring(H.title))end;H.i_y=H.i_y+K;H.i_h=H.i_h-K end;if H.gradient_bar then local L=0;if H.background then L=1;local M,N=16,25;b(H.i_x+1,H.i_y,H.i_w-2,1,M,M,M,o)b(H.i_x+1,H.i_y+3,H.i_w-2,1,N,N,N,o)for O=0,1 do c(H.i_x+(H.i_w-1)*O,H.i_y,1,4,M,M,M,o,N,N,N,o,false)end end;do local h,i,P=H.i_x+L,H.i_y+L,1;local Q,R=e((H.i_w-L*2)/2),f((H.i_w-L*2)/2)for O=1,2 do c(h,i,Q,1,59*P,175*P,222*P,o,202*P,70*P,205*P,o,true)c(h+Q,i,R,1,202*P,70*P,205*P,o,201*P,227*P,58*P,o,true)i,P=i+1,P*0.5 end end;H.i_y=H.i_y+2+L*2;H.i_h=H.i_h-2-L*2 end;if H.background then d(A,H.i_x,H.i_y,H.i_w,H.i_h,255,255,255,255,"t")end;if H.draggable then local p=7;renderer.triangle(h+j-1,i+k-p,h+j-1,i+k-1,h+j-p,i+k-1,62,62,62,o)end;H.i_x=H.i_x+H.margin_left;H.i_w=H.i_w-H.margin_left-H.margin_right;H.i_y=H.i_y+H.margin_top;H.i_h=H.i_h-H.margin_top-H.margin_bottom end;local S={}local T={}local U={}local V={__index=U}function U:set_active(W)if W then S[self.id]=self;table.insert(T,1,self.id)else S[self.id]=nil end end;function U:set_z_index(X)self.z_index=X;self.z_index_reset=true end;function U:is_in_window(h,i)return h>=self.x and h<=self.x+self.w and i>=self.y and i<=self.y+self.h end;function U:set_inner_width(Y)if self.border then Y=Y+(self.border_width+3)*2 end;Y=Y+self.margin_left+self.margin_right;self.w=Y end;function U:set_inner_height(Z)local K=1;if self.title_bar then K=(self.title~=nil and select(2,renderer.measure_text(self.title_text_size,self.title))or 13)+2 end;if self.border then Z=Z+(self.border_width+3)*2;K=K-1 end;if K>1 then Z=Z+K end;if self.gradient_bar then local L=0;if self.background then L=1 end;Z=Z+2+L*2 end;Z=Z+self.margin_top+self.margin_bottom;self.h=Z end;function a.new(_,h,i,j,k,a0)local H=setmetatable({id=_,top=h,left=i,w=j,h=k,a=255,paint_callback=a0,title_bar=true,title_bar_in_menu=false,title_text_color={255,255,255,255},title_text_size=nil,gradient_bar=true,border=true,border_width=3,background=true,first=true,visible=true,margin_top=0,margin_bottom=0,margin_left=0,margin_right=0,position="fixed",draggable=false,draggable_save=false,in_menu=false},V)H:set_active(true)return H end;local a1,a2,a3;local function a4(a5)local a6={"bottom","unset","top"}local a7={}for O=#T,1,-1 do local H=S[T[O]]if H~=nil then local a8=H.z_index or"unset"if H.z_index_reset then H.z_index=nil;H.z_index_reset=nil end;a7[a8]=a7[a8]or{}if H.first then table.insert(a7[a8],1,H.id)H.first=nil else table.insert(a7[a8],H.id)end end end;T={}for O=1,#a6 do local a9=a7[a6[O]]if a9~=nil then for O=#a9,1,-1 do table.insert(T,a9[O])end end end;local aa=ui.is_menu_open()local ab={}for O=1,#T do local H=S[T[O]]if H~=nil and H.in_menu==a5 then if H.title_bar_in_menu then H.title_bar=aa end;if H.pre_paint_callback~=nil then H:pre_paint_callback()end;if S[H.id]~=nil then table.insert(ab,S[H.id])end end end;if aa then local ac,ad=ui.mouse_position()local ae=client.key_state(0x01)if ae then for O=#ab,1,-1 do local H=ab[O]if H.visible and H:is_in_window(a1,a2)then H.first=true;if a3 then local af,ag=ac-a1,ad-a2;if H.position=="fixed"then local ah=H.left==nil and"right"or"left"local ai=H.top==nil and"bottom"or"top"local aj={{ah,(ah=="right"and-1 or 1)*af},{ai,(ai=="bottom"and-1 or 1)*ag}}for O=1,#aj do local ak,al=unpack(aj[O])local am=type(H[ak])if am=="string"and H[ak]:sub(-1,-1)=="%"then elseif am=="number"then H[ak]=H[ak]+al end end else H.x=H.x+af;H.y=H.y+ag end end;break end end end;a1,a2=ac,ad;a3=ae end;for O=1,#ab do local H=ab[O]if H.visible and H.in_menu==a5 then G(H)if H.paint_callback~=nil then H:paint_callback()end end end end;local a1,a2,a3;client.delay_call(0,client.set_event_callback,"paint",function()a4(false)end)client.delay_call(0,client.set_event_callback,"paint_ui",function()a4(true)end)return a end)()).new("watermark")
window.title = "Watermark"
window.title_bar = false
window.margin_bottom = 2
window.margin_left = 3
window.margin_right = 3
window.border_width = 2
window.top = 15
window.right = 15
window.in_menu = true
-- custom name
local db = database.read("sapphyrus_watermark") or {}
--local pingspike_reference = ui_reference("MISC", "Miscellaneous", "Ping spike")
local antiut_reference = ui_reference("MISC", "Settings", "Anti-untrusted")
local is_beta = pcall(ui_reference, "MISC", "Settings", "Crash logs")
local names = {"Logo", "Custom text", "FPS", "Ping", "KDR", "Server info", "Server framerate", "Server IP", "Network lag", "Tickrate", "Velocity", "Time", "Time + seconds"}
local watermark_reference = ui_new_multiselect("VISUALS", "Effects", "Watermark ", names)
local color_reference = ui_new_color_picker("VISUALS", "Effects", "Watermark", 149, 184, 6, 255)
local custom_name_reference = ui_new_textbox("VISUALS", "Effects", "Watermark name")
local rainbow_header_reference = ui_new_checkbox("VISUALS", "Effects", "Watermark rainbow header")
local fps_prev = 0
local value_prev = {}
local last_update_time = 0
local offset_x, offset_y = -15, 15
--local offset_x, offset_y = 525, 915 --debug, show above net_graph
local function clamp(cur_val, min_val, max_val)
return math_min(math.max(cur_val, min_val), max_val)
end
local function lerp(a, b, percentage)
return a + (b - a) * percentage
end
local function table_contains(tbl, val)
for i=1, #tbl do
if tbl[i] == val then
return true
end
end
return false
end
local function table_remove_element(tbl, val)
local tbl_new = {}
for i=1, #tbl do
if tbl[i] ~= val then
table_insert(tbl_new, tbl[i])
end
end
return tbl_new
end
local function table_lerp(a, b, percentage)
local result = {}
for i=1, #a do
result[i] = lerp(a[i], b[i], percentage)
end
return result
end
local function on_watermark_changed()
local value = ui_get(watermark_reference)
if #value > 0 then
--Make Time / Time + seconds act as a kind of "switch", only allow one to be selected at a time.
if table_contains(value, "Time") and table_contains(value, "Time + seconds") then
local value_new = value
if not table_contains(value_prev, "Time") then
value_new = table_remove_element(value_new, "Time + seconds")
elseif not table_contains(value_prev, "Time + seconds") then
value_new = table_remove_element(value_new, "Time")
end
--this shouldn't happen, but why not add a failsafe
if table_contains(value_new, "Time") and table_contains(value_new, "Time + seconds") then
value_new = table_remove_element(value_new, "Time")
end
ui_set(watermark_reference, value_new)
on_watermark_changed()
return
end
end
ui_set_visible(custom_name_reference, table_contains(value, "Custom text"))
ui_set_visible(rainbow_header_reference, #value > 0)
value_prev = value
end
ui_set_callback(watermark_reference, on_watermark_changed)
on_watermark_changed()
local function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math_floor(num * mult + 0.5) / mult
end
local ft_prev = 0
local function get_fps()
ft_prev = ft_prev * 0.9 + globals_absoluteframetime() * 0.1
return round(1 / ft_prev)
end
local function lerp_color_yellow_red(val, max_normal, max_yellow, max_red, default, yellow, red)
default = default or {255, 255, 255}
yellow = yellow or {230, 210, 40}
red = red or {255, 32, 32}
if val > max_yellow then
return unpack(table_lerp(yellow, red, clamp((val-max_yellow)/(max_red-max_yellow), 0, 1)))
else
return unpack(table_lerp(default, yellow, clamp((val-max_normal)/(max_yellow-max_normal), 0, 1)))
end
end
local watermark_items = {
{
--gamesense logo
name = "Logo",
get_width = function(self, frame_data)
self.game_width = renderer_measure_text(nil, "game")
self.sense_width = renderer_measure_text(nil, "sense")
self.beta_width = (is_beta and (renderer_measure_text(nil, " [beta]")) or 0)
return self.game_width + self.sense_width + self.beta_width
end,
draw = function(self, x, y, w, h, r, g, b, a)
local r_sense, g_sense, b_sense = ui_get(color_reference)
renderer_text(x, y, 255, 255, 255, a, nil, 0, "game")
renderer_text(x+self.game_width, y, r_sense, g_sense, b_sense, a, nil, 0, "sense")
if is_beta then
renderer_text(x+self.game_width+self.sense_width, y, 255, 255, 255, a*0.9, nil, 0, " [beta]")
end
end
},
{
name = "Custom text",
get_width = function(self, frame_data)
local edit = ui_get(custom_name_reference)
if edit ~= self.edit_prev and self.edit_prev ~= nil then
db.custom_name = edit
elseif edit == "" and db.custom_name ~= nil then
ui_set(custom_name_reference, db.custom_name)
end
self.edit_prev = edit
local text = db.custom_name
if text ~= nil and text:gsub(" ", "") ~= "" then
self.text = text
return renderer_measure_text(nil, text)
else
self.text = nil
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
-- local r_sense, g_sense, b_sense = ui_get(color_reference)
renderer_text(x, y, r, g, b, a, nil, 0, self.text)
end
},
{
name = "FPS",
get_width = function(self, frame_data)
self.fps = get_fps()
self.text = tostring(self.fps or 0) .. " fps"
local fps_max, fps_max_menu = cvar_fps_max:get_float(), cvar_fps_max_menu:get_float()
local fps_max = globals.mapname() == nil and math.min(fps_max == 0 and 999 or fps_max, fps_max_menu == 0 and 999 or fps_max) or fps_max == 0 and 999 or fps_max
self.width = math.max(renderer_measure_text(nil, self.text), renderer_measure_text(nil, fps_max .. " fps"))
return self.width
end,
draw = function(self, x, y, w, h, r, g, b, a)
--fps
local fps_r, fps_g, fps_b = r, g, b
if self.fps < (1 / globals_tickinterval()) then
-- fps_r, fps_g, fps_b = 255, 0, 0
end
renderer_text(x+self.width, y, fps_r, fps_g, fps_b, a, "r", 0, self.text)
end
},
{
name = "Ping",
get_width = function(self, frame_data)
local ping = client_latency()
if ping > 0 then
self.ping = ping
self.text = round(self.ping*1000, 0) .. "ms"
self.width = math.max(renderer_measure_text(nil, "999ms"), renderer_measure_text(nil, self.text))
return self.width
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
if self.ping > 0.15 then
r, g, b = 255, 0, 0
end
renderer_text(x+self.width, y, r, g, b, a, "r", 0, self.text)
end
},
{
name = "KDR",
get_width = function(self, frame_data)
frame_data.local_player = frame_data.local_player or entity.get_local_player()
if frame_data.local_player == nil then return end
local player_resource = entity_get_player_resource()
if player_resource == nil then return end
self.kills = entity_get_prop(player_resource, "m_iKills", frame_data.local_player)
self.deaths = math.max(entity_get_prop(player_resource, "m_iDeaths", frame_data.local_player), 1)
self.kdr = self.kills/self.deaths
if self.kdr ~= 0 then
self.text = string.format("%1.1f", round(self.kdr, 1))
self.text_width = math.max(renderer_measure_text(nil, "10.0"), renderer_measure_text(nil, self.text))
self.unit_width = renderer_measure_text("-", "kdr")
return self.text_width+self.unit_width
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
renderer_text(x+self.text_width, y, r, g, b, a, "r", 0, self.text)
renderer_text(x+self.text_width+self.unit_width, y+2, 255, 255, 255, a*0.75, "r-", 0, "kdr")
end
},
{
name = "Velocity",
get_width = function(self, frame_data)
frame_data.local_player = frame_data.local_player or entity.get_local_player()
if frame_data.local_player == nil then return end
local vel_x, vel_y = entity_get_prop(frame_data.local_player, "m_vecVelocity")
if vel_x ~= nil then
self.velocity = math_sqrt(vel_x*vel_x + vel_y*vel_y)
self.vel_width = renderer_measure_text(nil, "9999")
self.unit_width = renderer_measure_text("-", "vel")
return self.vel_width+self.unit_width
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
local velocity = self.velocity
-- velocity = string.rep(round(globals.realtime() % 9, 0), 4)
velocity = math_min(9999, velocity) + 0.4
velocity = round(velocity, 0)
renderer_text(x+self.vel_width, y, 255, 255, 255, a, "r", 0, velocity)
renderer_text(x+self.vel_width+self.unit_width, y+3, 255, 255, 255, a*0.75, "r-", 0, "vel")
end
},
{
name = "Server framerate",
get_width = function(self, frame_data)
if not allow_unsafe_scripts then return end
frame_data.local_player = frame_data.local_player or entity.get_local_player()
if frame_data.local_player == nil then return end
frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
if frame_data.net_channel_info == nil then return end
local frame_time, frame_time_std_dev, frame_time_start_time_std_dev = GetRemoteFramerate(frame_data.net_channel_info)
if frame_time ~= nil then
self.framerate = frame_time * 1000
self.var = frame_time_std_dev * 1000
self.text1 = "sv:"
self.text2 = string.format("%.1f", self.framerate)
self.text3 = " +-"
self.text4 = string.format("%.1f", self.var)
self.width1 = renderer_measure_text(nil, self.text1)
self.width2 = math.max(renderer_measure_text(nil, self.text2), renderer_measure_text(nil, "99.9"))
self.width3 = renderer_measure_text(nil, self.text3)
self.width4 = math.max(renderer_measure_text(nil, self.text4), renderer_measure_text(nil, "9.9"))
return self.width1 + self.width2 + self.width3 + self.width4
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
local fr_r, fr_g, fr_b = lerp_color_yellow_red(self.framerate, 8, 14, 20, {r, g, b})
local vr_r, vr_g, vr_b = lerp_color_yellow_red(self.var, 5, 10, 18, {r, g, b})
renderer_text(x, y, r, g, b, a, nil, 0, self.text1)
renderer_text(x+self.width1+self.width2, y, fr_r, fr_g, fr_b, a, "r", 0, self.text2)
renderer_text(x+self.width1+self.width2, y, r, g, b, a, nil, 0, self.text3)
renderer_text(x+self.width1+self.width2+self.width3, y, vr_r, vr_g, vr_b, a, nil, 0, self.text4)
end
},
{
name = "Network lag",
get_width = function(self, frame_data)
if not allow_unsafe_scripts then return end
frame_data.local_player = frame_data.local_player or entity.get_local_player()
if frame_data.local_player == nil then return end
frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
if frame_data.net_channel_info == nil then return end
local reasons = {}
-- timeout
local time_since_last_received = native_GetTimeSinceLastReceived(frame_data.net_channel_info)
if time_since_last_received ~= nil and time_since_last_received > 0.1 then
table_insert(reasons, string_format("%.1fs timeout", time_since_last_received))
end
-- loss
local avg_loss = native_GetAvgLoss(frame_data.net_channel_info, FLOW_INCOMING)
if avg_loss ~= nil and avg_loss > 0 then
table_insert(reasons, string_format("%d%% loss", math.ceil(avg_loss*100)))
end
-- choke
local avg_choke = native_GetAvgChoke(frame_data.net_channel_info, FLOW_INCOMING)
if avg_choke > 0 then
table_insert(reasons, string_format("%d%% choke", math.ceil(avg_choke*100)))
end
if #reasons > 0 then
self.text = table.concat(reasons, ", ")
return renderer_measure_text(nil, self.text)
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
renderer_text(x, y, 255, 32, 32, a, nil, 0, self.text)
end
},
{
name = "Server info",
get_width = function(self, frame_data)
if not allow_unsafe_scripts then return end
frame_data.local_player = frame_data.local_player or entity.get_local_player()
if frame_data.local_player == nil then return end
frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
if frame_data.net_channel_info == nil then return end
frame_data.is_loopback = frame_data.is_loopback == nil and native_IsLoopback(frame_data.net_channel_info) or frame_data.is_loopback
local game_rules = entity.get_game_rules()
frame_data.is_valve_ds = frame_data.is_valve_ds == nil and entity.get_prop(game_rules, "m_bIsValveDS") == 1 or frame_data.is_valve_ds
local text
if frame_data.is_loopback then
text = "Local server"
elseif frame_data.is_valve_ds then
local game_mode_name
local game_mode, game_type = cvar_game_mode:get_int(), cvar_game_type:get_int()
local is_queued_matchmaking = entity.get_prop(game_rules, "m_bIsQueuedMatchmaking") == 1
if is_queued_matchmaking then
if game_type == 0 and game_mode == 1 then
game_mode_name = "MM"
elseif game_type == 0 and game_mode == 2 then
game_mode_name = "Wingman"
elseif game_type == 3 then
game_mode_name = "Custom"
elseif game_type == 4 and game_mode == 0 then
game_mode_name = "Guardian"
elseif game_type == 4 and game_mode == 1 then
game_mode_name = "Co-op Strike"
elseif game_type == 6 and game_mode == 0 then
game_mode_name = "Danger Zone"
end
else
if game_type == 0 and game_mode == 0 then
game_mode_name = "Casual"
elseif game_type == 1 and game_mode == 0 then
game_mode_name = "Arms Race"
elseif game_type == 1 and game_mode == 1 then
game_mode_name = "Demolition"
elseif game_type == 1 and game_mode == 2 then
game_mode_name = "Deathmatch"
end
end
if game_mode_name ~= nil then
text = "Valve (" .. game_mode_name .. ")"
else
text = "Valve"
end
end
if text ~= nil then
self.text = text
return renderer_measure_text(nil, text)
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
renderer_text(x, y, 255, 255, 255, a, nil, 0, self.text)
end
},
{
name = "Server IP",
get_width = function(self, frame_data)
if not allow_unsafe_scripts then return end
frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
if frame_data.net_channel_info == nil then return end
frame_data.is_loopback = frame_data.is_loopback == nil and native_IsLoopback(frame_data.net_channel_info) or frame_data.is_loopback
if frame_data.is_loopback then return end
frame_data.is_valve_ds = frame_data.is_valve_ds == nil and entity.get_prop(entity.get_game_rules(), "m_bIsValveDS") == 1 or frame_data.is_valve_ds
if frame_data.is_valve_ds then return end
frame_data.server_address = frame_data.server_address or GetAddress(frame_data.net_channel_info)
if frame_data.server_address ~= nil and frame_data.server_address ~= "" then
self.text = frame_data.server_address
return renderer_measure_text(nil, self.text)
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
renderer_text(x, y, 255, 255, 255, a, nil, 0, self.text)
end
},
{
name = "Tickrate",
get_width = function(self, frame_data)
if globals.mapname() == nil then return end
local tickinterval = globals_tickinterval()
if tickinterval ~= nil then
local text = 1/globals_tickinterval() .. " tick"
self.text = text
return renderer_measure_text(nil, text)
end
end,
draw = function(self, x, y, w, h, r, g, b, a)
renderer_text(x, y, 255, 255, 255, a, nil, 0, self.text)
end
},
{
name = "Time",
get_width = function(self, frame_data)
self.time_width = renderer_measure_text(nil, "00")
self.sep_width = renderer_measure_text(nil, ":")
return self.time_width + self.sep_width + self.time_width + (self.seconds and (self.sep_width + self.time_width) or 0)
end,
draw = function(self, x, y, w, h, r, g, b, a)
-- local time_center = x + 16
local hours, minutes, seconds, milliseconds = client_system_time()
hours, minutes = string_format("%02d", hours), string_format("%02d", minutes)
-- renderer_text(time_center, y, 255, 255, 255, a, "r", 0, hours)
-- renderer_text(time_center, y, 255, 255, 255, a, "", 0, ":")
-- renderer_text(time_center+4, y, 255, 255, 255, a, "", 0, minutes)
-- time_center = time_center + 18
-- if self.seconds then
-- seconds = string_format("%02d", seconds)
-- renderer_text(time_center, y, 255, 255, 255, a, "", 0, ":")
-- renderer_text(time_center+4, y, 255, 255, 255, a, "", 0, seconds)
-- end
renderer_text(x, y, 255, 255, 255, a, "", 0, hours)
renderer_text(x+self.time_width, y, 255, 255, 255, a, "", 0, ":")
renderer_text(x+self.time_width+self.sep_width, y, 255, 255, 255, a, "", 0, minutes)
if self.seconds then
seconds = string_format("%02d", seconds)
renderer_text(x+self.time_width*2+self.sep_width, y, 255, 255, 255, a, "", 0, ":")
renderer_text(x+self.time_width*2+self.sep_width*2, y, 255, 255, 255, a, "", 0, seconds)
end
end,
seconds = false
},
}
local items_drawn = {}
window.pre_paint_callback = function()
table_clear(items_drawn)
local value = ui_get(watermark_reference)
if table_contains(value, "Custom text") then
value = table_remove_element(value, "Custom text")
if table_contains(value, "Logo") then
table_insert(value, 2, "Custom text")
else
table_insert(value, 1, "Custom text")
end
end
local screen_width, screen_height = client_screen_size()
local x = offset_x >= 0 and offset_x or screen_width + offset_x
local y = offset_y >= 0 and offset_y or screen_height + offset_y
for i=1, #watermark_items do
local item = watermark_items[i]
if item.name == "Time" then
item.seconds = table_contains(value, "Time + seconds")
if item.seconds then
table_insert(value, "Time")
end
end
end
--calculate width and draw container
local item_margin = 9
local width = 0
local frame_data = {}
for i=1, #watermark_items do
local item = watermark_items[i]
if table_contains(value, item.name) then
local item_width = item:get_width(frame_data)
if item_width ~= nil and item_width > 0 then
table.insert(items_drawn, {
item = item,
item_width = item_width,
x = width
})
width = width + item_width + item_margin
end
end
end
local _, height = renderer_measure_text(nil, "A")
window.gradient_bar = ui_get(rainbow_header_reference)
window:set_inner_width(width-item_margin)
window:set_inner_height(height)
window.visible = #items_drawn > 0
end
window.paint_callback = function()
local r, g, b = 255, 255, 255
local a_text = 230
for i=1, #items_drawn do
local item = items_drawn[i]
-- bounding box
-- renderer_rectangle(x_text+item.x, y_text, item.item_width, 14, 255, 0, 0, 100)
-- draw item
item.item:draw(window.i_x+item.x, window.i_y, item.item_width, 30, r, g, b, a_text)
-- draw seperator
if #items_drawn > i then
renderer.rectangle(window.i_x+item.x+item.item_width+4, window.i_y+1, 1, window.i_h-1, 210, 210, 210, 255)
end
end
end
client.set_event_callback("shutdown", function()
database.write("sapphyrus_watermark", db)
end)