1# SLOW!!! 2package stkutils::data_packet; 3use strict; 4use IO::File; 5use stkutils::debug; 6use stkutils::ini_file; 7sub new { 8 my $class = shift; 9 my $data = shift; 10 my $self = {}; 11 $self->{data} = ($data or ''); 12 $self->{init_length} = CORE::length($self->{data}); 13 bless($self, $class); 14 return $self; 15} 16sub unpack { 17 my $self = shift; 18 my $template = shift; 19 my ($len) = @_; 20stkutils::debug::fail(__PACKAGE__.'::unpack', __LINE__, 'defined $self', "packet is not defined") if !(defined $self); 21stkutils::debug::fail(__PACKAGE__.'::unpack', __LINE__, 'defined $self->{data}', "there is no data in packet") if !(defined $self->{data}); 22stkutils::debug::fail(__PACKAGE__.'::unpack', __LINE__, 'defined $template', "template is not defined") if !(defined $template); 23 my @values; 24 if (!defined $len) { 25 @values = CORE::unpack($template.'a*', $self->{data}); 26 stkutils::debug::fail(__PACKAGE__.'::unpack', __LINE__, '$#values != -1', "cannot unpack requested data") if $#values == -1; 27 $self->{data} = pop(@values); 28 } else { 29 my $d = substr($self->{data}, 0, $len, ''); 30 @values = CORE::unpack($template, $d); 31 } 32stkutils::debug::fail(__PACKAGE__.'::unpack', __LINE__, 'defined $self->{data}', "data container is empty") if !(defined $self->{data}); 33#print "@values\n"; 34 return @values; 35} 36sub pack { 37 my $self = shift; 38 my $template = shift; 39stkutils::debug::fail(__PACKAGE__.'::pack', __LINE__, 'defined $template', "template is not defined") if !(defined $template); 40stkutils::debug::fail(__PACKAGE__.'::pack', __LINE__, 'defined @_', "data is not defined") if !(defined @_); 41stkutils::debug::fail(__PACKAGE__.'::pack', __LINE__, '!defined $_[0]', "packet is not defined") unless defined $_[0]; 42#print "@_\n"; 43 $self->{data} .= CORE::pack($template, @_); 44} 45use constant template_for_scalar => { 46 h32 => 'V', 47 h16 => 'v', 48 h8 => 'C', 49 u32 => 'V', 50 u16 => 'v', 51 u8 => 'C', 52 s32 => 'l', 53 s16 => 'v', 54 s8 => 'C', 55 sz => 'Z*', 56 f32 => 'f', 57 guid => 'a[16]', 58}; 59use constant template_len => { 60 'V' => 4, 61 'v' => 2, 62 'C' => 1, 63 'l' => 4, 64 'f' => 4, 65 'a[16]' => 16, 66 'C8' => 8, 67 'C4' => 4, 68 'f3' => 12, 69 'f4' => 16, 70 'l3' => 12, 71 'l4' => 16, 72 'V3' => 12, 73 'V4' => 16, 74 'C171' => 171, 75 'C12' => 12, 76}; 77use constant template_for_vector => { 78 l8u8v => 'C/C', 79 l32u8v => 'V/C', 80 l32u16v => 'V/v', 81 l32u32v => 'V/V', 82 l32szv => 'V/(Z*)', 83 l8szbv => 'C/(Z*C)', 84 u8v8 => 'C8', 85 u8v4 => 'C4', 86 f32v3 => 'f3', 87 f32v4 => 'f4', 88 s32v3 => 'l3', 89 s32v4 => 'l4', 90 h32v3 => 'V3', 91 h32v4 => 'V4', 92 actorData => 'C171', 93 ha1 => 'C12', 94 ha2 => 'C8', 95}; 96sub unpack_properties { 97 my $self = shift; 98 my $container = shift; 99 foreach my $p (@_) { 100#print "$p->{name} = "; 101 if ($p->{type} eq 'shape') { 102 my ($count) = $self->unpack('C', 1); 103 while ($count--) { 104 my %shape; 105 ($shape{type}) = $self->unpack('C', 1); 106 if ($shape{type} == 0) { 107 @{$shape{sphere}} = $self->unpack('f4', 16); 108 } elsif ($shape{type} == 1) { 109 @{$shape{box}} = $self->unpack('f12', 48); 110 } else { 111 stkutils::debug::fail(__PACKAGE__.'::unpack_properties', __LINE__, '$shape{type} == 0 or $shape{type} == 1', "shape has undefined type ($shape{type})"); 112 } 113 push @{$container->{$p->{name}}}, \%shape; 114 } 115# } elsif ($p->{type} eq 'ordaf') { 116# my ($count) = $self->unpack('V'); 117# if ($count == 0) { 118# ($container->{$p->{name}}) = 0; 119# } 120# while ($count--) { 121# my %obj; 122# ($obj{name}, $obj{number}) = $self->unpack('Z*V'); 123# my ($inner_count) = $self->unpack('V'); 124# while ($inner_count--) { 125# my %afs; 126# ($afs{af_section}) = $self->unpack('Z*VV'); 127# push @{$obj{af_sects}}, \%afs; 128# } 129# push @{$container->{$p->{name}}}, \%obj; 130# } 131 } elsif ($p->{type} eq 'suppl') { 132 my ($count) = $self->unpack('V', 4); 133 while ($count--) { 134 my %obj; 135 ($obj{section_name}) = $self->unpack('Z*'); 136 ($obj{item_count}, $obj{min_factor}, $obj{max_factor}) = $self->unpack('Vff', 12); 137 push @{$container->{$p->{name}}}, \%obj; 138 } 139 } elsif ($p->{type} eq 'f32v4') { #let's shut up #QNAN warnings. 140 my @buf = $self->unpack('f4', 16); 141 my $i = 0; 142 while ($i < 4) { 143 if (!defined ($buf[$i] <=> 9**9**9)) { 144# print "replacing bad float $buf[$i]...\n"; 145 $buf[$i] = 0; 146 } 147 $i++; 148 } 149 @{$container->{$p->{name}}} = @buf; 150 } elsif ($p->{type} eq 'f32v3') { 151 my @buf = $self->unpack('f3', 12); 152 my $i = 0; 153 while ($i < 3) { 154 if (!defined ($buf[$i] <=> 9**9**9)) { 155# print "replacing bad float $buf[$i]...\n"; 156 $buf[$i] = 0; 157 } 158 $i++; 159 } 160 @{$container->{$p->{name}}} = @buf; 161 } elsif ($p->{type} eq 'afspawns' or $p->{type} eq 'afspawns_u32') { 162 my ($count) = $self->unpack('v', 2); 163 while ($count--) { 164 my %obj; 165 if ($p->{type} eq 'afspawns') { 166 ($obj{section_name}) = $self->unpack('Z*'); 167 ($obj{weight}) = $self->unpack('f', 4); 168 } else { 169 ($obj{section_name}) = $self->unpack('Z*'); 170 ($obj{weight}) = $self->unpack('V', 4); 171 } 172 push @{$container->{$p->{name}}}, \%obj; 173 } 174 } else { 175 my $template = template_for_scalar->{$p->{type}}; 176 if (defined $template) { 177 $self->error_handler($container, $template) if CORE::length($self->{data}) == 0; 178 ($container->{$p->{name}}) = $self->unpack($template, template_len->{$template}); 179 if ($p->{type} eq 'sz') { 180 chomp $container->{$p->{name}}; 181 $container->{$p->{name}} =~ s/\r//g; 182 } 183 } elsif ($p->{type} eq 'u24') { 184 ($container->{$p->{name}}) = CORE::unpack('V', CORE::pack('CCCC', $self->unpack('C3', 3), 0)); 185 } elsif ($p->{type} eq 'q16') { 186 my ($qf) = $self->unpack('v', 2); 187 ($container->{$p->{name}}) = convert_q16($qf); 188 } elsif ($p->{type} eq 'q16_old') { 189 my ($qf) = $self->unpack('v', 2); 190 ($container->{$p->{name}}) = convert_q16_old($qf); 191 } elsif ($p->{type} eq 'q8') { 192 my ($q8) = $self->unpack('C', 1); 193 ($container->{$p->{name}}) = convert_q8($q8); 194 } elsif ($p->{type} eq 'q8v3') { 195 my (@q8) = $self->unpack('C3', 3); 196 my $i = 0; 197 while ($i < 3) { 198 @{$container->{$p->{name}}}[$i] = convert_q8($q8[$i]); 199 $i++; 200 } 201 } elsif ($p->{type} eq 'q8v4') { 202 my (@q8) = $self->unpack('C4', 4); 203 my $i = 0; 204 while ($i < 4) { 205 @{$container->{$p->{name}}}[$i] = convert_q8($q8[$i]); 206 $i++; 207 } 208 } else { 209 @{$container->{$p->{name}}} = $self->unpack(template_for_vector->{$p->{type}}); 210 } 211 } 212 } 213} 214sub pack_properties { 215 my $self = shift; 216 my $container = shift; 217 218 foreach my $p (@_) { 219#print "$p->{name} = "; 220 my $template = template_for_scalar->{$p->{type}}; 221 if (defined $template) { 222 $self->pack($template, $container->{$p->{name}}); 223 } elsif ($p->{type} eq 'shape') { 224 $self->pack('C', $#{$container->{$p->{name}}} + 1); 225 foreach my $shape (@{$container->{$p->{name}}}) { 226 $self->pack('C', $$shape{type}); 227 if ($$shape{type} == 0) { 228 $self->pack('f4', @{$$shape{sphere}}); 229 } elsif ($$shape{type} == 1) { 230 $self->pack('f12', @{$$shape{box}}); 231 } 232 } 233 } elsif ($p->{type} eq 'u24') { 234 $self->pack('CCC', CORE::unpack('CCCC', CORE::pack('V', $container->{$p->{name}}))); 235 } elsif ($p->{type} eq 'q16') { 236 my $f16 = $container->{$p->{name}}; 237 $self->pack("v", convert_u16($f16)); 238 } elsif ($p->{type} eq 'q16_old') { 239 my $f16 = $container->{$p->{name}}; 240 $self->pack("v", convert_u16_old($f16)); 241 } elsif ($p->{type} eq 'suppl') { 242 $self->pack('V', $#{$container->{$p->{name}}} + 1); 243 foreach my $sect (@{$container->{$p->{name}}}) { 244 $self->pack('Z*Vff', $$sect{section_name}, $$sect{item_count}, $$sect{min_factor}, $$sect{max_factor}); 245 } 246 } elsif ($p->{type} eq 'afspawns') { 247 $self->pack('v', $#{$container->{$p->{name}}} + 1); 248 foreach my $sect (@{$container->{$p->{name}}}) { 249 $self->pack('Z*f', $$sect{section_name}, $$sect{weight}); 250 } 251 } elsif ($p->{type} eq 'afspawns_u32') { 252 $self->pack('v', $#{$container->{$p->{name}}} + 1); 253 foreach my $sect (@{$container->{$p->{name}}}) { 254 $self->pack('Z*V', $$sect{section_name}, $$sect{weight}); 255 } 256 } elsif ($p->{type} eq 'q8') { 257 my $f8 = $container->{$p->{name}}; 258 $self->pack("C", convert_u8($f8)); 259# } elsif ($p->{type} eq 'ordaf') { 260# $self->pack('V', $#{$container->{$p->{name}}} + 1); 261# my $i = 0; 262# foreach my $sect (@{$container->{$p->{name}}}) { 263# $self->pack('Z*V', $$sect[0..1]); 264# $self->pack('V', $#{$sect[2]} + 1); 265# my $k = 0; 266# foreach my $af_sect (@{$sect[2]}) { 267# $self->pack('Z*VV', $af_sect[0], $af_sect[1], $af_sect[2]); 268# $k++; 269# } 270# $i++; 271# } 272 } else { 273 my $n = $#{$container->{$p->{name}}} + 1; 274 if ($p->{type} eq 'l32u16v') { 275 $self->pack("Vv$n", $n, @{$container->{$p->{name}}}); 276 } elsif ($p->{type} eq 'l32u8v') { 277 $self->pack("VC$n", $n, @{$container->{$p->{name}}}); 278 } elsif ($p->{type} eq 'l32u32v') { 279 $self->pack("VV$n", $n, @{$container->{$p->{name}}}); 280 } elsif ($p->{type} eq 'l32szv') { 281 $self->pack("V(Z*)$n", $n, @{$container->{$p->{name}}}); 282 } elsif ($p->{type} eq 'l8u8v') { 283 $self->pack("CC$n", $n, @{$container->{$p->{name}}}); 284 } elsif ($p->{type} eq 'q8v') { 285 $self->pack("C$n", @{$container->{$p->{name}}}); 286 } elsif ($p->{type} eq 'q8v3' or $p->{type} eq 'q8v4') { 287 foreach my $u8 (@{$container->{$p->{name}}}) { 288 $self->pack('C', convert_u8($u8)); 289 } 290 } elsif ($p->{type} eq 'l8szbv') { 291 $n = $n/2; 292 $self->pack("C(Z*C)$n", $n, @{$container->{$p->{name}}}); 293 } elsif (exists (template_for_vector->{$p->{type}})) { 294 $self->pack(template_for_vector->{$p->{type}}, @{$container->{$p->{name}}}); 295 } else { 296 stkutils::debug::fail(__PACKAGE__.'::pack_properties', __LINE__, '', "cannot find proper template for type $p->{type}"); 297 } 298 } 299 } 300} 301sub length { 302 return CORE::length($_[0]->{data}); 303} 304sub r_tell { 305 return $_[0]->{init_length} - CORE::length($_[0]->{data}); 306} 307sub w_tell { 308 return CORE::length($_[0]->{data}); 309} 310sub data { 311 return $_[0]->{data}; 312} 313sub convert_q8 { 314 my ($u) = @_; 315 my $q = ($u / 255.0); 316 return $q; 317} 318sub convert_u8 { 319 my ($q) = @_; 320 my $u = int ($q * 255.0); 321 return $u; 322} 323sub convert_q16 { 324 my ($u) = @_; 325 my $q = (($u / 43.69) - 500.0); 326 return $q; 327} 328sub convert_u16 { 329 my ($q) = @_; 330 my $u = (($q + 500.0) * 43.69); 331 return $u; 332} 333sub convert_q16_old { 334 my ($u) = @_; 335 my $q = (($u / 32.77) - 1000.0); 336 return $q; 337} 338sub convert_u16_old { 339 my ($q) = @_; 340 my $u = (($q + 1000.0) * 32.77); 341 return $u; 342} 343sub error_handler { 344 my $self = shift; 345 my ($container, $template) = @_; 346 if (($template eq 'C') || (ref($container) eq 'se_zone_anom')) { 347 bless $container, 'cse_alife_anomalous_zone'; 348 my $ini = stkutils::ini_file->new('sections.ini', 'r'); 349 $ini->{sections_hash}{'sections'}{$container->{section_name}} = 'cse_alife_anomalous_zone'; 350 my $ini_new = IO::File->new('sections.new.ini', 'w'); 351 print $ini_new "[sections]\n"; 352 foreach my $section (keys %{$ini->{sections_hash}{'sections'}}) { 353 my $val = $ini->{sections_hash}{'sections'}{$section}; 354 print $ini_new "$section = $val\n"; 355 } 356 $ini->close(); 357 $ini_new->close(); 358 unlink 'sections.ini'; 359 rename 'sections.new.ini', 'sections.ini'; 360 unlink 'sections.new.ini'; 361 } else { 362 stkutils::debug::fail(__PACKAGE__.'::error_handler', __LINE__, '', "cannot fix NarSol problem\n"); 363 } 364} 3651; 366