Skip to content

Commit 8a96286

Browse files
committed
Initial, broken, support for legacy maps
1 parent 5b35a26 commit 8a96286

2 files changed

Lines changed: 121 additions & 38 deletions

File tree

io_scene_a3d/BattleMap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def __init__(self):
274274
self.position = (0.0, 0.0, 0.0)
275275

276276
# Optional
277-
self.groupName = ""
277+
self.groupName = None
278278
self.rotation = (0.0, 0.0, 0.0)
279279
self.scale = (1.0, 1.0, 1.0)
280280

io_scene_a3d/BattleMapBlenderImporter.py

Lines changed: 120 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,48 +26,122 @@
2626
from bpy_extras.image_utils import load_image
2727
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
2828
import bmesh
29+
from mathutils import Matrix
2930

3031
from .A3D import A3D
3132
from .A3DBlenderImporter import A3DBlenderImporter
3233
from .BlenderMaterialUtils import addImageTextureToMaterial
3334

34-
class PropLibrary:
35-
propCache = {}
35+
class Prop:
36+
def __init__(self):
37+
self.objects = []
38+
self.mainObject = None
39+
40+
def loadModel(self, modelPath):
41+
fileExtension = modelPath.split(".")[-1]
42+
if fileExtension == "a3d":
43+
modelData = A3D()
44+
with open(modelPath, "rb") as file: modelData.read(file)
45+
46+
# Import the model
47+
modelImporter = A3DBlenderImporter(modelData, None, reset_empty_transform=False, try_import_textures=False)
48+
self.objects = modelImporter.importData()
49+
elif fileExtension == "3ds":
50+
bpy.ops.import_scene.max3ds(filepath=modelPath, use_apply_transform=False)
51+
for ob in bpy.context.selectable_objects:
52+
# The imported objects are added to the active collection, remove them
53+
bpy.context.collection.objects.unlink(ob)
54+
55+
# Correct the origin XXX: this does not work for all cases, investigate more
56+
ob.animation_data_clear()
57+
x, y, z = -ob.location.x, -ob.location.y, -ob.location.z
58+
objectOrigin = Matrix.Translation((x, y, z))
59+
ob.data.transform(objectOrigin)
60+
ob.location = (0.0, 0.0, 0.0)
61+
62+
self.objects.append(ob)
63+
else:
64+
raise RuntimeError(f"Unknown model file extension: {fileExtension}")
65+
66+
# Identify the main parent object
67+
for ob in self.objects:
68+
if ob.parent == None: self.mainObject = ob
69+
if self.mainObject == None:
70+
raise RuntimeError(f"Unable to find the parent object for: {modelPath}")
71+
72+
def loadSprite(self, propInfo):
73+
spriteInfo = propInfo["sprite"]
74+
75+
# Create a plane we can use for the sprite
76+
me = bpy.data.meshes.new(propInfo["name"])
77+
78+
bm = bmesh.new()
79+
bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=spriteInfo["scale"]*100)
80+
bm.to_mesh(me)
81+
bm.free()
82+
83+
ob = bpy.data.objects.new(me.name, me)
84+
85+
# Assign data
86+
ob.scale = (spriteInfo["width"], 1.0, spriteInfo["height"]) #XXX: this should involve spriteInfo["scale"] probably?
87+
spriteOrigin = Matrix.Translation((0.0, spriteInfo["originY"], 0.0))
88+
me.transform(spriteOrigin)
89+
90+
# Finalise
91+
self.objects.append(ob)
92+
self.mainObject = ob
3693

94+
class PropLibrary:
95+
propGroups = {}
3796
def __init__(self, directory):
3897
self.directory = directory
39-
40-
# Load library json
4198
self.libraryInfo = {}
42-
with open(f"{self.directory}/library.json", "r") as file: # XXX: Get platform agnostic way of doing this
43-
self.libraryInfo = load(file)
99+
100+
# Load library info
101+
with open(f"{self.directory}/library.json", "r") as file: self.libraryInfo = load(file)
102+
print(f"Loaded prop library: " + self.libraryInfo["name"])
103+
104+
def getProp(self, propName, groupName):
105+
# Create the prop group if it's not already loaded
106+
if not groupName in self.propGroups:
107+
self.propGroups[groupName] = {}
44108

45-
print(f"Loaded prop library: {self.libraryInfo["name"]}")
46-
47-
def getProp(self, name, groupName):
48-
# XXX: Handle group names, this code can only load from the remaster libs
49-
# Check if the prop is cached
50-
if not name in self.propCache:
51-
# Get the prop's info
52-
propGroupInfo = self.libraryInfo["groups"][0]
53-
propInfo = {}
54-
for propInfo in propGroupInfo["props"]:
55-
if propInfo["name"] == name: break
56-
57-
# Load the prop
58-
modelFilePath = f"{self.directory}/{propInfo['mesh']['file']}" # XXX: Get platform agnostic way of doing this
59-
modelData = A3D()
60-
with open(modelFilePath, "rb") as file:
61-
modelData.read(file)
109+
# Load the prop if it's not already loaded
110+
if not propName in self.propGroups[groupName]:
111+
# Find the prop group
112+
groupInfo = None
113+
for group in self.libraryInfo["groups"]:
114+
if group["name"] == groupName:
115+
groupInfo = group
116+
break
117+
if groupInfo == None:
118+
raise RuntimeError(f"Unable to find prop group with name {groupName} in " + self.libraryInfo["name"])
62119

63-
# Import into blender
64-
modelImporter = A3DBlenderImporter(modelData, self.directory, try_import_textures=False)
65-
ob, = modelImporter.importData()
120+
# Find the prop
121+
propInfo = None
122+
for prop in groupInfo["props"]:
123+
if prop["name"] == propName:
124+
propInfo = prop
125+
break
126+
if propInfo == None:
127+
raise RuntimeError(f"Unable to find prop with name {propName} in {groupName} from " + self.libraryInfo["name"])
66128

67-
self.propCache[name] = ob
129+
# Create the prop
130+
prop = Prop()
131+
meshInfo = propInfo["mesh"]
132+
spriteInfo = propInfo["sprite"]
133+
if meshInfo != None:
134+
modelPath = f"{self.directory}/" + meshInfo["file"]
135+
prop.loadModel(modelPath)
136+
elif spriteInfo != None:
137+
prop.loadSprite(propInfo)
138+
else:
139+
#XXX: Uhhhhhh, empty prop?
140+
pass
141+
self.propGroups[groupName][propName] = prop
68142

69-
return self.propCache[name]
70-
143+
return self.propGroups[groupName][propName]
144+
71145
def getTexture(self, textureName):
72146
im = load_image(textureName, self.directory)
73147
return im
@@ -149,14 +223,22 @@ def getPropLibrary(self, libraryName):
149223

150224
return self.libraryCache[libraryName]
151225

226+
def tryLoadTexture(self, textureName, libraryName):
227+
if libraryName == None:
228+
libraryName = "Remaster"
229+
230+
propLibrary = self.getPropLibrary(libraryName)
231+
texture = propLibrary.getTexture(f"{textureName}.webp")
232+
return texture
233+
152234
'''
153235
Blender data builders
154236
'''
155237
def getBlenderProp(self, propData):
156238
# Load prop
157239
propLibrary = self.getPropLibrary(propData.libraryName)
158-
propOB = propLibrary.getProp(propData.name, propData.groupName)
159-
propOB = propOB.copy() # We want to use a copy of the prop object
240+
prop = propLibrary.getProp(propData.name, propData.groupName)
241+
propOB = prop.mainObject.copy() # We want to use a copy of the prop object
160242

161243
# Assign data
162244
propOB.name = f"{propData.name}_{propData.ID}"
@@ -167,7 +249,8 @@ def getBlenderProp(self, propData):
167249

168250
# Material
169251
ma = self.materials[propData.materialID]
170-
propOB.data.materials[0] = ma
252+
if len(propOB.data.materials) != 0:
253+
propOB.data.materials[0] = ma
171254

172255
return propOB
173256

@@ -264,15 +347,14 @@ def createBlenderMaterial(self, materialData):
264347
ma = bpy.data.materials.new(f"{materialData.ID}_{materialData.name}")
265348

266349
# Shader specific logic
267-
if materialData.shader == "TankiOnline/SingleTextureShader":
350+
if materialData.shader == "TankiOnline/SingleTextureShader" or materialData.shader == "TankiOnline/SingleTextureShaderWinter":
268351
bsdf = PrincipledBSDFWrapper(ma, is_readonly=False, use_nodes=True)
269352
bsdf.roughness_set(1.0)
270353
bsdf.ior_set(1.0)
271354

272355
# Try load texture
273356
textureParameter = materialData.textureParameters[0]
274-
propLibrary = self.getPropLibrary("Remaster")
275-
texture = propLibrary.getTexture(f"{textureParameter.textureName}.webp")
357+
texture = self.tryLoadTexture(textureParameter.textureName, textureParameter.libraryName)
276358

277359
addImageTextureToMaterial(texture, ma.node_tree)
278360
elif materialData.shader == "TankiOnline/SpriteShader":
@@ -282,8 +364,7 @@ def createBlenderMaterial(self, materialData):
282364

283365
# Try load texture
284366
textureParameter = materialData.textureParameters[0]
285-
propLibrary = self.getPropLibrary("Remaster")
286-
texture = propLibrary.getTexture(f"{textureParameter.textureName}.webp")
367+
texture = self.tryLoadTexture(textureParameter.textureName, textureParameter.libraryName)
287368

288369
addImageTextureToMaterial(texture, ma.node_tree, linkAlpha=True)
289370
elif materialData.shader == "TankiOnline/Terrain":
@@ -292,5 +373,7 @@ def createBlenderMaterial(self, materialData):
292373
bsdf.roughness_set(1.0)
293374
bsdf.ior_set(1.0)
294375
bsdf.base_color_set((0.0, 0.0, 0.0))
376+
else:
377+
pass # Unknown shader
295378

296379
return ma

0 commit comments

Comments
 (0)