Browse Source

personalize map loading with replacement of relative tileset/image paths

Bastien Sevajol 6 years ago
parent
commit
ae50954d34
2 changed files with 106 additions and 1 deletions
  1. 83 1
      synergine2_cocos2d/middleware.py
  2. 23 0
      tests/test_tmx.py

+ 83 - 1
synergine2_cocos2d/middleware.py View File

@@ -1,6 +1,11 @@
1 1
 # coding: utf-8
2 2
 import os
3
+import tempfile
3 4
 import typing
5
+from xml.etree import ElementTree
6
+from xml.etree.ElementTree import Element
7
+
8
+from cocos.tiles import Resource
4 9
 
5 10
 from synergine2.config import Config
6 11
 from synergine2.log import get_logger
@@ -10,6 +15,82 @@ if typing.TYPE_CHECKING:
10 15
     import cocos
11 16
 
12 17
 
18
+class MapLoader(object):
19
+    def load(self, map_file_path: str) -> Resource:
20
+        # import cocos here for prevent test crash when no X server is
21
+        # present
22
+        import cocos
23
+
24
+        tree = ElementTree.parse(map_file_path)
25
+        map_element = tree.getroot()
26
+
27
+        final_map_content = self.get_sanitized_map_content(map_element, map_file_path)
28
+        new_file = tempfile.NamedTemporaryFile(mode='w+', suffix='.tmx', delete=False)
29
+        new_file.write(final_map_content)
30
+        new_file.seek(0)
31
+
32
+        # return the map
33
+        return cocos.tiles.load(new_file.name)
34
+
35
+    def get_sanitized_map_content(
36
+        self,
37
+        map_element: Element,
38
+        map_file_path: str,
39
+    ) -> str:
40
+        # Parse tileset to modify path if required
41
+        for tileset_tag in map_element.findall('tileset'):
42
+            if 'source' in tileset_tag.attrib:
43
+                tileset_path = tileset_tag.attrib['source']
44
+
45
+                if not os.path.exists(tileset_path):
46
+                    # try with map file relative path
47
+                    map_dir = os.path.dirname(map_file_path)
48
+                    new_path = os.path.join(map_dir, tileset_path)
49
+                    if os.path.exists(new_path):
50
+                        # It is the correct path, update it
51
+                        tileset_new_content = self.get_sanitized_tileset_content(
52
+                            new_path,
53
+                        )
54
+
55
+                        new_file = tempfile.NamedTemporaryFile(
56
+                            mode='w+',
57
+                            suffix='.tsx',
58
+                            delete=False,
59
+                        )
60
+                        new_file.write(tileset_new_content)
61
+                        new_file.seek(0)
62
+
63
+                        tileset_tag.attrib['source'] = new_file.name
64
+
65
+        # Write new file in temporary dir
66
+        map_xml_str = ElementTree.tostring(
67
+            map_element,
68
+            encoding='utf8',
69
+            method='xml',
70
+        )
71
+        return map_xml_str.decode('utf-8')
72
+
73
+    def get_sanitized_tileset_content(
74
+        self,
75
+        tileset_path: str,
76
+    ) -> str:
77
+        tileset_dir = os.path.dirname(tileset_path)
78
+        tree = ElementTree.parse(tileset_path)
79
+        tileset_element = tree.getroot()
80
+
81
+        image_node = tileset_element.find('image')
82
+        image_path = image_node.attrib['source']
83
+
84
+        final_image_path = os.path.join(tileset_dir, image_path)
85
+        image_node.attrib['source'] = final_image_path
86
+        tileset_xml_str = ElementTree.tostring(
87
+            tileset_element,
88
+            encoding='utf8',
89
+            method='xml',
90
+        )
91
+        return tileset_xml_str.decode('utf-8')
92
+
93
+
13 94
 class MapMiddleware(object):
14 95
     def __init__(
15 96
         self,
@@ -30,7 +111,8 @@ class MapMiddleware(object):
30 111
         import cocos
31 112
 
32 113
         map_file_path = self.get_map_file_path()
33
-        self.tmx = cocos.tiles.load(map_file_path)
114
+        loader = MapLoader()
115
+        self.tmx = loader.load(map_file_path)
34 116
 
35 117
     def get_background_sprite(self) -> 'cocos.sprite.Sprite':
36 118
         raise NotImplementedError()

+ 23 - 0
tests/test_tmx.py View File

@@ -1,4 +1,7 @@
1 1
 # coding: utf-8
2
+from xml.etree import ElementTree
3
+
4
+from synergine2_cocos2d.middleware import MapLoader
2 5
 from synergine2_xyz.map import TMXMap
3 6
 from synergine2_xyz.physics import Matrixes
4 7
 from synergine2_xyz.tmx_utils import fill_matrix
@@ -35,3 +38,23 @@ class TestVisibilityMatrix(BaseTest):
35 38
             [(0.0, 0.0), (2.0, 100.0), (2.0, 100.0), (2.0, 100.0), (0.0, 0.0), ],
36 39
             [(0.0, 0.0), (0.0, 0.0),   (0.0, 0.0),   (0.0, 0.0),   (0.0, 0.0), ],
37 40
         ] == matrixes.get_matrix('visibility')
41
+
42
+
43
+class TestLoadMap(BaseTest):
44
+    def test_get_sanitized_map_content(self):
45
+        loader = MapLoader()
46
+        tree = ElementTree.parse('tests/fixtures/light.tmx')
47
+        map_element = tree.getroot()
48
+
49
+        map_content = loader.get_sanitized_map_content(
50
+            map_element,
51
+            'tests/fixtures/light.tmx',
52
+        )
53
+        assert '<tileset firstgid="1" source="/tmp/' in map_content
54
+
55
+    def test_get_sanitized_tileset_content(self):
56
+        loader = MapLoader()
57
+        tileset_content = loader.get_sanitized_tileset_content(
58
+            'tests/fixtures/terrain.tsx',
59
+        )
60
+        assert 'source="tests/fixtures/terrain.png"' in tileset_content