ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/bin/pclient
Revision: 1.1
Committed: Thu Apr 6 15:30:09 2006 UTC (18 years, 1 month ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #!/opt/bin/perl
2    
3     use SDL;
4     use SDL::App;
5     use SDL::Event;
6     use SDL::Surface;
7    
8     my $conn;
9     my $map_surface;
10    
11     my $app = new SDL::App
12     -flags => SDL_HWSURFACE | SDL_ANYFORMAT | SDL_HWACCEL | SDL_ASYNCBLIT,
13     -title => "Crossfire+ Client",
14     -width => 640,
15     -height => 480,
16     -depth => 24,
17     -double_buffer => 1,
18     -resizeable => 1;
19    
20     sub redraw {
21     $map_surface or return;
22    
23     $map_surface->blit (0, $app, 0);
24     $app->sync;
25     }
26    
27     my $ev = new SDL::Event;
28     my %ev_cb;
29    
30     sub event(&$) {
31     $ev_cb{$_[0]->()} = $_[1];
32     }
33    
34     sub does(&) { shift }
35    
36     event {SDL_QUIT} does {
37     exit;
38     };
39    
40     event {SDL_VIDEORESIZE} does {
41     print "resize\n";
42     };
43    
44     event {SDL_KEYDOWN} does {
45     print "keypress\n";
46     };
47    
48     event {SDL_KEYUP} does {
49     print "keyup\n";#d#
50     };
51    
52     event {SDL_MOUSEMOTION} does {
53     print "motion\n";
54     };
55    
56     event {SDL_MOUSEBUTTONDOWN} does {
57     print "button\n";
58     };
59    
60     event {SDL_MOUSEBUTTONUP} does {
61     print "buttup\n";
62     };
63    
64     event {SDL_ACTIVEEVENT} does {
65     print "active\n";
66     };
67    
68     package Crossfire::Protocol;
69    
70     use AnyEvent;
71     use IO::Socket::INET;
72    
73     sub new {
74     my $class = shift;
75     my $self = bless { @_ }, $class;
76    
77     $self->{fh} = new IO::Socket::INET PeerHost => $self->{host}, PeerPort => $self->{port}
78     or die "$self->{host}:$self->{port}: $!";
79     $self->{fh}->blocking (0); # stupid nonblock default
80    
81     my $buf;
82    
83     $self->{w} = AnyEvent->io (fh => $self->{fh}, poll => 'r', cb => sub {
84     if (sysread $self->{fh}, $buf, 16384, length $buf) {
85     if (2 <= length $buf) {
86     my $len = unpack "n", $buf;
87     if ($len + 2 <= length $buf) {
88     substr $buf, 0, 2, "";
89     $self->feed (substr $buf, 0, $len, "");
90     }
91     }
92     } else {
93     delete $self->{w};
94     close $self->{fh};
95     }
96     });
97    
98     $self->send ("version 1023 1027 perlclient");
99     $self->send ("setup sound 1 exp 1 map1acmd 1 itemcmd 2 darkness 1 mapsize 63x63 newmapcmd 1 facecache 1 extendedMapInfos 1 extendedTextInfos 1");
100     $self->send ("addme");
101    
102     $self
103     }
104    
105     sub feed {
106     my ($self, $data) = @_;
107    
108     $data =~ s/^(\S+)\s//
109     or return;
110    
111     my $command = "feed_$1";
112    
113     $self->$command ($data);
114     }
115    
116     sub feed_version {
117     my ($self, $version) = @_;
118     }
119    
120     sub feed_setup {
121     my ($self, $data) = @_;
122    
123     $data =~ s/^ +//;
124    
125     $self->{setup} = { split / +/, $data };
126    
127     ($self->{mapw}, $self->{maph}) = split /x/, $self->{setup}{mapsize};
128    
129     $self->feed_newmap;
130     }
131    
132     sub feed_query {
133     my ($self, $data) = @_;
134     warn "Q<$data>\n";
135     }
136    
137     sub feed_stats {
138     my ($self, $data) = @_;
139     # warn "S<$data>\n";
140     }
141    
142     sub feed_face1 {
143     my ($self, $data) = @_;
144    
145     my ($num, $chksum, $name) = unpack "nNa*", $data;
146    
147     $self->{face}[$num] = { name => $name, chksum => $chksum };
148     }
149    
150     sub feed_drawinfo {
151     my ($self, $data) = @_;
152     # warn "<$data>\n";
153     }
154    
155     sub feed_delinv {
156     my ($self, $data) = @_;
157     }
158    
159     sub feed_item2 {
160     my ($self, $data) = @_;
161     }
162    
163     sub feed_map1a {
164     my ($self, $data) = @_;
165    
166     my $map = $self->{map} ||= [];
167    
168     my @dirty;
169     my ($coord, $x, $y, $darkness, $fa, $fb, $fc, $cell);
170    
171     while (length $data) {
172     $coord = unpack "n", substr $data, 0, 2, "";
173    
174     $x = ($coord >> 10) & 63;
175     $y = ($coord >> 4) & 63;
176    
177     $cell = $map->[$x][$y] ||= [];
178    
179     $cell->[3] = unpack "C", substr $data, 0, 1, ""
180     if $coord & 8;
181     $cell->[0] = unpack "n", substr $data, 0, 2, ""
182     if $coord & 4;
183     $cell->[1] = unpack "n", substr $data, 0, 2, ""
184     if $coord & 2;
185     $cell->[2] = unpack "n", substr $data, 0, 2, ""
186     if $coord & 1;
187    
188     @$cell = ()
189     unless $coord & 15;
190    
191     push @dirty, [$x, $y];
192     }
193    
194     $self->map_update (\@dirty);
195     }
196    
197     sub feed_map_scroll {
198     my ($self, $data) = @_;
199    
200     my ($dx, $dy) = split / /, $data;
201    
202     my $map = $self->{map} ||= [];
203    
204     $self->{mapx} += $dx;
205     $self->{mapy} += $dy;
206    
207     if ($dx > 0) {
208     unshift @$_, ([]) x $dx for @$map;
209     } elsif ($dx < 0) {
210     splice @$_, 0, -$dx, () for @$map;
211     }
212    
213     if ($dy > 0) {
214     unshift @$map, ([]) x $dy;
215     } elsif ($dy < 0) {
216     splice @$map, 0, -$dy, ();
217     }
218    
219     $self->map_scroll ($dx, $dy);
220     }
221    
222     sub feed_newmap {
223     my ($self) = @_;
224    
225     $self->{map} = [];
226     $self->{mapx} = 0;
227     $self->{mapy} = 0;
228    
229     $self->map_clear;
230     }
231    
232     sub feed_image {
233     my ($self, $data) = @_;
234    
235     my ($face, $len, $data) = unpack "NNa*", $data;
236    
237     $self->{face}[$face]{image} = $data;
238    
239     $self->face_update ($face, $self->{face}[$face]);
240     }
241    
242     sub map_clear { }
243     sub map_update { }
244     sub map_scroll { }
245    
246     sub face_update { }
247    
248     sub send {
249     my ($self, $data) = @_;
250    
251     $data = pack "na*", length $data, $data;
252    
253     syswrite $self->{fh}, $data;
254     }
255    
256     package conn;
257    
258     @ISA = Crossfire::Protocol::;
259    
260     sub map_update {
261     my ($self, $dirty) = @_;
262    
263     for (@$dirty) {
264     my ($x, $y) = @$_;
265    
266     my $px = $x * 32;
267     my $py = $y * 32;
268    
269     my $dst = new SDL::Rect -x => $px, -y => $py, -width => 32, -height => 32;
270    
271     my $cell = $self->{map}[$x][$y];
272    
273     if ($cell) {
274     $cell->[0] or $map_surface->fill ($dst, new SDL::Color -r => 0, -g => 0, -b => 0); # is_floor is opaque, I hope
275    
276     for my $num (grep $_, $cell->[0], $cell->[1], $cell->[2]) {
277     my $surface = $self->{face}[$num]{surface} ||= do {
278     $self->send ("askface $num");
279    
280     # TODO: fog of "war"
281     my $surface = new SDL::Surface
282     -flags => SDL::SDL_HWSURFACE | SDL::SDL_ANYFORMAT | SDL::SDL_HWACCEL | SDL::SDL_ASYNCBLIT,
283     -width => 32,
284     -height => 32,
285     -depth => 32;
286    
287     $surface->fill (0, new SDL::Color -r => 128, -g => 128, -b => 128);
288    
289     $surface
290     };
291    
292     $surface->blit (0, $map_surface, $dst);
293     }
294     } else {
295     $map_surface->fill ($dst, new SDL::Color -r => 0, -g => 0, -b => 0);
296     }
297     }
298    
299     ::redraw;
300     }
301    
302     sub map_scroll {
303     my ($self, $dx, $dy) = @_;
304    
305     ::redraw;
306     }
307    
308     sub map_clear {
309     my ($self) = @_;
310    
311     $map_surface = new SDL::Surface
312     -flags => SDL::HWSURFACE,
313     -width => $self->{mapw} * 32,
314     -height => $self->{maph} * 32,
315     -depth => 32;
316    
317     SDL::SetClipRect $$map_surface, 0;
318     $map_surface->fill (0, new SDL::Color -r => 0, -g => 0, -b => 0);
319    
320     ::redraw;
321     }
322    
323     sub face_update {
324     my ($self, $num, $face) = @_;
325    
326     warn "up face $self,$num,$face\n";#d#
327     #TODO
328     open my $fh, ">:raw", "/tmp/x~";
329     syswrite $fh, $face->{image};
330     close $fh;
331    
332     $face->{surface} = (new SDL::Surface -name => "/tmp/x~")->display_format;
333    
334     unlink "/tmp/x~";
335    
336     my @dirty;
337    
338     for my $x (0..$self->{mapw} - 1) {
339     for my $y (0..$self->{maph} - 1) {
340     push @dirty, [$x, $y]
341     if grep $_ == $num, @{$self->{map}[$x][$y] || []};
342     }
343     }
344     $self->map_update (\@dirty);
345     }
346    
347     package main;
348    
349     #############################################################################
350    
351     use Event;
352    
353     $conn = new conn
354     host => "cf.schmorp.de",
355     port => 13327;
356    
357     Event->timer (after => 0, interval => 1/20, hard => 1, cb => sub {
358     while ($ev->poll) {
359     ($ev_cb{$ev->type} || sub { warn "unhandled event ", $ev->type })->();
360     }
361     });
362    
363     Event::loop;
364    
365