]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/tools/demotc.pl
demotc: support client->server packets
[divverent/nexuiz.git] / misc / tools / demotc.pl
1 #!/usr/bin/perl
2
3 # Fake demo "cutting" tool
4 # works by looking for time codes in the demo
5 # and injecting playback speed commands
6
7 use strict;
8 use warnings;
9
10 sub sanitize($)
11 {
12         my ($str) = @_;
13         $str =~ y/\000-\037//d;
14         return $str;
15 }
16
17 # opening the files
18
19 my ($in, $out, $tc0, $tc1, $pattern, $capture);
20
21 my $mode = shift @ARGV;
22 $mode = 'help' if not defined $mode;
23
24 if($mode eq 'grep' && @ARGV == 2)
25 {
26         $in = $ARGV[0];
27         $pattern = $ARGV[1];
28 }
29 elsif($mode eq 'uncut' && @ARGV == 2)
30 {
31         $in = $ARGV[0];
32         $out = $ARGV[1];
33 }
34 elsif($mode eq 'cut' && (@ARGV == 4 || @ARGV == 5))
35 {
36         $in = $ARGV[0];
37         $out = $ARGV[1];
38         $tc0 = $ARGV[2];
39         $tc1 = $ARGV[3];
40         $capture = (@ARGV == 5);
41 }
42 else
43 {
44         die "Usage: $0 cut infile outfile tc_start tc_end [--capture], or $0 uncut infile outfile, or $0 grep infile pattern\n"
45 }
46
47 if($mode ne 'grep')
48 {
49         $in ne $out
50                 or die "Input and output file may not be the same!";
51 }
52
53 open my $infh, "<", $in
54         or die "open $in: $!";
55 binmode $infh;
56
57 my $outfh;
58 if($mode ne 'grep') # cutting
59 {
60         open $outfh, ">", $out
61                 or die "open $out: $!";
62         binmode $outfh;
63 }
64
65 # 1. CD track
66
67 $/ = "\012";
68 my $cdtrack = <$infh>;
69 print $outfh $cdtrack if $mode ne 'grep';
70
71 # 2. packets
72
73 my $tc = undef;
74
75 my $first = 1;
76 my $demo_started = 0;
77 my $demo_stopped = 0;
78 my $inject_buffer = "";
79
80 use constant DEMOMSG_CLIENT_TO_SERVER => 0x80000000;
81 for(;;)
82 {
83         last
84                 unless 4 == read $infh, my $length, 4;
85         $length = unpack("V", $length);
86         if($length & DEMOMSG_CLIENT_TO_SERVER)
87         {
88                 # client-to-server packet
89                 $length = $length & ~DEMOMSG_CLIENT_TO_SERVER;
90                 die "Invalid demo packet"
91                         unless 12 == read $infh, my $angles, 12;
92                 die "Invalid demo packet"
93                         unless $length == read $infh, my($data), $length;
94
95                 next if $mode eq 'grep';
96                 print $outfh pack("V", length($data) | DEMOMSG_CLIENT_TO_SERVER);
97                 print $outfh $angles;
98                 print $outfh $data;
99         }
100         die "Invalid demo packet"
101                 unless 12 == read $infh, my $angles, 12;
102         die "Invalid demo packet"
103                 unless $length == read $infh, my($data), $length;
104         
105         # remove existing cut marks
106         $data =~ s{^\011\n//CUTMARK\n[^\0]*\0}{};
107         
108         if(substr($data, 0, 1) eq "\007") # svc_time
109         {
110                 $tc = unpack "f", substr $data, 1, 4;
111         }
112
113         if($mode eq 'cut' && defined $tc)
114         {
115                 if($first)
116                 {
117                         $inject_buffer = "\011\n//CUTMARK\nslowmo 100\n\000";
118                         $first = 0;
119                 }
120                 if($demo_started < 1 && $tc > $tc0 - 50)
121                 {
122                         $inject_buffer = "\011\n//CUTMARK\nslowmo 10\n\000";
123                         $demo_started = 1;
124                 }
125                 if($demo_started < 2 && $tc > $tc0 - 5)
126                 {
127                         $inject_buffer = "\011\n//CUTMARK\nslowmo 1\n\000";
128                         $demo_started = 2;
129                 }
130                 if($demo_started < 3 && $tc > $tc0)
131                 {
132                         if($capture)
133                         {
134                                 $inject_buffer = "\011\n//CUTMARK\ncl_capturevideo 1\n\000";
135                         }
136                         else
137                         {
138                                 $inject_buffer = "\011\n//CUTMARK\nslowmo 0; defer 1 \"slowmo 1\"\n\000";
139                         }
140                         $demo_started = 3;
141                 }
142                 if(!$demo_stopped && $tc > $tc1)
143                 {
144                         if($capture)
145                         {
146                                 $inject_buffer = "\011\n//CUTMARK\ncl_capturevideo 0; defer 0.5 \"disconnect\"\n\000";
147                         }
148                         else
149                         {
150                                 $inject_buffer = "\011\n//CUTMARK\ndefer 0.5 \"disconnect\"\n\000";
151                         }
152                         $demo_stopped = 1;
153                 }
154         }
155         elsif($mode eq 'grep')
156         {
157                 if(my @l = ($data =~ /$pattern/))
158                 {
159                         if(defined $tc)
160                         {
161                                 print "$tc:";
162                         }
163                         else
164                         {
165                                 print "start:";
166                         }
167                         for(@l)
168                         {
169                                 print " \"", sanitize($_), "\"";
170                         }
171                         print "\n";
172                 }
173         }
174         
175         next if $mode eq 'grep';
176         if(length($inject_buffer . $data) < 65536)
177         {
178                 $data = $inject_buffer . $data;
179                 $inject_buffer = "";
180         }
181         print $outfh pack("V", length $data);
182         print $outfh $angles;
183         print $outfh $data;
184 }
185
186 close $outfh if $mode ne 'grep';
187 close $infh;