maps4fs 2.9.2__py3-none-any.whl → 2.9.37__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -168,6 +168,14 @@ class Texture(ImageComponent):
168
168
  """
169
169
  return [layer for layer in self.layers if layer.indoor]
170
170
 
171
+ def get_building_category_layers(self) -> list[Layer]:
172
+ """Returns layers which have building category defined.
173
+
174
+ Returns:
175
+ list[Layer]: List of layers which have building category defined.
176
+ """
177
+ return [layer for layer in self.layers if layer.building_category is not None]
178
+
171
179
  def process(self) -> None:
172
180
  """Processes the data to generate textures."""
173
181
  self._prepare_weights()
@@ -469,8 +477,11 @@ class Texture(ImageComponent):
469
477
  self._draw_layer(layer, info_layer_data, layer_image) # type: ignore
470
478
  self._add_roads(layer, info_layer_data)
471
479
 
472
- output_image = cv2.bitwise_and(layer_image, mask) # type: ignore
473
- cumulative_image = cv2.bitwise_or(cumulative_image, output_image) # type: ignore
480
+ if not layer.external:
481
+ output_image = cv2.bitwise_and(layer_image, mask) # type: ignore
482
+ cumulative_image = cv2.bitwise_or(cumulative_image, output_image) # type: ignore
483
+ else:
484
+ output_image = layer_image # type: ignore
474
485
 
475
486
  cv2.imwrite(layer_path, output_image)
476
487
  self.logger.debug("Texture %s saved.", layer_path)
@@ -550,6 +561,7 @@ class Texture(ImageComponent):
550
561
  "points": linestring,
551
562
  "tags": str(layer.tags),
552
563
  "width": layer.width,
564
+ "road_texture": layer.road_texture,
553
565
  }
554
566
  info_layer_data[f"{layer.info_layer}_polylines"].append(linestring_entry) # type: ignore
555
567
 
@@ -803,7 +815,7 @@ class Texture(ImageComponent):
803
815
  is_fieds = info_layer == "fields"
804
816
 
805
817
  ox_settings.use_cache = self.map.texture_settings.use_cache
806
- ox_settings.requests_timeout = 30
818
+ ox_settings.requests_timeout = 10
807
819
 
808
820
  objects = self.fetch_osm_data(tags)
809
821
  if objects is None or objects.empty:
@@ -834,7 +846,7 @@ class Texture(ImageComponent):
834
846
  else:
835
847
  objects = ox.features_from_bbox(bbox=self.new_bbox, tags=tags)
836
848
  except Exception as e:
837
- self.logger.debug("Error fetching objects for tags: %s. Error: %s.", tags, e)
849
+ self.logger.warning("Error fetching objects for tags: %s. Error: %s.", tags, e)
838
850
  return None
839
851
 
840
852
  return objects
@@ -40,7 +40,7 @@ logger.info(
40
40
  )
41
41
 
42
42
  TEMPLATES_STRUCTURE = {
43
- "fs25": ["texture_schemas", "tree_schemas", "map_templates"],
43
+ "fs25": ["texture_schemas", "tree_schemas", "buildings_schemas", "map_templates"],
44
44
  "fs22": ["texture_schemas", "map_templates"],
45
45
  }
46
46
 
@@ -51,11 +51,19 @@ def ensure_templates():
51
51
  If MFS_TEMPLATES_DIR is empty or doesn't exist, clone the maps4fsdata
52
52
  repository and run the preparation script to populate it.
53
53
  """
54
-
55
54
  # Check if templates directory exists and has content
56
- if os.path.exists(MFS_TEMPLATES_DIR) and os.listdir(MFS_TEMPLATES_DIR):
57
- logger.info("Templates directory already exists and contains data: %s", MFS_TEMPLATES_DIR)
58
- return
55
+ if os.path.exists(MFS_TEMPLATES_DIR): # and os.listdir(MFS_TEMPLATES_DIR):
56
+ logger.info("Templates directory already exists: %s", MFS_TEMPLATES_DIR)
57
+
58
+ files = [
59
+ entry
60
+ for entry in os.listdir(MFS_TEMPLATES_DIR)
61
+ if os.path.isfile(os.path.join(MFS_TEMPLATES_DIR, entry))
62
+ ]
63
+
64
+ if files:
65
+ logger.info("Templates directory contains files and will not be modified.")
66
+ return
59
67
 
60
68
  logger.info("Templates directory is empty or missing, preparing data...")
61
69
 
@@ -82,15 +90,31 @@ def ensure_templates():
82
90
  text=True,
83
91
  )
84
92
 
85
- # Make the preparation script executable
86
- prep_script = os.path.join(clone_dir, "prepare_data.sh")
93
+ if os.name == "nt":
94
+ logger.info("Detected Windows OS, running PowerShell preparation script...")
95
+ prep_script = os.path.join(clone_dir, "prepare_data.ps1")
96
+ for_subprocess = [
97
+ "powershell",
98
+ "-ExecutionPolicy",
99
+ "Bypass",
100
+ "-File",
101
+ "prepare_data.ps1",
102
+ ]
103
+ else:
104
+ logger.info("Detected non-Windows OS, running bash preparation script...")
105
+ prep_script = os.path.join(clone_dir, "prepare_data.sh")
106
+ for_subprocess = ["./prepare_data.sh"]
107
+
87
108
  if os.path.exists(prep_script):
88
- os.chmod(prep_script, 0o755)
109
+ try:
110
+ os.chmod(prep_script, 0o755)
111
+ except Exception as e:
112
+ logger.warning("Could not set execute permissions on script: %s", str(e))
89
113
 
90
114
  logger.info("Running data preparation script...")
91
115
  # Run the preparation script from the cloned directory
92
116
  subprocess.run(
93
- ["./prepare_data.sh"], cwd=clone_dir, check=True, capture_output=True, text=True
117
+ for_subprocess, cwd=clone_dir, check=True, capture_output=True, text=True
94
118
  )
95
119
 
96
120
  # Copy the generated data directory to templates directory
@@ -140,6 +164,27 @@ def ensure_template_subdirs() -> None:
140
164
  logger.info("Templates directory is ready at: %s", MFS_TEMPLATES_DIR)
141
165
 
142
166
 
167
+ def reload_templates() -> None:
168
+ """Reload templates by removing existing files and re-preparing them.
169
+ Does not affect nested directories containing user data.
170
+ If needed, the files should be removed manually.
171
+ """
172
+ logger.info("Reloading templates...")
173
+ # Remove files from the templates directory.
174
+ # But do not remove nested directories, because they contain user data.
175
+ # Only remove files in the top-level templates directory.
176
+ for item in os.listdir(MFS_TEMPLATES_DIR):
177
+ item_path = os.path.join(MFS_TEMPLATES_DIR, item)
178
+ if os.path.isfile(item_path):
179
+ try:
180
+ os.remove(item_path)
181
+ except Exception as e:
182
+ logger.warning("Could not remove file %s: %s", item_path, str(e))
183
+ ensure_templates()
184
+ ensure_template_subdirs()
185
+ logger.info("Templates reloaded successfully.")
186
+
187
+
143
188
  ensure_templates()
144
189
  ensure_template_subdirs()
145
190
 
@@ -160,8 +205,31 @@ SAT_CACHE_DIR = os.path.join(MFS_CACHE_DIR, "sat")
160
205
 
161
206
  osmnx_cache = os.path.join(MFS_CACHE_DIR, "osmnx")
162
207
  osmnx_data = os.path.join(MFS_CACHE_DIR, "odata")
163
- os.makedirs(osmnx_cache, exist_ok=True)
164
- os.makedirs(osmnx_data, exist_ok=True)
208
+
209
+ CACHE_DIRS = [DTM_CACHE_DIR, SAT_CACHE_DIR, osmnx_cache, osmnx_data]
210
+
211
+
212
+ def create_cache_dirs() -> None:
213
+ """Create cache directories if they do not exist."""
214
+ logger.info("Ensuring cache directories exist...")
215
+ for cache_dir in CACHE_DIRS:
216
+ os.makedirs(cache_dir, exist_ok=True)
217
+ logger.debug("Cache directory ensured: %s", cache_dir)
218
+ logger.info("All cache directories are ready.")
219
+
220
+
221
+ def clean_cache() -> None:
222
+ """Clean all cache directories by removing and recreating them."""
223
+ logger.info("Cleaning cache directories...")
224
+ for cache_dir in CACHE_DIRS:
225
+ if os.path.exists(cache_dir):
226
+ shutil.rmtree(cache_dir)
227
+ logger.debug("Removed cache directory: %s", cache_dir)
228
+ create_cache_dirs()
229
+ logger.info("Cache directories cleaned and recreated.")
230
+
231
+
232
+ create_cache_dirs()
165
233
 
166
234
 
167
235
  ox_settings.cache_folder = osmnx_cache
maps4fs/generator/game.py CHANGED
@@ -5,12 +5,15 @@ template file and specific settings for map generation."""
5
5
  from __future__ import annotations
6
6
 
7
7
  import os
8
+ from typing import Callable
8
9
 
9
10
  import maps4fs.generator.config as mfscfg
10
11
  from maps4fs.generator.component.background import Background
12
+ from maps4fs.generator.component.building import Building
11
13
  from maps4fs.generator.component.config import Config
12
14
  from maps4fs.generator.component.grle import GRLE
13
15
  from maps4fs.generator.component.i3d import I3d
16
+ from maps4fs.generator.component.road import Road
14
17
  from maps4fs.generator.component.satellite import Satellite
15
18
  from maps4fs.generator.component.texture import Texture
16
19
 
@@ -37,6 +40,7 @@ class Game:
37
40
  _texture_schema_file: str | None = None
38
41
  _grle_schema_file: str | None = None
39
42
  _tree_schema_file: str | None = None
43
+ _buildings_schema_file: str | None = None
40
44
  _i3d_processing: bool = True
41
45
  _plants_processing: bool = True
42
46
  _environment_processing: bool = True
@@ -45,7 +49,7 @@ class Game:
45
49
  _mesh_processing: bool = True
46
50
 
47
51
  # Order matters! Some components depend on others.
48
- components = [Satellite, Texture, Background, GRLE, I3d, Config]
52
+ components = [Satellite, Texture, Background, GRLE, I3d, Config, Road, Building]
49
53
 
50
54
  def __init__(self, map_template_path: str | None = None):
51
55
  if map_template_path:
@@ -72,6 +76,11 @@ class Game:
72
76
  else:
73
77
  self._tree_schema = os.path.join(mfscfg.MFS_TEMPLATES_DIR, self._tree_schema_file) # type: ignore
74
78
 
79
+ if not self._buildings_schema_file:
80
+ self._buildings_schema_file = None
81
+ else:
82
+ self._buildings_schema_file = os.path.join(mfscfg.MFS_TEMPLATES_DIR, self._buildings_schema_file) # type: ignore
83
+
75
84
  def set_components_by_names(self, component_names: list[str]) -> None:
76
85
  """Sets the components used for map generation by their names.
77
86
 
@@ -159,6 +168,19 @@ class Game:
159
168
  raise ValueError("Tree layers schema path not set.")
160
169
  return self._tree_schema
161
170
 
171
+ @property
172
+ def buildings_schema(self) -> str:
173
+ """Returns the path to the buildings layers schema file.
174
+
175
+ Raises:
176
+ ValueError: If the buildings layers schema path is not set.
177
+
178
+ Returns:
179
+ str: The path to the buildings layers schema file."""
180
+ if not self._buildings_schema_file:
181
+ raise ValueError("Buildings layers schema path not set.")
182
+ return self._buildings_schema_file
183
+
162
184
  def dem_file_path(self, map_directory: str) -> str:
163
185
  """Returns the path to the DEM file.
164
186
 
@@ -166,8 +188,7 @@ class Game:
166
188
  map_directory (str): The path to the map directory.
167
189
 
168
190
  Returns:
169
- str: The path to the DEM file.
170
- """
191
+ str: The path to the DEM file."""
171
192
  raise NotImplementedError
172
193
 
173
194
  def weights_dir_path(self, map_directory: str) -> str:
@@ -341,6 +362,45 @@ class Game:
341
362
  bool: True if the mesh should be processed, False otherwise."""
342
363
  return self._mesh_processing
343
364
 
365
+ def validate_template(self, map_directory: str) -> None:
366
+ """Validates that all required files exist in the map template directory.
367
+
368
+ Arguments:
369
+ map_directory (str): The path to the map directory.
370
+
371
+ Raises:
372
+ FileNotFoundError: If any required files are missing from the template.
373
+ """
374
+ all_files = []
375
+ for root, _, files in os.walk(map_directory):
376
+ for file in files:
377
+ all_files.append(os.path.join(root, file))
378
+
379
+ missing_files = []
380
+ for func in self.required_file_methods():
381
+ try:
382
+ required_filepath = func(map_directory)
383
+ except NotImplementedError:
384
+ continue
385
+ if required_filepath not in all_files:
386
+ missing_files.append(required_filepath)
387
+ if missing_files:
388
+ raise FileNotFoundError(f"The following files are not found: {missing_files}.")
389
+
390
+ def required_file_methods(self) -> list[Callable[[str], str]]:
391
+ """Returns a list of methods that return paths to required files for map generation.
392
+
393
+ Returns:
394
+ list[Callable[[str], str]]: List of methods that take a map directory path
395
+ and return file paths that are required for the map template.
396
+ """
397
+ return [
398
+ self.map_xml_path,
399
+ self.i3d_file_path,
400
+ self.get_environment_xml_path,
401
+ self.get_farmlands_xml_path,
402
+ ]
403
+
344
404
 
345
405
  class FS22(Game):
346
406
  """Class used to define the game version FS22."""
@@ -396,6 +456,7 @@ class FS25(Game):
396
456
  _texture_schema_file = "fs25-texture-schema.json"
397
457
  _grle_schema_file = "fs25-grle-schema.json"
398
458
  _tree_schema_file = "fs25-tree-schema.json"
459
+ _buildings_schema_file = "fs25-buildings-schema.json"
399
460
 
400
461
  def dem_file_path(self, map_directory: str) -> str:
401
462
  """Returns the path to the DEM file.
maps4fs/generator/map.py CHANGED
@@ -105,6 +105,7 @@ class Map:
105
105
  self.i3d_settings = generation_settings.i3d_settings
106
106
  self.texture_settings = generation_settings.texture_settings
107
107
  self.satellite_settings = generation_settings.satellite_settings
108
+ self.building_settings = generation_settings.building_settings
108
109
  self.process_settings()
109
110
 
110
111
  self.logger = logger if logger else Logger()
@@ -123,11 +124,13 @@ class Map:
123
124
  os.makedirs(self.map_directory, exist_ok=True)
124
125
  self.texture_custom_schema = kwargs.get("texture_custom_schema", None)
125
126
  self.tree_custom_schema = kwargs.get("tree_custom_schema", None)
127
+ self.buildings_custom_schema = kwargs.get("buildings_custom_schema", None)
126
128
 
127
129
  json_data = {
128
130
  "generation_settings.json": generation_settings_json,
129
131
  "texture_custom_schema.json": self.texture_custom_schema,
130
132
  "tree_custom_schema.json": self.tree_custom_schema,
133
+ "buildings_custom_schema.json": self.buildings_custom_schema,
131
134
  }
132
135
 
133
136
  for filename, data in json_data.items():
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  from datetime import datetime
7
- from typing import TYPE_CHECKING, Any, NamedTuple
7
+ from typing import TYPE_CHECKING, Any, Literal, NamedTuple
8
8
 
9
9
  from pydantic import BaseModel, ConfigDict
10
10
 
@@ -279,6 +279,21 @@ class SatelliteSettings(SettingsModel):
279
279
  zoom_level: int = 16
280
280
 
281
281
 
282
+ class BuildingSettings(SettingsModel):
283
+ """Represents the advanced settings for building component.
284
+
285
+ Attributes:
286
+ generate_buildings (bool): generate buildings on the map.
287
+ region (Literal["auto", "all", "EU", "US"]): region for the buildings.
288
+ tolerance_factor (float): tolerance factor representing allowed dimension difference
289
+ between OSM building footprint and the building model footprint.
290
+ """
291
+
292
+ generate_buildings: bool = True
293
+ region: Literal["auto", "all", "EU", "US"] = "auto"
294
+ tolerance_factor: float = 0.3
295
+
296
+
282
297
  class GenerationSettings(BaseModel):
283
298
  """Represents the settings for the map generation process."""
284
299
 
@@ -288,6 +303,7 @@ class GenerationSettings(BaseModel):
288
303
  i3d_settings: I3DSettings = I3DSettings()
289
304
  texture_settings: TextureSettings = TextureSettings()
290
305
  satellite_settings: SatelliteSettings = SatelliteSettings()
306
+ building_settings: BuildingSettings = BuildingSettings()
291
307
 
292
308
  def to_json(self) -> dict[str, Any]:
293
309
  """Convert the GenerationSettings instance to JSON format.
@@ -302,6 +318,7 @@ class GenerationSettings(BaseModel):
302
318
  "I3DSettings": self.i3d_settings.model_dump(),
303
319
  "TextureSettings": self.texture_settings.model_dump(),
304
320
  "SatelliteSettings": self.satellite_settings.model_dump(),
321
+ "BuildingSettings": self.building_settings.model_dump(),
305
322
  }
306
323
 
307
324
  @classmethod
@@ -4,7 +4,7 @@ import json
4
4
  import os
5
5
  import shutil
6
6
  from datetime import datetime
7
- from typing import Any
7
+ from typing import Any, Literal
8
8
  from xml.etree import ElementTree as ET
9
9
 
10
10
  import osmnx as ox
@@ -122,6 +122,20 @@ def get_country_by_coordinates(coordinates: tuple[float, float]) -> str:
122
122
  return "Unknown"
123
123
 
124
124
 
125
+ def get_region_by_coordinates(coordinates: tuple[float, float]) -> Literal["EU", "US"]:
126
+ """Get region (EU or US) by coordinates.
127
+
128
+ Arguments:
129
+ coordinates (tuple[float, float]): Latitude and longitude.
130
+
131
+ Returns:
132
+ Literal["EU", "US"]: Region code.
133
+ """
134
+ country = get_country_by_coordinates(coordinates)
135
+ # If country is not US, assume EU for simplicity.
136
+ return "US" if country == "United States" else "EU"
137
+
138
+
125
139
  def get_timestamp() -> str:
126
140
  """Get current underscore-separated timestamp.
127
141
 
@@ -1,15 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maps4fs
3
- Version: 2.9.2
3
+ Version: 2.9.37
4
4
  Summary: Generate map templates for Farming Simulator from real places.
5
5
  Author-email: iwatkot <iwatkot@gmail.com>
6
- License: GNU Affero General Public License v3.0
6
+ License-Expression: CC-BY-NC-4.0
7
7
  Project-URL: Homepage, https://github.com/iwatkot/maps4fs
8
8
  Project-URL: Repository, https://github.com/iwatkot/maps4fs
9
9
  Keywords: farmingsimulator,fs,farmingsimulator22,farmingsimulator25,fs22,fs25
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
- Classifier: License :: OSI Approved :: GNU Affero General Public License v3
13
12
  Classifier: Operating System :: OS Independent
14
13
  Description-Content-Type: text/markdown
15
14
  License-File: LICENSE.md
@@ -76,6 +75,7 @@ Dynamic: license-file
76
75
  🚜 **Farming Simulator 22 & 25** - Generate maps for both game versions<br>
77
76
  🗺️ **Flexible Map Sizes** - 2x2, 4x4, 8x8, 16x16 km + custom sizes<br>
78
77
  ✂️ **Map Scaling & Rotation** - Perfect positioning and sizing control<br>
78
+ 🏘️ **Adding buildings** - Automatic building placement system<br>
79
79
 
80
80
  🌍 **Real-World Foundation** - Built from OpenStreetMap and satellite data<br>
81
81
  🏞️ **Accurate Terrain** - SRTM elevation data with custom DTM support<br>
@@ -86,7 +86,9 @@ Dynamic: license-file
86
86
  🌲 **Natural Forests** - Tree placement with customizable density<br>
87
87
  🌊 **Water Systems** - Rivers, lakes, and water planes<br>
88
88
  🌿 **Decorative Foliage** - Realistic vegetation and grass areas<br>
89
+ 🏘️ **Intelligent Building Placement** - Automatic building placement in appropriate areas<br>
89
90
 
91
+ 🚧 **3D Road Generation** - Automatic road mesh creation with custom textures<br>
90
92
  🚧 **Complete Spline Networks** - Roads and infrastructure<br>
91
93
  🔷 **Background Terrain** - 3D *.obj files for surrounding landscape<br>
92
94
  📦 **Giants Editor Ready** - Import and start building immediately<br>
@@ -96,7 +98,7 @@ Dynamic: license-file
96
98
  📚 **Complete Documentation** - [Detailed guides](https://maps4fs.gitbook.io/docs) and video tutorials<br>
97
99
 
98
100
  <p align="center">
99
- <img src="https://github.com/iwatkot/maps4fsui/releases/download/0.0.2/mfstr.gif"><br>
101
+ <img src="https://github.com/iwatkot/maps4fs/releases/download/2.9.34/mfsg.gif"><br>
100
102
  <i>Example of map generated with Maps4FS with no manual edits.</i>
101
103
  </p>
102
104
 
@@ -0,0 +1,32 @@
1
+ maps4fs/__init__.py,sha256=5ixsCA5vgcIV0OrF9EJBm91Mmc_KfMiDRM-QyifMAvo,386
2
+ maps4fs/logger.py,sha256=aZAa9glzgvH6ySVDLelSPTwHfWZtpGK5YBl-ufNUsPg,801
3
+ maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
4
+ maps4fs/generator/config.py,sha256=o_zRT8Nauy1djELsC867yD7GTs1fwz1OtZ2jE4w_7Ts,9797
5
+ maps4fs/generator/game.py,sha256=B7-a9gEBIOKAmC2eAAnEx65Ghx6U-edvNvU4a3WmjIw,18513
6
+ maps4fs/generator/map.py,sha256=kkyMETKteFhnWRgmcR8gjdNBQy4roQzcdlFw1nE5chE,16116
7
+ maps4fs/generator/monitor.py,sha256=Yrc7rClpmJK53SRzrOYZNBlwJmb5l6TkW-laFbyBEno,3524
8
+ maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
9
+ maps4fs/generator/settings.py,sha256=jrrIILNRtIpj7hpLrQqLTIagTY8tdJlLZDEN1M4n3Yc,14116
10
+ maps4fs/generator/statistics.py,sha256=ol0MTiehcCbQFfyYA7cKU-M4_cjiLCktnGbid4GYABU,2641
11
+ maps4fs/generator/utils.py,sha256=qaHmS5I30OhDwd213bbctlplQQlX-qkHugyszXGmh0U,5587
12
+ maps4fs/generator/component/__init__.py,sha256=s01yVVVi8R2xxNvflu2D6wTd9I_g73AMM2x7vAC7GX4,490
13
+ maps4fs/generator/component/background.py,sha256=3nzrIENqHVJiZzICqtMdgD-QbGS9125IeTCvO60y7jI,50155
14
+ maps4fs/generator/component/building.py,sha256=VoLjj6mDT-4kVfwxXP-lD0r4vJVYszyWZtciVFwdkIk,27402
15
+ maps4fs/generator/component/config.py,sha256=tI2RQaGIqBgJIi9KjYfMZZ8AWg_YVUm6KKsBHGV241g,31285
16
+ maps4fs/generator/component/dem.py,sha256=vMVJtU2jAS-2lfB9JsqodZsrUvY1h5xr3Dh5qk6txwk,11895
17
+ maps4fs/generator/component/grle.py,sha256=FAcGmG7yq0icOElRoO4QMsVisZMsNrLhfNSWvGKnOHg,29899
18
+ maps4fs/generator/component/i3d.py,sha256=idOixc2UF6RSvQud9GCWmMuTcY1qKVuzijUHakSzWks,28952
19
+ maps4fs/generator/component/layer.py,sha256=-pnKPlZFmsU-OmvG7EX-Nb55eETY0NTiYnnkCIRJuvY,7731
20
+ maps4fs/generator/component/road.py,sha256=YHX3-GcRXEyy9UG5KpUwC75n0FEIysn9PJnC7-tiwkw,27850
21
+ maps4fs/generator/component/satellite.py,sha256=1bPqd8JqAPqU0tEI9m-iuljMW9hXqlaCIxvq7kdpMY0,5219
22
+ maps4fs/generator/component/texture.py,sha256=46eG1EUWqDEppdxkimgu_gCBcNf2KqvZXfkak3GO8EI,38584
23
+ maps4fs/generator/component/base/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
24
+ maps4fs/generator/component/base/component.py,sha256=-7H3donrH19f0_rivNyI3fgLsiZkntXfGywEx4tOnM4,23924
25
+ maps4fs/generator/component/base/component_image.py,sha256=GXFkEFARNRkWkDiGSjvU4WX6f_8s6R1t2ZYqZflv1jk,9626
26
+ maps4fs/generator/component/base/component_mesh.py,sha256=2wGe_-wAZVRljMKzzVJ8jdzIETWg7LjxGj8A3inH5eI,25550
27
+ maps4fs/generator/component/base/component_xml.py,sha256=MT-VhU2dEckLFxAgmxg6V3gnv11di_94Qq6atfpOLdc,5342
28
+ maps4fs-2.9.37.dist-info/licenses/LICENSE.md,sha256=LzOB2xtN1AlHJi4hqoEsBlYLfmfRyXCPC2417miYoBc,19579
29
+ maps4fs-2.9.37.dist-info/METADATA,sha256=rJbXUF1gfOOgila4vS8faBTPMkZSKX0bxCxotgQl940,10204
30
+ maps4fs-2.9.37.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ maps4fs-2.9.37.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
32
+ maps4fs-2.9.37.dist-info/RECORD,,