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