maps4fs 1.9.2__py3-none-any.whl → 1.9.4__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.
- maps4fs/generator/component/background.py +11 -2
- maps4fs/generator/component/base/component.py +12 -0
- maps4fs/generator/component/base/component_xml.py +1 -1
- maps4fs/generator/component/config.py +1 -1
- maps4fs/generator/component/grle.py +6 -1
- maps4fs/generator/component/i3d.py +16 -10
- maps4fs/generator/component/satellite.py +4 -0
- maps4fs/generator/component/texture.py +4 -1
- maps4fs/generator/game.py +8 -0
- maps4fs/generator/map.py +3 -3
- maps4fs/generator/settings.py +7 -0
- maps4fs/logger.py +1 -19
- maps4fs/toolbox/background.py +9 -0
- maps4fs/toolbox/custom_osm.py +15 -0
- maps4fs/toolbox/dem.py +19 -0
- {maps4fs-1.9.2.dist-info → maps4fs-1.9.4.dist-info}/METADATA +20 -39
- {maps4fs-1.9.2.dist-info → maps4fs-1.9.4.dist-info}/RECORD +20 -20
- {maps4fs-1.9.2.dist-info → maps4fs-1.9.4.dist-info}/WHEEL +1 -1
- {maps4fs-1.9.2.dist-info → maps4fs-1.9.4.dist-info}/licenses/LICENSE.md +0 -0
- {maps4fs-1.9.2.dist-info → maps4fs-1.9.4.dist-info}/top_level.txt +0 -0
@@ -224,6 +224,8 @@ class Background(MeshComponent, ImageComponent):
|
|
224
224
|
save_path = os.path.join(self.background_directory, f"{filename}.obj")
|
225
225
|
self.logger.debug("Generating obj file in path: %s", save_path)
|
226
226
|
|
227
|
+
self.assets.background_mesh = save_path
|
228
|
+
|
227
229
|
dem_data = cv2.imread(self.output_path, cv2.IMREAD_UNCHANGED)
|
228
230
|
|
229
231
|
if self.map.output_size is not None:
|
@@ -279,6 +281,8 @@ class Background(MeshComponent, ImageComponent):
|
|
279
281
|
cv2.imwrite(main_dem_path, resized_dem_data)
|
280
282
|
self.logger.debug("DEM cutout saved: %s", main_dem_path)
|
281
283
|
|
284
|
+
self.assets.dem = main_dem_path
|
285
|
+
|
282
286
|
return main_dem_path
|
283
287
|
|
284
288
|
def plane_from_np(
|
@@ -321,8 +325,11 @@ class Background(MeshComponent, ImageComponent):
|
|
321
325
|
self.logger.debug("Obj file saved: %s", save_path)
|
322
326
|
|
323
327
|
if create_preview:
|
324
|
-
|
325
|
-
|
328
|
+
try:
|
329
|
+
mesh.apply_scale([0.5, 0.5, 0.5])
|
330
|
+
self.mesh_to_stl(mesh, save_path=self.stl_preview_path)
|
331
|
+
except Exception as e:
|
332
|
+
self.logger.error("Could not create STL preview: %s", e)
|
326
333
|
|
327
334
|
def update_mesh_info(self, save_path: str, mesh: Trimesh) -> None:
|
328
335
|
"""Updates the mesh info with the data from the mesh.
|
@@ -587,4 +594,6 @@ class Background(MeshComponent, ImageComponent):
|
|
587
594
|
elevated_water = np.where(mask, background_dem, elevated_water)
|
588
595
|
elevated_save_path = os.path.join(self.water_directory, "elevated_water.obj")
|
589
596
|
|
597
|
+
self.assets.water_mesh = elevated_save_path
|
598
|
+
|
590
599
|
self.plane_from_np(elevated_water, elevated_save_path, include_zeros=False)
|
@@ -20,6 +20,16 @@ if TYPE_CHECKING:
|
|
20
20
|
from maps4fs.generator.map import Map
|
21
21
|
|
22
22
|
|
23
|
+
class AttrDict(dict):
|
24
|
+
"""A dictionary that allows attribute-style access to its keys."""
|
25
|
+
|
26
|
+
def __getattr__(self, name):
|
27
|
+
return self[name]
|
28
|
+
|
29
|
+
def __setattr__(self, name, value):
|
30
|
+
self[name] = value
|
31
|
+
|
32
|
+
|
23
33
|
class Component:
|
24
34
|
"""Base class for all map generation components.
|
25
35
|
|
@@ -72,6 +82,8 @@ class Component:
|
|
72
82
|
self.save_bbox()
|
73
83
|
self.preprocess()
|
74
84
|
|
85
|
+
self.assets = AttrDict()
|
86
|
+
|
75
87
|
def preprocess(self) -> None:
|
76
88
|
"""Prepares the component for processing. Must be implemented in the child class."""
|
77
89
|
return
|
@@ -35,7 +35,7 @@ class XMLComponent(Component):
|
|
35
35
|
if not os.path.isfile(xml_path):
|
36
36
|
raise FileNotFoundError(f"XML file {xml_path} does not exist.")
|
37
37
|
|
38
|
-
return ET.parse(xml_path)
|
38
|
+
return ET.parse(xml_path) # type: ignore
|
39
39
|
|
40
40
|
def save_tree(self, tree: ET.ElementTree, xml_path: str | None = None) -> None:
|
41
41
|
"""Saves the XML tree to the file.
|
@@ -204,7 +204,7 @@ class GRLE(ImageComponent, XMLComponent):
|
|
204
204
|
|
205
205
|
tree = self.get_tree()
|
206
206
|
root = tree.getroot()
|
207
|
-
farmlands_node = root.find("farmlands")
|
207
|
+
farmlands_node = root.find("farmlands") # type: ignore
|
208
208
|
if farmlands_node is None:
|
209
209
|
raise ValueError("Farmlands XML element not found in the farmlands XML file.")
|
210
210
|
|
@@ -263,6 +263,8 @@ class GRLE(ImageComponent, XMLComponent):
|
|
263
263
|
|
264
264
|
cv2.imwrite(info_layer_farmlands_path, image)
|
265
265
|
|
266
|
+
self.assets.farmlands = info_layer_farmlands_path
|
267
|
+
|
266
268
|
self.preview_paths["farmlands"] = info_layer_farmlands_path
|
267
269
|
|
268
270
|
def _add_plants(self) -> None:
|
@@ -362,6 +364,9 @@ class GRLE(ImageComponent, XMLComponent):
|
|
362
364
|
# Ensure that order of channels is correct because CV2 uses BGR and we need RGB.
|
363
365
|
density_map_fruits = cv2.cvtColor(density_map_fruits, cv2.COLOR_BGR2RGB)
|
364
366
|
cv2.imwrite(density_map_fruit_path, density_map_fruits)
|
367
|
+
|
368
|
+
self.assets.plants = density_map_fruit_path
|
369
|
+
|
365
370
|
self.logger.debug("Updated density map for fruits saved in %s.", density_map_fruit_path)
|
366
371
|
|
367
372
|
def create_island_of_plants(self, image: np.ndarray, count: int) -> np.ndarray:
|
@@ -85,8 +85,8 @@ class I3d(XMLComponent):
|
|
85
85
|
|
86
86
|
data = {"heightScale": str(value)}
|
87
87
|
|
88
|
-
self.get_and_update_element(root, path, data)
|
89
|
-
self.save_tree(tree)
|
88
|
+
self.get_and_update_element(root, path, data) # type: ignore
|
89
|
+
self.save_tree(tree) # type: ignore
|
90
90
|
|
91
91
|
def _update_parameters(self) -> None:
|
92
92
|
"""Updates the map I3D file with the sun bounding box and displacement layer size."""
|
@@ -101,11 +101,11 @@ class I3d(XMLComponent):
|
|
101
101
|
"lastShadowMapSplitBboxMax": f"{distance},148,{distance}",
|
102
102
|
}
|
103
103
|
|
104
|
-
self.get_and_update_element(root, sun_element_path, data)
|
104
|
+
self.get_and_update_element(root, sun_element_path, data) # type: ignore
|
105
105
|
|
106
106
|
displacement_layer_path = ".//Scene/TerrainTransformGroup/Layers/DisplacementLayer"
|
107
107
|
data = {"size": str(int(self.map_size * 8))}
|
108
|
-
self.get_and_update_element(root, displacement_layer_path, data)
|
108
|
+
self.get_and_update_element(root, displacement_layer_path, data) # type: ignore
|
109
109
|
|
110
110
|
self.save_tree(tree)
|
111
111
|
|
@@ -125,9 +125,9 @@ class I3d(XMLComponent):
|
|
125
125
|
|
126
126
|
root = tree.getroot()
|
127
127
|
# Find <Shapes> element in the I3D file.
|
128
|
-
shapes_node = root.find(".//Shapes")
|
128
|
+
shapes_node = root.find(".//Shapes") # type: ignore
|
129
129
|
# Find <Scene> element in the I3D file.
|
130
|
-
scene_node = root.find(".//Scene")
|
130
|
+
scene_node = root.find(".//Scene") # type: ignore
|
131
131
|
|
132
132
|
if shapes_node is None or scene_node is None:
|
133
133
|
self.logger.warning("Shapes or Scene node not found in I3D file.")
|
@@ -145,7 +145,7 @@ class I3d(XMLComponent):
|
|
145
145
|
interpolation=cv2.INTER_NEAREST,
|
146
146
|
)
|
147
147
|
|
148
|
-
user_attributes_node = root.find(".//UserAttributes")
|
148
|
+
user_attributes_node = root.find(".//UserAttributes") # type: ignore
|
149
149
|
if user_attributes_node is None:
|
150
150
|
self.logger.warning("UserAttributes node not found in I3D file.")
|
151
151
|
return
|
@@ -222,6 +222,8 @@ class I3d(XMLComponent):
|
|
222
222
|
tree.write(splines_i3d_path) # type: ignore
|
223
223
|
self.logger.debug("Splines I3D file saved to: %s.", splines_i3d_path)
|
224
224
|
|
225
|
+
self.assets.splines = splines_i3d_path
|
226
|
+
|
225
227
|
def _add_fields(self) -> None:
|
226
228
|
"""Adds fields to the map I3D file."""
|
227
229
|
tree = self.get_tree()
|
@@ -240,12 +242,12 @@ class I3d(XMLComponent):
|
|
240
242
|
self.logger.debug("Starging to add fields to the I3D file.")
|
241
243
|
|
242
244
|
root = tree.getroot()
|
243
|
-
gameplay_node = root.find(".//TransformGroup[@name='gameplay']")
|
245
|
+
gameplay_node = root.find(".//TransformGroup[@name='gameplay']") # type: ignore
|
244
246
|
|
245
247
|
if gameplay_node is None:
|
246
248
|
return
|
247
249
|
fields_node = gameplay_node.find(".//TransformGroup[@name='fields']")
|
248
|
-
user_attributes_node = root.find(".//UserAttributes")
|
250
|
+
user_attributes_node = root.find(".//UserAttributes") # type: ignore
|
249
251
|
|
250
252
|
if fields_node is None or user_attributes_node is None:
|
251
253
|
return
|
@@ -285,6 +287,8 @@ class I3d(XMLComponent):
|
|
285
287
|
|
286
288
|
self.save_tree(tree)
|
287
289
|
|
290
|
+
self.assets.fields = self.xml_path
|
291
|
+
|
288
292
|
def _get_field_xml_entry(
|
289
293
|
self, field_id: int, field_ccs: list[tuple[int, int]], node_id: int
|
290
294
|
) -> tuple[ET.Element, int] | tuple[None, int]:
|
@@ -497,7 +501,7 @@ class I3d(XMLComponent):
|
|
497
501
|
|
498
502
|
tree = self.get_tree()
|
499
503
|
root = tree.getroot()
|
500
|
-
scene_node = root.find(".//Scene")
|
504
|
+
scene_node = root.find(".//Scene") # type: ignore
|
501
505
|
if scene_node is None:
|
502
506
|
self.logger.warning("Scene element not found in I3D file.")
|
503
507
|
return
|
@@ -559,6 +563,8 @@ class I3d(XMLComponent):
|
|
559
563
|
scene_node.append(trees_node)
|
560
564
|
self.save_tree(tree)
|
561
565
|
|
566
|
+
self.assets.forests = self.xml_path
|
567
|
+
|
562
568
|
@staticmethod
|
563
569
|
def randomize_coordinates(
|
564
570
|
coordinates: tuple[int, int], density: int, shift_percent: int
|
@@ -59,9 +59,13 @@ class Satellite(ImageComponent):
|
|
59
59
|
overview_size = (self.map_size + margin) * 2
|
60
60
|
overwiew_path = os.path.join(self.satellite_directory, "satellite_overview.png")
|
61
61
|
|
62
|
+
self.assets.overview = overwiew_path
|
63
|
+
|
62
64
|
background_size = self.map_size + (Parameters.BACKGROUND_DISTANCE + margin) * 2
|
63
65
|
background_path = os.path.join(self.satellite_directory, "satellite_background.png")
|
64
66
|
|
67
|
+
self.assets.background = background_path
|
68
|
+
|
65
69
|
sizes = [overview_size, background_size]
|
66
70
|
self.image_paths = [overwiew_path, background_path]
|
67
71
|
|
@@ -149,6 +149,9 @@ class Texture(ImageComponent):
|
|
149
149
|
self.dissolve()
|
150
150
|
self.copy_procedural()
|
151
151
|
|
152
|
+
for layer in self.layers:
|
153
|
+
self.assets[layer.name] = layer.path(self._weights_dir)
|
154
|
+
|
152
155
|
def add_borders(self) -> None:
|
153
156
|
"""Iterates over all the layers and picks the one which have the border propety defined.
|
154
157
|
Borders are distance from the edge of the map on each side (top, right, bottom, left).
|
@@ -504,7 +507,7 @@ class Texture(ImageComponent):
|
|
504
507
|
|
505
508
|
# Randomly assign non-zero values to sublayers.
|
506
509
|
for coord in non_zero_coords:
|
507
|
-
sublayers[np.random.randint(0, layer.count)][coord[0], coord[1]] = 255
|
510
|
+
sublayers[np.random.randint(0, layer.count)][coord[0], coord[1]] = 255 # type: ignore
|
508
511
|
|
509
512
|
# Save the sublayers.
|
510
513
|
for sublayer, sublayer_path in zip(sublayers, layer_paths):
|
maps4fs/generator/game.py
CHANGED
@@ -49,6 +49,14 @@ class Game:
|
|
49
49
|
if map_template_path:
|
50
50
|
self._map_template_path = map_template_path
|
51
51
|
|
52
|
+
def set_components_by_names(self, component_names: list[str]) -> None:
|
53
|
+
"""Sets the components used for map generation by their names.
|
54
|
+
|
55
|
+
Arguments:
|
56
|
+
component_names (list[str]): List of component names to be used.
|
57
|
+
"""
|
58
|
+
self.components = [comp for comp in self.components if comp.__name__ in component_names]
|
59
|
+
|
52
60
|
def map_xml_path(self, map_directory: str) -> str:
|
53
61
|
"""Returns the path to the map.xml file.
|
54
62
|
|
maps4fs/generator/map.py
CHANGED
@@ -58,7 +58,7 @@ class Map:
|
|
58
58
|
**kwargs,
|
59
59
|
):
|
60
60
|
if not logger:
|
61
|
-
logger = Logger(
|
61
|
+
logger = Logger()
|
62
62
|
self.logger = logger
|
63
63
|
self.size = size
|
64
64
|
|
@@ -226,8 +226,8 @@ class Map:
|
|
226
226
|
self.rotation,
|
227
227
|
self.map_directory,
|
228
228
|
self.logger,
|
229
|
-
texture_custom_schema=self.texture_custom_schema,
|
230
|
-
tree_custom_schema=self.tree_custom_schema,
|
229
|
+
texture_custom_schema=self.texture_custom_schema, # type: ignore
|
230
|
+
tree_custom_schema=self.tree_custom_schema, # type: ignore
|
231
231
|
)
|
232
232
|
self.components.append(component)
|
233
233
|
|
maps4fs/generator/settings.py
CHANGED
@@ -145,6 +145,13 @@ class BackgroundSettings(SettingsModel):
|
|
145
145
|
generate_water (bool): generate obj files for the water.
|
146
146
|
resize_factor (int): resize factor for the background terrain and water.
|
147
147
|
It will be used as 1 / resize_factor of the original size.
|
148
|
+
water_blurriness (int): blurriness of the water.
|
149
|
+
remove_center (bool): remove the center of the background terrain.
|
150
|
+
It will be used to remove the center of the map where the player starts.
|
151
|
+
apply_decimation (bool): apply decimation to the background terrain.
|
152
|
+
decimation_percent (int): percentage of the decimation.
|
153
|
+
decimation_agression (int): agression of the decimation.
|
154
|
+
It will be used to control the amount of decimation applied to the background terrain.
|
148
155
|
"""
|
149
156
|
|
150
157
|
generate_background: bool = False
|
maps4fs/logger.py
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
import logging
|
4
4
|
import os
|
5
5
|
import sys
|
6
|
-
from datetime import datetime
|
7
6
|
from typing import Literal
|
8
7
|
|
9
8
|
LOGGER_NAME = "maps4fs"
|
@@ -12,35 +11,18 @@ os.makedirs(log_directory, exist_ok=True)
|
|
12
11
|
|
13
12
|
|
14
13
|
class Logger(logging.Logger):
|
15
|
-
"""Handles logging to
|
14
|
+
"""Handles logging to stdout with timestamps."""
|
16
15
|
|
17
16
|
def __init__(
|
18
17
|
self,
|
19
18
|
level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO",
|
20
19
|
to_stdout: bool = True,
|
21
|
-
to_file: bool = True,
|
22
20
|
):
|
23
21
|
super().__init__(LOGGER_NAME)
|
24
22
|
self.setLevel(level)
|
25
23
|
self.stdout_handler = logging.StreamHandler(sys.stdout)
|
26
|
-
self.file_handler = logging.FileHandler(
|
27
|
-
filename=self.log_file(), mode="a", encoding="utf-8"
|
28
|
-
)
|
29
24
|
formatter = "%(name)s | %(levelname)s | %(asctime)s | %(message)s"
|
30
25
|
self.fmt = formatter
|
31
26
|
self.stdout_handler.setFormatter(logging.Formatter(formatter))
|
32
|
-
self.file_handler.setFormatter(logging.Formatter(formatter))
|
33
27
|
if to_stdout:
|
34
28
|
self.addHandler(self.stdout_handler)
|
35
|
-
if to_file:
|
36
|
-
self.addHandler(self.file_handler)
|
37
|
-
|
38
|
-
def log_file(self) -> str:
|
39
|
-
"""Returns the path to the log file.
|
40
|
-
|
41
|
-
Returns:
|
42
|
-
str: The path to the log file.
|
43
|
-
"""
|
44
|
-
today = datetime.now().strftime("%Y-%m-%d")
|
45
|
-
log_file = os.path.join(log_directory, f"{today}.txt")
|
46
|
-
return log_file
|
maps4fs/toolbox/background.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
"""This module contains functions to work with the background terrain of the map."""
|
2
2
|
|
3
|
+
import warnings
|
4
|
+
|
3
5
|
import cv2
|
4
6
|
import numpy as np
|
5
7
|
import trimesh # type: ignore
|
@@ -22,6 +24,13 @@ def plane_from_np(
|
|
22
24
|
will result in a simpler mesh.
|
23
25
|
save_path (str) -- The path to save the obj file.
|
24
26
|
"""
|
27
|
+
warnings.warn(
|
28
|
+
"The 'plane_from_np' function is deprecated and will be removed in maps4fs 2.0. "
|
29
|
+
"Use 'trimesh' directly instead or maps4fs.generator.component.base.component_mesh."
|
30
|
+
"MeshComponent.mesh_from_np' instead.",
|
31
|
+
DeprecationWarning,
|
32
|
+
stacklevel=2,
|
33
|
+
)
|
25
34
|
dem_data = cv2.resize(dem_data, (0, 0), fx=resize_factor, fy=resize_factor)
|
26
35
|
|
27
36
|
# Invert the height values.
|
maps4fs/toolbox/custom_osm.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""This module contains functions to work with custom OSM files."""
|
2
2
|
|
3
3
|
import json
|
4
|
+
import warnings
|
4
5
|
from xml.etree import ElementTree as ET
|
5
6
|
|
6
7
|
import osmnx as ox
|
@@ -19,6 +20,13 @@ def check_osm_file(file_path: str) -> bool:
|
|
19
20
|
Returns:
|
20
21
|
bool: True if the file is valid, False otherwise.
|
21
22
|
"""
|
23
|
+
warnings.warn(
|
24
|
+
"The 'check_osm_file' function is deprecated and will be removed in maps4fs 2.0. "
|
25
|
+
"The feature will be directly integrated into the maps4fs generator. "
|
26
|
+
"And will not be available as a separate function.",
|
27
|
+
DeprecationWarning,
|
28
|
+
stacklevel=2,
|
29
|
+
)
|
22
30
|
with open(FS25().texture_schema, encoding="utf-8") as f:
|
23
31
|
schema = json.load(f)
|
24
32
|
|
@@ -50,6 +58,13 @@ def fix_osm_file(input_file_path: str, output_file_path: str) -> tuple[bool, int
|
|
50
58
|
tuple[bool, int]: A tuple containing the result of the check_osm_file function
|
51
59
|
and the number of fixed errors.
|
52
60
|
"""
|
61
|
+
warnings.warn(
|
62
|
+
"The 'fix_osm_file' function is deprecated and will be removed in maps4fs 2.0. "
|
63
|
+
"The feature will be directly integrated into the maps4fs generator. "
|
64
|
+
"And will not be available as a separate function.",
|
65
|
+
DeprecationWarning,
|
66
|
+
stacklevel=2,
|
67
|
+
)
|
53
68
|
broken_entries = ["relation", ".//*[@action='delete']"]
|
54
69
|
|
55
70
|
tree = ET.parse(input_file_path)
|
maps4fs/toolbox/dem.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""This module contains functions for working with Digital Elevation Models (DEMs)."""
|
2
2
|
|
3
3
|
import os
|
4
|
+
import warnings
|
4
5
|
|
5
6
|
import rasterio # type: ignore
|
6
7
|
from pyproj import Transformer
|
@@ -21,6 +22,12 @@ def read_geo_tiff(file_path: str) -> DatasetReader:
|
|
21
22
|
Returns:
|
22
23
|
DatasetReader: The DatasetReader object for the GeoTIFF file.
|
23
24
|
"""
|
25
|
+
warnings.warn(
|
26
|
+
"The 'read_geo_tiff' function is deprecated and will be removed in maps4fs 2.0. "
|
27
|
+
"Use 'rasterio.open' directly instead.",
|
28
|
+
DeprecationWarning,
|
29
|
+
stacklevel=2,
|
30
|
+
)
|
24
31
|
if not os.path.isfile(file_path):
|
25
32
|
raise FileNotFoundError(f"File not found: {file_path}")
|
26
33
|
|
@@ -51,6 +58,12 @@ def get_geo_tiff_bbox(
|
|
51
58
|
tuple[float, float, float, float]: The bounding box in the destination CRS
|
52
59
|
as (north, south, east, west).
|
53
60
|
"""
|
61
|
+
warnings.warn(
|
62
|
+
"The 'get_geo_tiff_bbox' function is deprecated and will be removed in maps4fs 2.0. "
|
63
|
+
"Use 'rasterio' methods directly instead.",
|
64
|
+
DeprecationWarning,
|
65
|
+
stacklevel=2,
|
66
|
+
)
|
54
67
|
left, bottom, right, top = src.bounds
|
55
68
|
|
56
69
|
transformer = Transformer.from_crs(src.crs, dst_crs, always_xy=True)
|
@@ -76,6 +89,12 @@ def extract_roi(file_path: str, bbox: tuple[float, float, float, float]) -> str:
|
|
76
89
|
Returns:
|
77
90
|
str: The path to the new GeoTIFF file containing the extracted ROI.
|
78
91
|
"""
|
92
|
+
warnings.warn(
|
93
|
+
"The 'extract_roi' function is deprecated and will be removed in maps4fs 2.0. "
|
94
|
+
"Use 'rasterio' methods directly instead.",
|
95
|
+
DeprecationWarning,
|
96
|
+
stacklevel=2,
|
97
|
+
)
|
79
98
|
with rasterio.open(file_path) as src:
|
80
99
|
transformer = Transformer.from_crs("EPSG:4326", src.crs, always_xy=True)
|
81
100
|
north, south, east, west = bbox
|
@@ -1,22 +1,21 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: maps4fs
|
3
|
-
Version: 1.9.
|
3
|
+
Version: 1.9.4
|
4
4
|
Summary: Generate map templates for Farming Simulator from real places.
|
5
5
|
Author-email: iwatkot <iwatkot@gmail.com>
|
6
|
-
License:
|
6
|
+
License: Apache License 2.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 ::
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
13
13
|
Classifier: Operating System :: OS Independent
|
14
14
|
Description-Content-Type: text/markdown
|
15
15
|
License-File: LICENSE.md
|
16
16
|
Requires-Dist: opencv-python
|
17
17
|
Requires-Dist: osmnx>=2.0.0
|
18
18
|
Requires-Dist: rasterio
|
19
|
-
Requires-Dist: folium
|
20
19
|
Requires-Dist: geopy
|
21
20
|
Requires-Dist: trimesh
|
22
21
|
Requires-Dist: imageio
|
@@ -29,6 +28,18 @@ Requires-Dist: tqdm
|
|
29
28
|
Requires-Dist: scipy
|
30
29
|
Dynamic: license-file
|
31
30
|
|
31
|
+
⚠️ Learn more about the upcoming 2.0 changes in the [migration guide](docs/migration.md).
|
32
|
+
⚠️ Some components are deprecated and there are major changes in the project structure.
|
33
|
+
|
34
|
+
|
35
|
+
<p align="center">
|
36
|
+
<a href="https://github.com/iwatkot/maps4fs">maps4fs</a> •
|
37
|
+
<a href="https://github.com/iwatkot/maps4fsui">maps4fs UI</a> •
|
38
|
+
<a href="https://github.com/iwatkot/maps4fsapi">maps4fs API</a> •
|
39
|
+
<a href="https://github.com/iwatkot/maps4fsstats">maps4fs Stats</a> •
|
40
|
+
<a href="https://github.com/iwatkot/maps4fsbot">maps4fs Bot</a>
|
41
|
+
</p>
|
42
|
+
|
32
43
|
<div align="center" markdown>
|
33
44
|
<a href="https://discord.gg/Sj5QKKyE42">
|
34
45
|
<img src="https://github.com/user-attachments/assets/37043333-d6ef-4ca3-9f3c-81323d9d0b71">
|
@@ -40,8 +51,8 @@ Dynamic: license-file
|
|
40
51
|
<a href="docs/step_by_step.md">Create a map in 10 steps</a> •
|
41
52
|
<a href="#How-To-Run">How-To-Run</a><br>
|
42
53
|
<a href="docs/FAQ.md">FAQ</a> •
|
43
|
-
<a href="docs/map_structure.md">Map Structure</a>
|
44
|
-
<a href="#
|
54
|
+
<a href="docs/map_structure.md">Map Structure</a> •
|
55
|
+
<a href="#Schemas-Editor">Schemas Editor</a> •
|
45
56
|
<a href="#Main-Settings">Main Settings</a><br>
|
46
57
|
<a href="#Supported-objects">Supported objects</a> •
|
47
58
|
<a href="#Generation-info">Generation info</a> •
|
@@ -69,7 +80,6 @@ Dynamic: license-file
|
|
69
80
|
[](https://github.com/iwatkot/maps4fs/actions)
|
70
81
|
[](https://codeclimate.com/github/iwatkot/maps4fs/test_coverage)
|
71
82
|
[](https://github.com/iwatkot/maps4fs/stargazers)<br>
|
72
|
-
[](https://github.com/iwatkot/maps4fs)
|
73
83
|
|
74
84
|
</div>
|
75
85
|
|
@@ -92,7 +102,6 @@ Dynamic: license-file
|
|
92
102
|
🔷 Generates \*.obj files for background terrain based on the real-world height map<br>
|
93
103
|
📄 Generates scripts to download high-resolution satellite images from [QGIS](https://qgis.org/download/) in one click<br>
|
94
104
|
📕 Detailed [documentation](/docs) and tutorials <br>
|
95
|
-
🧰 Modder Toolbox to help you with various tasks <br>
|
96
105
|
|
97
106
|
<p align="center">
|
98
107
|
<img src="https://github.com/user-attachments/assets/cf8f5752-9c69-4018-bead-290f59ba6976"><br>
|
@@ -146,7 +155,7 @@ There are several ways to use the tool. You obviously need the **first one**, bu
|
|
146
155
|
**Option 2:** Run the Docker version in your browser. Launch the following command in your terminal:
|
147
156
|
|
148
157
|
```bash
|
149
|
-
docker run -d -p 8501:8501 --name maps4fs iwatkot/maps4fs
|
158
|
+
docker run -d -p 8501:8501 -p 8000:8000 --name maps4fs iwatkot/maps4fs
|
150
159
|
```
|
151
160
|
|
152
161
|
And open [http://localhost:8501](http://localhost:8501) in your browser.<br>
|
@@ -228,21 +237,13 @@ You can launch the project with minimalistic UI in your browser using Docker. Fo
|
|
228
237
|
2. Run the following command in your terminal:
|
229
238
|
|
230
239
|
```bash
|
231
|
-
docker run -d -p 8501:8501 --name maps4fs iwatkot/maps4fs
|
240
|
+
docker run -d -p 8501:8501 -p 8000:8000 --name maps4fs iwatkot/maps4fs
|
232
241
|
```
|
233
242
|
|
234
243
|
3. Open your browser and go to [http://localhost:8501](http://localhost:8501).
|
235
244
|
4. Fill in the required fields and click on the `Generate` button.
|
236
245
|
5. When the map is generated click on the `Download` button to get the map.
|
237
246
|
|
238
|
-
➡️ If you don't need Blender backend, you can use the **lite** version of the Docker image.
|
239
|
-
|
240
|
-
```bash
|
241
|
-
docker run -d -p 8501:8501 --name maps4fs iwatkot/maps4fs:*.*.*_lite
|
242
|
-
```
|
243
|
-
|
244
|
-
Remember to replace `*.*.*` with the version you want to use, e.g. `iwatkot/maps4fs:1.8.202_lite`. Also, pay attention that some features will not work in the lite version, such as removing the center part of the background mesh.
|
245
|
-
|
246
247
|
### Option 3: Python package or source code
|
247
248
|
|
248
249
|
🔴 Recommended for developers.
|
@@ -326,32 +327,12 @@ The map will be saved in the `map_directory` directory.
|
|
326
327
|
|
327
328
|
➡️ Check out the [demo.py](demo.py) file for a complete example.
|
328
329
|
|
329
|
-
##
|
330
|
-
|
331
|
-
The tool now has a Modder Toolbox, which is a set of tools to help you with various tasks. You can open the toolbox by switching to the `🧰 Modder Toolbox` tab in the StreamLit app.<br>
|
332
|
-
|
333
|
-

|
334
|
-
|
335
|
-
### Tool Categories
|
336
|
-
|
337
|
-
Tools are divided into categories, which are listed below.
|
338
|
-
|
339
|
-
#### For custom schemas
|
330
|
+
## Schemas Editor
|
340
331
|
|
341
332
|
- **Tree Schema Editor** - allows you to view all the supported trees models and select the ones you need on your map. After it, you should click the Show updated schema button and copy the JSON schema to the clipboard. Then you can use it in the Expert settings to generate the map with the selected trees.
|
342
333
|
|
343
334
|
- **Texture Schema Editor** - allows you to view all the supported textures and edit their parameters, such as priority, OSM tags and so on. After editing, you should click the Show updated schema button and copy the JSON schema to the clipboard. Then you can use it in the Expert settings to generate the map with the updated textures.
|
344
335
|
|
345
|
-
#### For Textures and DEM
|
346
|
-
|
347
|
-
- **Fix custom OSM file** - this tool fixes the most common errors in the custom OSM file, but it can not guarantee that the file will be fixed completely if some non-common errors are present.
|
348
|
-
|
349
|
-
- **GeoTIFF windowing** - allows you to upload your GeoTIFF file and select the region of interest to extract it from the image. It's useful when you have high-resolution DEM data and want to create a height map using it.
|
350
|
-
|
351
|
-
#### For Background terrain
|
352
|
-
|
353
|
-
- **Convert image to obj model** - allows you to convert the image to the obj model. You can use this tool to create the background terrain for your map. It can be extremely useful if you have access to the sources of high-resolution DEM data and want to create the background terrain using it.
|
354
|
-
|
355
336
|
## Main Settings
|
356
337
|
|
357
338
|
### Game Selection
|
@@ -1,25 +1,25 @@
|
|
1
1
|
maps4fs/__init__.py,sha256=EGvLVoRpSt4jITswsGbe1ISVmGAZAMQJcBmTwtyuVxI,335
|
2
|
-
maps4fs/logger.py,sha256=
|
2
|
+
maps4fs/logger.py,sha256=WDfR14hxqy8b6xtwL6YIu2LGzFO1sbt0LxMgfsDTOkA,865
|
3
3
|
maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
4
|
-
maps4fs/generator/game.py,sha256=
|
5
|
-
maps4fs/generator/map.py,sha256=
|
4
|
+
maps4fs/generator/game.py,sha256=g8lMHuuRRmJLSDsQTAMv8p_-qntYMiZKnAqn7ru96i0,11645
|
5
|
+
maps4fs/generator/map.py,sha256=7-nx27M-VwTocPor8BCkkpthYBJYe_B-pe5_Dcsijaw,13899
|
6
6
|
maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
|
7
|
-
maps4fs/generator/settings.py,sha256=
|
7
|
+
maps4fs/generator/settings.py,sha256=E_M47X2QhbBqgiNraBDQd62lAQlNWHYLq30HQ59_4k4,7490
|
8
8
|
maps4fs/generator/statistics.py,sha256=aynS3zbAtiwnU_YLKHPTiiaKW98_suvQUhy1SGBA6mc,2448
|
9
9
|
maps4fs/generator/component/__init__.py,sha256=s01yVVVi8R2xxNvflu2D6wTd9I_g73AMM2x7vAC7GX4,490
|
10
|
-
maps4fs/generator/component/background.py,sha256=
|
11
|
-
maps4fs/generator/component/config.py,sha256=
|
10
|
+
maps4fs/generator/component/background.py,sha256=AfbgNUai3tvpMe8lYmfiaM1n51ssunECy4gRglihumU,24032
|
11
|
+
maps4fs/generator/component/config.py,sha256=IP530sapLofFskSnBEB96G0aUSd6Sno0G9ET3ca0ZOQ,3696
|
12
12
|
maps4fs/generator/component/dem.py,sha256=Bvm3ViA6PpR7RXRAHBj5rgYB9PWy55Qj6PhTMv6dJRI,11953
|
13
|
-
maps4fs/generator/component/grle.py,sha256=
|
14
|
-
maps4fs/generator/component/i3d.py,sha256=
|
13
|
+
maps4fs/generator/component/grle.py,sha256=ao3-4B4QUVl0XgOmYAj9L48KGaZtCZRTB1BqYgdAJIc,19613
|
14
|
+
maps4fs/generator/component/i3d.py,sha256=xTiZYQRahYBsVALxmnsBygzTHJLE54ucXvHK8LWCYAs,23914
|
15
15
|
maps4fs/generator/component/layer.py,sha256=-br4gAGcGeBNb3ldch9XFEK0lhXqb1IbArhFB5Owu54,6186
|
16
|
-
maps4fs/generator/component/satellite.py,sha256=
|
17
|
-
maps4fs/generator/component/texture.py,sha256=
|
16
|
+
maps4fs/generator/component/satellite.py,sha256=47V9aPbv7k-2C-PsoXd33EO92yavFzB6_MRCd7fLP6k,5042
|
17
|
+
maps4fs/generator/component/texture.py,sha256=Nc_oOHX3b4vJm8FnNOn3W4EQGFkW0zW0rGzO_0nTJMM,33392
|
18
18
|
maps4fs/generator/component/base/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
19
|
-
maps4fs/generator/component/base/component.py,sha256=
|
19
|
+
maps4fs/generator/component/base/component.py,sha256=HeNDaToKrS6OLeJepKZA7iQzZQDYy-9QRtv1A73Ire0,22090
|
20
20
|
maps4fs/generator/component/base/component_image.py,sha256=2NYJgCU8deHl7O2FYFYk38WKZVJygFoc2gjBXwH6vjM,5970
|
21
21
|
maps4fs/generator/component/base/component_mesh.py,sha256=BsxS5NlUK2hLhksgCwSoMK-00GNAwK2fYGpgb3R4n1w,9396
|
22
|
-
maps4fs/generator/component/base/component_xml.py,sha256=
|
22
|
+
maps4fs/generator/component/base/component_xml.py,sha256=V9pGUvHh6UF6BP0qFARqDq9vquoAgq1zJqhOgBoeS_Y,3983
|
23
23
|
maps4fs/generator/dtm/__init__.py,sha256=CzK8ZdLU5Iv7DrwK5hIQ41zVsLRFgZO-IuRxf-NCVqg,1516
|
24
24
|
maps4fs/generator/dtm/arctic.py,sha256=LSivLLjtd6TJUaPYvgSYQ4KalMTaY58zFvwivSh45uM,2587
|
25
25
|
maps4fs/generator/dtm/baden.py,sha256=PQTMEPm9hrO3nKbv_DXA9oNYnGK_0ei41Q_DhtethX0,1041
|
@@ -51,11 +51,11 @@ maps4fs/generator/dtm/utils.py,sha256=I-wUSA_J85Xbt8sZCZAVKHSIcrMj5Ng-0adtPVhVmk
|
|
51
51
|
maps4fs/generator/dtm/base/wcs.py,sha256=lQAp_gVz9_XUmtyobJkskiefQpuJH4o1Vwb3CSQ0lQA,2510
|
52
52
|
maps4fs/generator/dtm/base/wms.py,sha256=6Va2UMhg_s0TMOfMhxrPbsiAPiw6-vXBglnaij032I0,2264
|
53
53
|
maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
54
|
-
maps4fs/toolbox/background.py,sha256=
|
55
|
-
maps4fs/toolbox/custom_osm.py,sha256=
|
56
|
-
maps4fs/toolbox/dem.py,sha256=
|
57
|
-
maps4fs-1.9.
|
58
|
-
maps4fs-1.9.
|
59
|
-
maps4fs-1.9.
|
60
|
-
maps4fs-1.9.
|
61
|
-
maps4fs-1.9.
|
54
|
+
maps4fs/toolbox/background.py,sha256=RB0pHuRyfnDuqYtO2gUypfPm4G5cYRFdT2W-DG49zy0,2427
|
55
|
+
maps4fs/toolbox/custom_osm.py,sha256=fjVSl9Ztc8_q0DxgNkhM7tE0Y-XpX8xcGGW-Tunp0R8,2518
|
56
|
+
maps4fs/toolbox/dem.py,sha256=mbn3ZqMRhhYmzgssm2CGvg6aa89MUBOJPq6QyE54OLY,4191
|
57
|
+
maps4fs-1.9.4.dist-info/licenses/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
|
58
|
+
maps4fs-1.9.4.dist-info/METADATA,sha256=MXtYH5U2kDN-FzFipLbbHxgOCaZPkt-UFqF5H6rIQQM,49319
|
59
|
+
maps4fs-1.9.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
60
|
+
maps4fs-1.9.4.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
|
61
|
+
maps4fs-1.9.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|