Skip to content

Commit 0398697

Browse files
authored
Merge pull request #68 from MrClock8163/dev
v2.4.0
2 parents a361b16 + af0b391 commit 0398697

File tree

15 files changed

+546
-43
lines changed

15 files changed

+546
-43
lines changed

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
* text=auto
22

33
* text eol=lf
4+
5+
*.png binary
6+
*.p3d binary
7+
*.blend binary

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*.blend*
22
*.bat
33
*.zip
4+
test/
45

56
# Byte-compiled / optimized / DLL files
67
__pycache__/

Arma3ObjectBuilder/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## [v2.4.0](https://github.com/MrClock8163/Arma3ObjectBuilder/releases/tag/v2.4.0) (Blender 2.90 -> 4.2)
4+
5+
### Added
6+
7+
- import-export:
8+
- Terrain Builder object list import
9+
- Terrain Builder object list export
10+
11+
### Changed
12+
13+
- LZO1X decompression for BMTR files was improved
14+
15+
### Fixed
16+
17+
- the mandatory part of the LOD validation during export was mistakenly using the Warnings Are Errors setting even if verbose LOD validation was not enabled
18+
319
## [v2.3.5](https://github.com/MrClock8163/Arma3ObjectBuilder/releases/tag/v2.3.5) (Blender 2.90 -> 4.2)
420

521
### Added

Arma3ObjectBuilder/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ The documentation can be found on [GitBook](https://mrcmodding.gitbook.io/arma-3
2020
The add-on can be installed after either downloading a packaged release, or cloning the repository and manually packing it.
2121
For information about add-on installation, visit the official [Blender documentation](https://docs.blender.org/manual/en/latest/editors/preferences/addons.html) page about add-ons.
2222

23+
For Blender 4.2 and higher, the add-on can also be installed from the official [Extensions repository](https://extensions.blender.org/add-ons/arma3objectbuilder).
24+
2325
## License
2426

2527
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Arma3ObjectBuilder/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "Arma 3 Object Builder",
33
"description": "Collection of tools for editing Arma 3 content",
44
"author": "MrClock (present add-on), Hans-Joerg \"Alwarren\" Frieden (original ArmaToolbox add-on)",
5-
"version": (2, 3, 5),
5+
"version": (2, 4, 0),
66
"blender": (2, 90, 0),
77
"location": "Object Builder panels",
88
"warning": "",
@@ -330,6 +330,7 @@ def draw(self, context):
330330
ui.import_export_rtm,
331331
ui.import_export_mcfg,
332332
ui.import_export_armature,
333+
ui.import_export_tbcsv,
333334
ui.import_export_asc,
334335
ui.tool_outliner,
335336
ui.tool_mass,

Arma3ObjectBuilder/blender_manifest.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ type = "add-on"
55
id = "Arma3ObjectBuilder"
66
name = "Arma 3 Object Builder"
77
tagline = "Comprehensive add-on for modding Arma 3"
8-
version = "2.3.5"
8+
version = "2.4.0"
99
blender_version_min = "4.2.0"
1010
website = "https://mrcmodding.gitbook.io/arma-3-object-builder/home"
1111
tags = ["Import-Export", "Game Engine", "Object"]

Arma3ObjectBuilder/io/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from . import data_p3d
44
from . import data_rap
55
from . import data_rtm
6+
from . import data_tbcsv
67
from . import export_asc
78
from . import export_mcfg
89
from . import export_p3d

Arma3ObjectBuilder/io/compression.py

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,28 @@ def lzo1x_decompress(file, expected):
2222
output = bytearray()
2323

2424
def check_free_space(length):
25-
output_length = len(output)
26-
free_space = expected - output_length
25+
free_space = expected - len(output)
2726
if free_space < length:
28-
raise LZO_Error("Output overrun (free buffer: %d, match length: %d)" % (expected - output_length, length))
27+
raise LZO_Error("Output overrun (free buffer: %d, match length: %d)" % (free_space, length))
2928

3029
def read1():
31-
nonlocal file
3230
return struct.unpack('B', file.read(1))[0]
3331

3432
def read(size):
35-
nonlocal file
3633
return struct.unpack('%dB' % size, file.read(size))
3734

3835
def read_le16():
39-
nonlocal file
4036
return struct.unpack('<H', file.read(2))[0]
4137

4238
def extend(items):
4339
nonlocal output
4440
output.extend(items)
45-
46-
def append(item):
47-
nonlocal output
48-
output.append(item)
4941

5042
def copy_literal(length):
5143
check_free_space(length)
5244
extend(read(length))
5345

5446
def copy_match(distance, length):
55-
nonlocal output
5647
output_length = len(output)
5748

5849
if output_length < distance:
@@ -63,15 +54,12 @@ def copy_match(distance, length):
6354
# It is valid to have length that is longer than the back pointer distance, which creates a repeating pattern,
6455
# copying the same bytes that were copied in this same command.
6556
# For this reason, we cannot simply take a slice of the output at the given point with the given length, as
66-
# some of the bytes might not yet be there. We have to copy 1 by 1, like the C implementations.
67-
ptr = output_length - distance
68-
for i in range(length):
69-
append(output[ptr])
70-
ptr += 1
57+
# some of the bytes might not yet be there. We have to copy in chunks with size of the backpointer distance.
58+
start = output_length - distance
59+
extend(output[start:] * (length // distance)) # copy as many whole chunks as possible
60+
extend(output[start:(start + (length % distance))]) # copy remainder
7161

7262
def get_length(x, mask):
73-
nonlocal file
74-
7563
length = x & mask
7664
if not length:
7765
while True:
@@ -91,8 +79,25 @@ def get_length(x, mask):
9179
state = min(4, length)
9280
x = read1()
9381

94-
while True:
95-
if x > 127:
82+
while True:
83+
if x <= 15:
84+
if not state:
85+
length = 3 + get_length(x, 15)
86+
copy_literal(length)
87+
state = 4
88+
elif state < 4:
89+
length = 2
90+
state = x & 3
91+
distance = (read1() << 2) + (x >> 2) + 1
92+
copy_match(distance, length)
93+
copy_literal(state)
94+
elif state == 4:
95+
length = 3
96+
state = x & 3
97+
distance = (read1() << 2) + (x >> 2) + 2049
98+
copy_match(distance, length)
99+
copy_literal(state)
100+
elif x > 127:
96101
state = x & 3
97102
length = 5 + ((x >> 5) & 3)
98103
distance = (read1() << 3) + ((x >> 2) & 7) + 1
@@ -111,7 +116,7 @@ def get_length(x, mask):
111116
state = extra & 3
112117
copy_match(distance, length)
113118
copy_literal(state)
114-
elif x > 15:
119+
else:
115120
length = 2 + get_length(x, 7)
116121
extra = read_le16()
117122
distance = 16384 + ((x & 8) << 11) + (extra >> 2)
@@ -124,24 +129,7 @@ def get_length(x, mask):
124129

125130
copy_match(distance, length)
126131
copy_literal(state)
127-
else:
128-
if not state:
129-
length = 3 + get_length(x, 15)
130-
copy_literal(length)
131-
state = 4
132-
elif state < 4:
133-
length = 2
134-
state = x & 3
135-
distance = (read1() << 2) + (x >> 2) + 1
136-
copy_match(distance, length)
137-
copy_literal(state)
138-
elif state == 4:
139-
length = 3
140-
state = x & 3
141-
distance = (read1() << 2) + (x >> 2) + 2049
142-
copy_match(distance, length)
143-
copy_literal(state)
144-
132+
145133
x = read1()
146134

147135
if expected - len(output):
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Class structure and read-write methods for handling the object list format
2+
# used for interoperability with Terrain Builder
3+
4+
5+
class TBCSV_Error(Exception):
6+
def __str__(self):
7+
return "TBCSV - %s" % super().__str__()
8+
9+
10+
class TBCSV_Transform:
11+
def __init__(self, loc = (0, 0, 0), rot = (0, 0, 0), scale = 1):
12+
self.loc = loc
13+
self.rot = rot
14+
self.scale = scale
15+
16+
def print(self):
17+
east, north, elev = self.loc
18+
yaw, pitch, roll = self.rot
19+
20+
return ";".join(["%.8f" % value for value in (east, north, yaw, pitch, roll, self.scale, elev)])
21+
22+
23+
class TBCSV_Object:
24+
def __init__(self, name = ""):
25+
self.name = name
26+
self.transform = TBCSV_Transform()
27+
28+
@classmethod
29+
def parse(cls, data):
30+
fields = data.rstrip(";").split(";")
31+
if len(fields) != 8:
32+
raise TBCSV_Error("Invalid row, unexpected field count: \"%s\"" % data)
33+
34+
name, east, north, yaw, pitch, roll, scale, elev = fields
35+
36+
output = cls()
37+
try:
38+
output.name = name[1:-1]
39+
output.transform = TBCSV_Transform((float(east), float(north), float(elev)), (float(yaw), float(pitch), float(roll)), float(scale))
40+
except Exception as e:
41+
raise TBCSV_Error(e)
42+
43+
return output
44+
45+
def print(self):
46+
return "\"%s\";%s\n" % (self.name, self.transform.print())
47+
48+
49+
class TBCSV_File:
50+
def __init__(self):
51+
self.source = ""
52+
self.objects = []
53+
54+
@classmethod
55+
def read(cls, file):
56+
output = cls()
57+
58+
for line in file:
59+
if line == "\n":
60+
continue
61+
output.objects.append(TBCSV_Object.parse(line.strip()))
62+
63+
return output
64+
65+
@classmethod
66+
def read_file(cls, filepath):
67+
output = None
68+
with open(filepath, "tr") as file:
69+
output = cls.read(file)
70+
71+
output.source = filepath
72+
73+
return output
74+
75+
def write(self, file):
76+
for obj in self.objects:
77+
file.write(obj.print())
78+
79+
def write_file(self, filepath):
80+
with open(filepath, "wt") as file:
81+
self.write(file)

Arma3ObjectBuilder/io/export_p3d.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,10 @@ def get_lod_data(operator, context, validator, temp_collection):
353353
is_valid_copies = []
354354
for copy in main_obj.a3ob_properties_object.copies:
355355
with temporary_component(operator, main_obj):
356-
is_valid_copies.append(is_valid and validator.validate_lod(main_obj, copy.lod, True, operator.validate_lods_warning_errors, operator.relative_paths))
356+
is_valid_copies.append(is_valid and validator.validate_lod(main_obj, copy.lod, True, operator.validate_lods_warning_errors and operator.validate_lods, operator.relative_paths))
357357

358358
with temporary_component(operator, main_obj):
359-
is_valid &= validator.validate_lod(main_obj, main_obj.a3ob_properties_object.lod, True, operator.validate_lods_warning_errors, operator.relative_paths)
359+
is_valid &= validator.validate_lod(main_obj, main_obj.a3ob_properties_object.lod, True, operator.validate_lods_warning_errors and operator.validate_lods, operator.relative_paths)
360360

361361
proxy_lookup = merge_proxy_objects(main_obj, proxy_objects, operator.relative_paths)
362362

0 commit comments

Comments
 (0)