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.150 by root, Sun Sep 2 03:55:02 2007 UTC vs.
Revision 1.200 by root, Sun Jan 4 10:22:19 2009 UTC

1=head1 NAME 1=head1 NAME
2 2
3CFPlus - undocumented utility garbage for our crossfire client 3DC - undocumented utility garbage for our deliantra client
4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 use CFPlus; 7 use DC;
8 8
9=head1 DESCRIPTION 9=head1 DESCRIPTION
10 10
11=over 4 11=over 4
12 12
13=cut 13=cut
14 14
15package CFPlus; 15package DC;
16 16
17use Carp (); 17use Carp ();
18 18
19our $VERSION;
20
19BEGIN { 21BEGIN {
20 $VERSION = '0.9842'; 22 $VERSION = '2.02';
21 23
22 use XSLoader; 24 use XSLoader;
23 XSLoader::load "CFPlus", $VERSION; 25 XSLoader::load "Deliantra::Client", $VERSION;
24} 26}
25 27
26use utf8; 28use utf8;
29use strict qw(vars subs);
27 30
31use Socket ();
28use AnyEvent (); 32use AnyEvent ();
33use AnyEvent::Util ();
29use Pod::POM (); 34use Pod::POM ();
30use File::Path (); 35use File::Path ();
31use Storable (); # finally 36use Storable (); # finally
32use Fcntl (); 37use Fcntl ();
33use JSON::XS qw(to_json from_json); 38use JSON::XS qw(encode_json decode_json);
34 39
35=item guard { BLOCK } 40=item guard { BLOCK }
36 41
37Returns 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.
38 43
39=cut 44=cut
40 45
41sub guard(&) { 46sub guard(&) {
42 bless \(my $cb = $_[0]), "CFPlus::Guard" 47 bless \(my $cb = $_[0]), "DC::Guard"
43} 48}
44 49
45sub CFPlus::Guard::DESTROY { 50sub DC::Guard::DESTROY {
46 ${$_[0]}->() 51 ${$_[0]}->()
47} 52}
48 53
49=item shorten $string[, $maxlength] 54=item shorten $string[, $maxlength]
50 55
64 s/</&lt;/g; 69 s/</&lt;/g;
65 70
66 $_ 71 $_
67} 72}
68 73
69sub socketpipe() {
70 socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
71 or die "cannot establish bidirectional pipe: $!\n";
72
73 ($fh1, $fh2)
74}
75
76sub background(&;&) { 74sub background(&;&) {
77 my ($bg, $cb) = @_; 75 my ($bg, $cb) = @_;
78 76
79 my ($fh_r, $fh_w) = CFPlus::socketpipe; 77 my ($fh_r, $fh_w) = AnyEvent::Util::portable_socketpair
78 or die "unable to create background socketpair: $!";
80 79
81 my $pid = fork; 80 my $pid = fork;
82 81
83 if (defined $pid && !$pid) { 82 if (defined $pid && !$pid) {
84 local $SIG{__DIE__}; 83 local $SIG{__DIE__};
94 93
95 if ($@) { 94 if ($@) {
96 my $msg = $@; 95 my $msg = $@;
97 $msg =~ s/\n+/\n/; 96 $msg =~ s/\n+/\n/;
98 warn "FATAL: $msg"; 97 warn "FATAL: $msg";
99 CFPlus::_exit 1; 98 DC::_exit 1;
100 } 99 }
101 100
102 # win32 is fucked up, of course. exit will clean stuff up, 101 # win32 is fucked up, of course. exit will clean stuff up,
103 # which destroys our database etc. _exit will exit ALL 102 # which destroys our database etc. _exit will exit ALL
104 # forked processes, because of the dreaded fork emulation. 103 # forked processes, because of the dreaded fork emulation.
105 CFPlus::_exit 0; 104 DC::_exit 0;
106 } 105 }
107 106
108 close $fh_w; 107 close $fh_w;
109 108
110 my $buffer; 109 my $buffer;
122 utf8::decode $line; 121 utf8::decode $line;
123 if ($line =~ /^\x{e877}json_msg (.*)$/s) { 122 if ($line =~ /^\x{e877}json_msg (.*)$/s) {
124 $cb->(JSON::XS->new->allow_nonref->decode ($1)); 123 $cb->(JSON::XS->new->allow_nonref->decode ($1));
125 } else { 124 } else {
126 ::message ({ 125 ::message ({
127 markup => "background($pid): " . CFPlus::asxml $line, 126 markup => "background($pid): " . DC::asxml $line,
128 }); 127 });
129 } 128 }
130 } 129 }
131 }); 130 });
132} 131}
138 $msg =~ s/\n//g; 137 $msg =~ s/\n//g;
139 utf8::encode $msg; 138 utf8::encode $msg;
140 print $msg, "\n"; 139 print $msg, "\n";
141} 140}
142 141
143package CFPlus; 142package DC;
143
144our $RC_THEME;
145our %THEME;
146our @RC_PATH;
147our $RC_BASE;
148
149for (grep !ref, @INC) {
150 $RC_BASE = "$_/Deliantra/Client/private/resources";
151 last if -d $RC_BASE;
152}
144 153
145sub find_rcfile($) { 154sub find_rcfile($) {
146 my $path; 155 my $path;
147 156
148 for (grep !ref, @INC) { 157 for (@RC_PATH, "") {
149 $path = "$_/CFPlus/resources/$_[0]"; 158 $path = "$RC_BASE/$_/$_[0]";
150 return $path if -r $path; 159 return $path if -r $path;
151 } 160 }
152 161
153 die "FATAL: can't find required file $_[0]\n"; 162 die "FATAL: can't find required file \"$_[0]\" in \"$RC_BASE\"\n";
163}
164
165sub load_json($) {
166 my ($file) = @_;
167
168 open my $fh, $file
169 or return;
170
171 local $/;
172 JSON::XS->new->utf8->relaxed->decode (<$fh>)
173}
174
175sub set_theme($) {
176 return if $RC_THEME eq $_[0];
177 $RC_THEME = $_[0];
178
179 # kind of hacky, find the main theme file, then load all theme files and merge them
180
181 %THEME = ();
182 @RC_PATH = "theme-$RC_THEME";
183
184 my $theme = load_json find_rcfile "theme.json"
185 or die "FATAL: theme resource file not found";
186
187 @RC_PATH = @{ $theme->{path} } if $theme->{path};
188
189 for (@RC_PATH, "") {
190 my $theme = load_json "$RC_BASE/$_/theme.json"
191 or next;
192
193 %THEME = ( %$theme, %THEME );
194 }
154} 195}
155 196
156sub read_cfg { 197sub read_cfg {
157 my ($file) = @_; 198 my ($file) = @_;
158 199
159 open my $fh, $file 200 $::CFG = load_json $file;
160 or return;
161
162 local $/;
163 my $CFG = <$fh>;
164
165 if ($CFG =~ /^---/) { ## TODO compatibility cruft, remove
166 require YAML;
167 utf8::decode $CFG;
168 $::CFG = YAML::Load ($CFG);
169 } elsif ($CFG =~ /^\{/) {
170 $::CFG = from_json $CFG;
171 } else {
172 $::CFG = eval $CFG; ## todo comaptibility cruft
173 }
174} 201}
175 202
176sub write_cfg { 203sub write_cfg {
177 my ($file) = @_; 204 my $file = "$Deliantra::VARDIR/client.cf";
178 205
179 $::CFG->{VERSION} = $::VERSION; 206 $::CFG->{VERSION} = $::VERSION;
180 207
181 open my $fh, ">:utf8", $file 208 open my $fh, ">:utf8", $file
182 or return; 209 or return;
183 print $fh to_json $::CFG; 210 print $fh JSON::XS->new->utf8->pretty->encode ($::CFG);
184} 211}
185 212
186sub http_proxy { 213sub http_proxy {
187 my @proxy = win32_proxy_info; 214 my @proxy = win32_proxy_info;
188 215
203} 230}
204 231
205sub lwp_useragent { 232sub lwp_useragent {
206 require LWP::UserAgent; 233 require LWP::UserAgent;
207 234
208 CFPlus::set_proxy; 235 DC::set_proxy;
209 236
210 my $ua = LWP::UserAgent->new ( 237 my $ua = LWP::UserAgent->new (
211 agent => "cfplus $VERSION", 238 agent => "deliantra $VERSION",
212 keep_alive => 1, 239 keep_alive => 1,
213 env_proxy => 1, 240 env_proxy => 1,
214 timeout => 30, 241 timeout => 30,
215 ); 242 );
216} 243}
231 $nb = (! ! $nb) + 0; 258 $nb = (! ! $nb) + 0;
232 ioctl $fh, 0x8004667e, \$nb; # FIONBIO 259 ioctl $fh, 0x8004667e, \$nb; # FIONBIO
233 } else { 260 } else {
234 fcntl $fh, &Fcntl::F_SETFL, $nb ? &Fcntl::O_NONBLOCK : 0; 261 fcntl $fh, &Fcntl::F_SETFL, $nb ? &Fcntl::O_NONBLOCK : 0;
235 } 262 }
236
237} 263}
238 264
239package CFPlus::Layout; 265package DC::Layout;
240 266
267$DC::OpenGL::INIT_HOOK{"DC::Layout"} = sub {
268 glyph_cache_restore;
269};
270
241$CFPlus::OpenGL::SHUTDOWN_HOOK{"CFPlus::Layout"} = sub { 271$DC::OpenGL::SHUTDOWN_HOOK{"DC::Layout"} = sub {
242 reset_glyph_cache; 272 glyph_cache_backup;
243}; 273};
244 274
2451; 2751;
246 276
247=back 277=back

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines