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.156 by root, Sat Oct 20 21:50:59 2007 UTC vs.
Revision 1.201 by root, Sun Jan 11 03:19:47 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.995'; 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
200 $::CFG = (load_json $file) || (load_json "$file.bak");
201}
202
203sub write_cfg {
204 my $file = "$Deliantra::VARDIR/client.cf";
205
206 $::CFG->{VERSION} = $::VERSION;
207 $::CFG->{layout} = DC::UI::get_layout ();
208
159 open my $fh, $file 209 open my $fh, ">:utf8", "$file~"
160 or return; 210 or return;
211 print $fh JSON::XS->new->utf8->pretty->encode ($::CFG);
212 close $fh;
161 213
162 local $/; 214 rename $file, "$file.bak";
163 my $CFG = <$fh>; 215 rename "$file~", $file;
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}
175
176sub write_cfg {
177 my ($file) = @_;
178
179 $::CFG->{VERSION} = $::VERSION;
180
181 open my $fh, ">:utf8", $file
182 or return;
183 print $fh to_json $::CFG;
184} 216}
185 217
186sub http_proxy { 218sub http_proxy {
187 my @proxy = win32_proxy_info; 219 my @proxy = win32_proxy_info;
188 220
203} 235}
204 236
205sub lwp_useragent { 237sub lwp_useragent {
206 require LWP::UserAgent; 238 require LWP::UserAgent;
207 239
208 CFPlus::set_proxy; 240 DC::set_proxy;
209 241
210 my $ua = LWP::UserAgent->new ( 242 my $ua = LWP::UserAgent->new (
211 agent => "cfplus $VERSION", 243 agent => "deliantra $VERSION",
212 keep_alive => 1, 244 keep_alive => 1,
213 env_proxy => 1, 245 env_proxy => 1,
214 timeout => 30, 246 timeout => 30,
215 ); 247 );
216} 248}
231 $nb = (! ! $nb) + 0; 263 $nb = (! ! $nb) + 0;
232 ioctl $fh, 0x8004667e, \$nb; # FIONBIO 264 ioctl $fh, 0x8004667e, \$nb; # FIONBIO
233 } else { 265 } else {
234 fcntl $fh, &Fcntl::F_SETFL, $nb ? &Fcntl::O_NONBLOCK : 0; 266 fcntl $fh, &Fcntl::F_SETFL, $nb ? &Fcntl::O_NONBLOCK : 0;
235 } 267 }
236
237} 268}
238 269
239package CFPlus::Layout; 270package DC::Layout;
240 271
272$DC::OpenGL::INIT_HOOK{"DC::Layout"} = sub {
273 glyph_cache_restore;
274};
275
241$CFPlus::OpenGL::SHUTDOWN_HOOK{"CFPlus::Layout"} = sub { 276$DC::OpenGL::SHUTDOWN_HOOK{"DC::Layout"} = sub {
242 reset_glyph_cache; 277 glyph_cache_backup;
243}; 278};
244 279
2451; 2801;
246 281
247=back 282=back

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines