ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC.pm
(Generate patch)

Comparing deliantra/Deliantra-Client/DC.pm (file contents):
Revision 1.114 by elmex, Mon Aug 14 04:34:40 2006 UTC vs.
Revision 1.134 by root, Thu Dec 7 03:54:47 2006 UTC

12 12
13=cut 13=cut
14 14
15package CFPlus; 15package CFPlus;
16 16
17use Carp ();
18
17BEGIN { 19BEGIN {
18 $VERSION = '0.2'; 20 $VERSION = '0.97';
19 21
20 use XSLoader; 22 use XSLoader;
21 XSLoader::load "CFPlus", $VERSION; 23 XSLoader::load "CFPlus", $VERSION;
22} 24}
23 25
24use utf8; 26use utf8;
25 27
26use Carp ();
27use AnyEvent (); 28use AnyEvent ();
28use BerkeleyDB; 29use BerkeleyDB;
29use Pod::POM (); 30use Pod::POM ();
30use Scalar::Util (); 31use Scalar::Util ();
31use Storable (); # finally 32use Storable (); # finally
32 33
34BEGIN {
35 use Crossfire::Protocol::Base ();
36 *to_json = \&Crossfire::Protocol::Base::to_json;
37 *from_json = \&Crossfire::Protocol::Base::from_json;
38}
39
33=item guard { BLOCK } 40=item guard { BLOCK }
34 41
35Returns an object that executes the given block as soon as it is destroyed. 42Returns an object that executes the given block as soon as it is destroyed.
36 43
37=cut 44=cut
40 bless \(my $cb = $_[0]), "CFPlus::Guard" 47 bless \(my $cb = $_[0]), "CFPlus::Guard"
41} 48}
42 49
43sub CFPlus::Guard::DESTROY { 50sub CFPlus::Guard::DESTROY {
44 ${$_[0]}->() 51 ${$_[0]}->()
52}
53
54=item shorten $string[, $maxlength]
55
56=cut
57
58sub shorten($;$) {
59 my ($str, $len) = @_;
60 substr $str, $len, (length $str), "..." if $len + 3 <= length $str;
61 $str
45} 62}
46 63
47sub asxml($) { 64sub asxml($) {
48 local $_ = $_[0]; 65 local $_ = $_[0];
49 66
52 s/</&lt;/g; 69 s/</&lt;/g;
53 70
54 $_ 71 $_
55} 72}
56 73
74sub socketpipe() {
75 socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
76 or die "cannot establish bidiretcional pipe: $!\n";
77
78 ($fh1, $fh2)
79}
80
81sub background(&;&) {
82 my ($bg, $cb) = @_;
83
84 my ($fh_r, $fh_w) = CFPlus::socketpipe;
85
86 my $pid = fork;
87
88 if (defined $pid && !$pid) {
89 local $SIG{__DIE__};
90
91 open STDOUT, ">&", $fh_w;
92 open STDERR, ">&", $fh_w;
93 close $fh_r;
94 close $fh_w;
95
96 $| = 1;
97
98 eval { $bg->() };
99
100 if ($@) {
101 my $msg = $@;
102 $msg =~ s/\n+/\n/;
103 warn "FATAL: $msg";
104 CFPlus::_exit 1;
105 }
106
107 # win32 is fucked up, of course. exit will clean stuff up,
108 # which destroys our database etc. _exit will exit ALL
109 # forked processes, because of the dreaded fork emulation.
110 CFPlus::_exit 0;
111 }
112
113 close $fh_w;
114
115 my $buffer;
116
117 my $w; $w = AnyEvent->io (fh => $fh_r, poll => 'r', cb => sub {
118 unless (sysread $fh_r, $buffer, 4096, length $buffer) {
119 undef $w;
120 $cb->();
121 return;
122 }
123
124 while ($buffer =~ s/^(.*)\n//) {
125 my $line = $1;
126 $line =~ s/\s+$//;
127 utf8::decode $line;
128 if ($line =~ /^\x{e877}json_msg (.*)$/s) {
129 $cb->(from_json $1);
130 } else {
131 ::message ({
132 markup => "background($pid): " . CFPlus::asxml $line,
133 });
134 }
135 }
136 });
137}
138
139sub background_msg {
140 my ($msg) = @_;
141
142 $msg = "\x{e877}json_msg " . to_json $msg;
143 $msg =~ s/\n//g;
144 utf8::encode $msg;
145 print $msg, "\n";
146}
147
57package CFPlus::Database; 148package CFPlus::Database;
58 149
59our @ISA = BerkeleyDB::Btree::; 150our @ISA = BerkeleyDB::Btree::;
60 151
61sub get($$) { 152sub get($$) {
69my %DB_SYNC; 160my %DB_SYNC;
70 161
71sub put($$$) { 162sub put($$$) {
72 my ($db, $key, $data) = @_; 163 my ($db, $key, $data) = @_;
73 164
165 my $hkey = $db + 0;
166 Scalar::Util::weaken $db;
74 $DB_SYNC{$db} = AnyEvent->timer (after => 5, cb => sub { $db->db_sync }); 167 $DB_SYNC{$hkey} ||= AnyEvent->timer (after => 5, cb => sub {
168 delete $DB_SYNC{$hkey};
169 $db->db_sync if $db;
170 });
75 171
76 $db->db_put ($key => $data) 172 $db->db_put ($key => $data)
77} 173}
78 174
79package CFPlus; 175package CFPlus;
85 $path = "$_/CFPlus/resources/$_[0]"; 181 $path = "$_/CFPlus/resources/$_[0]";
86 return $path if -r $path; 182 return $path if -r $path;
87 } 183 }
88 184
89 die "FATAL: can't find required file $_[0]\n"; 185 die "FATAL: can't find required file $_[0]\n";
90}
91
92BEGIN {
93 use Crossfire::Protocol::Base ();
94 *to_json = \&Crossfire::Protocol::Base::to_json;
95 *from_json = \&Crossfire::Protocol::Base::from_json;
96} 186}
97 187
98sub read_cfg { 188sub read_cfg {
99 my ($file) = @_; 189 my ($file) = @_;
100 190
123 open my $fh, ">:utf8", $file 213 open my $fh, ">:utf8", $file
124 or return; 214 or return;
125 print $fh to_json $::CFG; 215 print $fh to_json $::CFG;
126} 216}
127 217
218sub http_proxy {
219 my @proxy = win32_proxy_info;
220
221 if (@proxy) {
222 "http://" . (@proxy < 2 ? "" : @proxy < 3 ? "$proxy[1]\@" : "$proxy[1]:$proxy[2]\@") . $proxy[0]
223 } elsif (exists $ENV{http_proxy}) {
224 $ENV{http_proxy}
225 } else {
226 ()
227 }
228}
229
230sub set_proxy {
231 my $proxy = http_proxy
232 or return;
233
234 $ENV{http_proxy} = $proxy;
235}
236
237sub lwp_useragent {
238 require LWP::UserAgent;
239
240 CFPlus::set_proxy;
241
242 my $ua = LWP::UserAgent->new (
243 agent => "cfplus $VERSION",
244 keep_alive => 1,
245 env_proxy => 1,
246 timeout => 30,
247 );
248}
249
250sub lwp_check($) {
251 my ($res) = @_;
252
253 $res->is_error
254 and die $res->status_line;
255
256 $res
257}
258
128our $DB_ENV; 259our $DB_ENV;
129 260our $DB_STATE;
130{
131 use strict;
132
133 mkdir "$Crossfire::VARDIR/cfplus", 0777;
134 my $recover = $BerkeleyDB::db_version >= 4.4
135 ? eval "DB_REGISTER | DB_RECOVER"
136 : 0;
137
138 $DB_ENV = new BerkeleyDB::Env
139 -Home => "$Crossfire::VARDIR/cfplus",
140 -Cachesize => 1_000_000,
141 -ErrFile => "$Crossfire::VARDIR/cfplus/errorlog.txt",
142# -ErrPrefix => "DATABASE",
143 -Verbose => 1,
144 -Flags => DB_CREATE | DB_RECOVER | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | $recover,
145 -SetFlags => DB_AUTO_COMMIT | DB_LOG_AUTOREMOVE,
146 or die "unable to create/open database home $Crossfire::VARDIR/cfplus: $BerkeleyDB::Error";
147}
148 261
149sub db_table($) { 262sub db_table($) {
150 my ($table) = @_; 263 my ($table) = @_;
151 264
152 $table =~ s/([^a-zA-Z0-9_\-])/sprintf "=%x=", ord $1/ge; 265 $table =~ s/([^a-zA-Z0-9_\-])/sprintf "=%x=", ord $1/ge;
157# -Filename => "database", 270# -Filename => "database",
158# -Subname => $table, 271# -Subname => $table,
159 -Property => DB_CHKSUM, 272 -Property => DB_CHKSUM,
160 -Flags => DB_CREATE | DB_UPGRADE, 273 -Flags => DB_CREATE | DB_UPGRADE,
161 or die "unable to create/open database table $_[0]: $BerkeleyDB::Error" 274 or die "unable to create/open database table $_[0]: $BerkeleyDB::Error"
275}
276
277{
278 use strict;
279
280 my $HOME = "$Crossfire::VARDIR/cfplus-$BerkeleyDB::db_version";
281
282 mkdir $HOME, 0777;
283 my $recover = $BerkeleyDB::db_version >= 4.4
284 ? eval "DB_REGISTER | DB_RECOVER"
285 : 0;
286
287 $DB_ENV = new BerkeleyDB::Env
288 -Home => $HOME,
289 -Cachesize => 1_000_000,
290 -ErrFile => "$HOME/errorlog.txt",
291# -ErrPrefix => "DATABASE",
292 -Verbose => 1,
293 -Flags => DB_CREATE | DB_RECOVER | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | $recover,
294 -SetFlags => DB_AUTO_COMMIT | DB_LOG_AUTOREMOVE,
295 or die "unable to create/open database home $HOME: $BerkeleyDB::Error";
296
297 $DB_STATE = db_table "state";
162} 298}
163 299
164package CFPlus::Layout; 300package CFPlus::Layout;
165 301
166$CFPlus::OpenGL::SHUTDOWN_HOOK{"CFPlus::Layout"} = sub { 302$CFPlus::OpenGL::SHUTDOWN_HOOK{"CFPlus::Layout"} = sub {
264 } elsif ($ev->{button} == 3) { 400 } elsif ($ev->{button} == 3) {
265 my $move_prefix = $::CONN->{open_container} ? 'put' : 'drop'; 401 my $move_prefix = $::CONN->{open_container} ? 'put' : 'drop';
266 if ($self->{container} == $::CONN->{open_container}) { 402 if ($self->{container} == $::CONN->{open_container}) {
267 $move_prefix = "take"; 403 $move_prefix = "take";
268 } 404 }
405
406 my $shortname = CFPlus::shorten $self->{name}, 14;
269 407
270 my @menu_items = ( 408 my @menu_items = (
271 ["examine", sub { $::CONN->send ("examine $self->{tag}") }], 409 ["examine", sub { $::CONN->send ("examine $self->{tag}") }],
272 ["mark", sub { $::CONN->send ("mark ". pack "N", $self->{tag}) }], 410 ["mark", sub { $::CONN->send ("mark ". pack "N", $self->{tag}) }],
273 ["ignite/thaw", # first try of an easier use of flint&steel 411 ["ignite/thaw", # first try of an easier use of flint&steel
289 sub { 427 sub {
290 &::open_string_query ("Rename item to:", sub { 428 &::open_string_query ("Rename item to:", sub {
291 my ($entry, $txt) = @_; 429 my ($entry, $txt) = @_;
292 $::CONN->send ("mark ". pack "N", $self->{tag}); 430 $::CONN->send ("mark ". pack "N", $self->{tag});
293 $::CONN->send ("command rename to <$txt>"); 431 $::CONN->send ("command rename to <$txt>");
294 }); 432 }, $self->{name},
433 "If you input no name or erase the current custom name, the custom name will be unset");
295 } 434 }
296 ], 435 ],
297 ["apply", sub { $::CONN->send ("apply $self->{tag}") }], 436 ["apply", sub { $::CONN->send ("apply $self->{tag}") }],
298 ( 437 (
299 $self->{flags} & F_LOCKED 438 $self->{flags} & F_LOCKED
308 do_n_dialog (sub { $::CONN->send ("move $targ $self->{tag} $_[0]") }) 447 do_n_dialog (sub { $::CONN->send ("move $targ $self->{tag} $_[0]") })
309 } 448 }
310 ] 449 ]
311 ) 450 )
312 ), 451 ),
452 ["bind <i>apply $shortname</i> to a key" => sub { $::BIND_EDITOR->do_quick_binding (["apply $self->{name}"]) }],
313 ); 453 );
314 454
315 CFPlus::UI::Menu->new (items => \@menu_items)->popup ($ev); 455 CFPlus::UI::Menu->new (items => \@menu_items)->popup ($ev);
316 } 456 }
317 457

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines