maps4fs 1.6.3__py3-none-any.whl → 1.6.6__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.
Potentially problematic release.
This version of maps4fs might be problematic. Click here for more details.
- maps4fs/generator/background.py +81 -5
- maps4fs/generator/grle.py +2 -2
- maps4fs/generator/i3d.py +2 -2
- maps4fs/generator/map.py +16 -0
- maps4fs/generator/settings.py +8 -0
- maps4fs/generator/texture.py +55 -2
- {maps4fs-1.6.3.dist-info → maps4fs-1.6.6.dist-info}/METADATA +17 -8
- {maps4fs-1.6.3.dist-info → maps4fs-1.6.6.dist-info}/RECORD +11 -11
- {maps4fs-1.6.3.dist-info → maps4fs-1.6.6.dist-info}/LICENSE.md +0 -0
- {maps4fs-1.6.3.dist-info → maps4fs-1.6.6.dist-info}/WHEEL +0 -0
- {maps4fs-1.6.3.dist-info → maps4fs-1.6.6.dist-info}/top_level.txt +0 -0
maps4fs/generator/background.py
CHANGED
@@ -58,6 +58,10 @@ class Background(Component):
|
|
58
58
|
os.makedirs(self.water_directory, exist_ok=True)
|
59
59
|
|
60
60
|
self.output_path = os.path.join(self.background_directory, f"{FULL_NAME}.png")
|
61
|
+
if self.map.custom_background_path:
|
62
|
+
self.check_custom_background(self.map.custom_background_path)
|
63
|
+
shutil.copyfile(self.map.custom_background_path, self.output_path)
|
64
|
+
|
61
65
|
self.not_substracted_path = os.path.join(self.background_directory, "not_substracted.png")
|
62
66
|
self.not_resized_path = os.path.join(self.background_directory, "not_resized.png")
|
63
67
|
|
@@ -75,6 +79,28 @@ class Background(Component):
|
|
75
79
|
self.dem.set_output_resolution((self.rotated_size, self.rotated_size))
|
76
80
|
self.dem.set_dem_path(self.output_path)
|
77
81
|
|
82
|
+
def check_custom_background(self, image_path: str) -> None:
|
83
|
+
"""Checks if the custom background image meets the requirements.
|
84
|
+
|
85
|
+
Arguments:
|
86
|
+
image_path (str): The path to the custom background image.
|
87
|
+
|
88
|
+
Raises:
|
89
|
+
ValueError: If the custom background image does not meet the requirements.
|
90
|
+
"""
|
91
|
+
image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) # pylint: disable=no-member
|
92
|
+
if image.shape[0] != image.shape[1]:
|
93
|
+
raise ValueError("The custom background image must be a square.")
|
94
|
+
|
95
|
+
if image.shape[0] != self.map_size + DEFAULT_DISTANCE * 2:
|
96
|
+
raise ValueError("The custom background image must have the size of the map + 4096.")
|
97
|
+
|
98
|
+
if len(image.shape) != 2:
|
99
|
+
raise ValueError("The custom background image must be a grayscale image.")
|
100
|
+
|
101
|
+
if image.dtype != np.uint16:
|
102
|
+
raise ValueError("The custom background image must be a 16-bit grayscale image.")
|
103
|
+
|
78
104
|
def is_preview(self, name: str) -> bool:
|
79
105
|
"""Checks if the DEM is a preview.
|
80
106
|
|
@@ -91,7 +117,9 @@ class Background(Component):
|
|
91
117
|
as a result the DEM files will be saved, then based on them the obj files will be
|
92
118
|
generated."""
|
93
119
|
self.create_background_textures()
|
94
|
-
|
120
|
+
|
121
|
+
if not self.map.custom_background_path:
|
122
|
+
self.dem.process()
|
95
123
|
|
96
124
|
shutil.copyfile(self.dem.dem_path, self.not_substracted_path)
|
97
125
|
self.cutout(self.dem.dem_path, save_path=self.not_resized_path)
|
@@ -179,7 +207,13 @@ class Background(Component):
|
|
179
207
|
self.logger.debug("Generating obj file in path: %s", save_path)
|
180
208
|
|
181
209
|
dem_data = cv2.imread(self.dem.dem_path, cv2.IMREAD_UNCHANGED) # pylint: disable=no-member
|
182
|
-
self.plane_from_np(
|
210
|
+
self.plane_from_np(
|
211
|
+
dem_data,
|
212
|
+
save_path,
|
213
|
+
create_preview=True,
|
214
|
+
remove_center=self.map.background_settings.remove_center,
|
215
|
+
include_zeros=False,
|
216
|
+
) # type: ignore
|
183
217
|
|
184
218
|
# pylint: disable=too-many-locals
|
185
219
|
def cutout(self, dem_path: str, save_path: str | None = None) -> str:
|
@@ -222,17 +256,37 @@ class Background(Component):
|
|
222
256
|
)
|
223
257
|
|
224
258
|
cv2.imwrite(main_dem_path, resized_dem_data) # pylint: disable=no-member
|
225
|
-
self.logger.
|
259
|
+
self.logger.debug("DEM cutout saved: %s", main_dem_path)
|
226
260
|
|
227
261
|
return main_dem_path
|
228
262
|
|
229
|
-
|
263
|
+
def remove_center(self, dem_data: np.ndarray, resize_factor: float) -> np.ndarray:
|
264
|
+
"""Removes the center part of the DEM data.
|
265
|
+
|
266
|
+
Arguments:
|
267
|
+
dem_data (np.ndarray) -- The DEM data as a numpy array.
|
268
|
+
resize_factor (float) -- The resize factor of the DEM data.
|
269
|
+
|
270
|
+
Returns:
|
271
|
+
np.ndarray -- The DEM data with the center part removed.
|
272
|
+
"""
|
273
|
+
center = (dem_data.shape[0] // 2, dem_data.shape[1] // 2)
|
274
|
+
half_size = int(self.map_size // 2 * resize_factor)
|
275
|
+
x1 = center[0] - half_size
|
276
|
+
x2 = center[0] + half_size
|
277
|
+
y1 = center[1] - half_size
|
278
|
+
y2 = center[1] + half_size
|
279
|
+
dem_data[x1:x2, y1:y2] = 0
|
280
|
+
return dem_data
|
281
|
+
|
282
|
+
# pylint: disable=R0913, R0917, R0915
|
230
283
|
def plane_from_np(
|
231
284
|
self,
|
232
285
|
dem_data: np.ndarray,
|
233
286
|
save_path: str,
|
234
287
|
include_zeros: bool = True,
|
235
288
|
create_preview: bool = False,
|
289
|
+
remove_center: bool = False,
|
236
290
|
) -> None:
|
237
291
|
"""Generates a 3D obj file based on DEM data.
|
238
292
|
|
@@ -241,11 +295,17 @@ class Background(Component):
|
|
241
295
|
save_path (str) -- The path where the obj file will be saved.
|
242
296
|
include_zeros (bool, optional) -- If True, the mesh will include the zero height values.
|
243
297
|
create_preview (bool, optional) -- If True, a simplified mesh will be saved as an STL.
|
298
|
+
remove_center (bool, optional) -- If True, the center of the mesh will be removed.
|
299
|
+
This setting is used for a Background Terrain, where the center part where the
|
300
|
+
playable area is will be cut out.
|
244
301
|
"""
|
245
302
|
resize_factor = 1 / self.map.background_settings.resize_factor
|
246
303
|
dem_data = cv2.resize( # pylint: disable=no-member
|
247
304
|
dem_data, (0, 0), fx=resize_factor, fy=resize_factor
|
248
305
|
)
|
306
|
+
if remove_center:
|
307
|
+
dem_data = self.remove_center(dem_data, resize_factor)
|
308
|
+
self.logger.debug("Center removed from DEM data.")
|
249
309
|
self.logger.debug(
|
250
310
|
"DEM data resized to shape: %s with factor: %s", dem_data.shape, resize_factor
|
251
311
|
)
|
@@ -306,12 +366,28 @@ class Background(Component):
|
|
306
366
|
self.logger.debug("Z scaling factor: %s", z_scaling_factor)
|
307
367
|
mesh.apply_scale([1 / resize_factor, 1 / resize_factor, z_scaling_factor])
|
308
368
|
|
369
|
+
old_faces = len(mesh.faces)
|
370
|
+
self.logger.debug("Mesh generated with %s faces.", old_faces)
|
371
|
+
|
372
|
+
if self.map.background_settings.apply_decimation:
|
373
|
+
percent = self.map.background_settings.decimation_percent / 100
|
374
|
+
mesh = mesh.simplify_quadric_decimation(
|
375
|
+
percent=percent, aggression=self.map.background_settings.decimation_agression
|
376
|
+
)
|
377
|
+
|
378
|
+
new_faces = len(mesh.faces)
|
379
|
+
decimation_percent = (old_faces - new_faces) / old_faces * 100
|
380
|
+
|
381
|
+
self.logger.debug(
|
382
|
+
"Mesh simplified to %s faces. Decimation percent: %s", new_faces, decimation_percent
|
383
|
+
)
|
384
|
+
|
309
385
|
mesh.export(save_path)
|
310
386
|
self.logger.debug("Obj file saved: %s", save_path)
|
311
387
|
|
312
388
|
if create_preview:
|
313
389
|
# Simplify the preview mesh to reduce the size of the file.
|
314
|
-
mesh = mesh.simplify_quadric_decimation(face_count=len(mesh.faces) // 2**7)
|
390
|
+
# mesh = mesh.simplify_quadric_decimation(face_count=len(mesh.faces) // 2**7)
|
315
391
|
|
316
392
|
# Apply scale to make the preview mesh smaller in the UI.
|
317
393
|
mesh.apply_scale([0.5, 0.5, 0.5])
|
maps4fs/generator/grle.py
CHANGED
@@ -114,12 +114,12 @@ class GRLE(Component):
|
|
114
114
|
self.logger.warning("Fields data not found in textures info layer.")
|
115
115
|
return
|
116
116
|
|
117
|
-
self.logger.
|
117
|
+
self.logger.debug("Found %s fields in textures info layer.", len(fields))
|
118
118
|
|
119
119
|
farmyards: list[list[tuple[int, int]]] | None = textures_info_layer.get("farmyards")
|
120
120
|
if farmyards and self.map.grle_settings.add_farmyards:
|
121
121
|
fields.extend(farmyards)
|
122
|
-
self.logger.
|
122
|
+
self.logger.debug("Found %s farmyards in textures info layer.", len(farmyards))
|
123
123
|
|
124
124
|
info_layer_farmlands_path = os.path.join(
|
125
125
|
self.game.weights_dir_path(self.map_directory), "infoLayer_farmlands.png"
|
maps4fs/generator/i3d.py
CHANGED
@@ -155,7 +155,7 @@ class I3d(Component):
|
|
155
155
|
self.logger.warning("Roads polylines data not found in textures info layer.")
|
156
156
|
return
|
157
157
|
|
158
|
-
self.logger.
|
158
|
+
self.logger.debug("Found %s roads polylines in textures info layer.", len(roads_polylines))
|
159
159
|
self.logger.debug("Starging to add roads polylines to the I3D file.")
|
160
160
|
|
161
161
|
root = tree.getroot()
|
@@ -300,7 +300,7 @@ class I3d(Component):
|
|
300
300
|
self.logger.warning("Fields data not found in textures info layer.")
|
301
301
|
return
|
302
302
|
|
303
|
-
self.logger.
|
303
|
+
self.logger.debug("Found %s fields in textures info layer.", len(fields))
|
304
304
|
self.logger.debug("Starging to add fields to the I3D file.")
|
305
305
|
|
306
306
|
root = tree.getroot()
|
maps4fs/generator/map.py
CHANGED
@@ -89,6 +89,17 @@ class Map:
|
|
89
89
|
|
90
90
|
self.dem_settings = dem_settings
|
91
91
|
self.logger.info("DEM settings: %s", dem_settings)
|
92
|
+
if self.dem_settings.water_depth > 0:
|
93
|
+
# Make sure that the plateau value is >= water_depth
|
94
|
+
self.dem_settings.plateau = max(
|
95
|
+
self.dem_settings.plateau, self.dem_settings.water_depth
|
96
|
+
)
|
97
|
+
self.logger.info(
|
98
|
+
"Plateau value was set to %s to be >= water_depth value %s",
|
99
|
+
self.dem_settings.plateau,
|
100
|
+
self.dem_settings.water_depth,
|
101
|
+
)
|
102
|
+
|
92
103
|
self.background_settings = background_settings
|
93
104
|
self.logger.info("Background settings: %s", background_settings)
|
94
105
|
self.grle_settings = grle_settings
|
@@ -140,6 +151,11 @@ class Map:
|
|
140
151
|
json.dump(self.tree_custom_schema, file, indent=4)
|
141
152
|
self.logger.debug("Tree custom schema saved to %s", save_path)
|
142
153
|
|
154
|
+
self.custom_background_path = kwargs.get("custom_background_path", None)
|
155
|
+
if self.custom_background_path:
|
156
|
+
save_path = os.path.join(self.map_directory, "custom_background.png")
|
157
|
+
shutil.copyfile(self.custom_background_path, save_path)
|
158
|
+
|
143
159
|
try:
|
144
160
|
shutil.unpack_archive(game.template_path, self.map_directory)
|
145
161
|
self.logger.debug("Map template unpacked to %s", self.map_directory)
|
maps4fs/generator/settings.py
CHANGED
@@ -23,6 +23,10 @@ class SharedSettings(BaseModel):
|
|
23
23
|
class SettingsModel(BaseModel):
|
24
24
|
"""Base class for settings models. It provides methods to convert settings to and from JSON."""
|
25
25
|
|
26
|
+
model_config = ConfigDict(
|
27
|
+
frozen=False,
|
28
|
+
)
|
29
|
+
|
26
30
|
@classmethod
|
27
31
|
def all_settings_to_json(cls) -> dict[str, dict[str, Any]]:
|
28
32
|
"""Get all settings of the current class and its subclasses as a dictionary.
|
@@ -98,6 +102,10 @@ class BackgroundSettings(SettingsModel):
|
|
98
102
|
generate_background: bool = False
|
99
103
|
generate_water: bool = False
|
100
104
|
resize_factor: int = 8
|
105
|
+
remove_center: bool = False
|
106
|
+
apply_decimation: bool = False
|
107
|
+
decimation_percent: int = 25
|
108
|
+
decimation_agression: int = 3
|
101
109
|
|
102
110
|
|
103
111
|
class GRLESettings(SettingsModel):
|
maps4fs/generator/texture.py
CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
5
5
|
import json
|
6
6
|
import os
|
7
7
|
import re
|
8
|
+
import shutil
|
8
9
|
from collections import defaultdict
|
9
10
|
from typing import Any, Callable, Generator, Optional
|
10
11
|
|
@@ -69,6 +70,7 @@ class Texture(Component):
|
|
69
70
|
usage: str | None = None,
|
70
71
|
background: bool = False,
|
71
72
|
invisible: bool = False,
|
73
|
+
procedural: list[str] | None = None,
|
72
74
|
):
|
73
75
|
self.name = name
|
74
76
|
self.count = count
|
@@ -81,6 +83,7 @@ class Texture(Component):
|
|
81
83
|
self.usage = usage
|
82
84
|
self.background = background
|
83
85
|
self.invisible = invisible
|
86
|
+
self.procedural = procedural
|
84
87
|
|
85
88
|
def to_json(self) -> dict[str, str | list[str] | bool]: # type: ignore
|
86
89
|
"""Returns dictionary with layer data.
|
@@ -99,6 +102,7 @@ class Texture(Component):
|
|
99
102
|
"usage": self.usage,
|
100
103
|
"background": self.background,
|
101
104
|
"invisible": self.invisible,
|
105
|
+
"procedural": self.procedural,
|
102
106
|
}
|
103
107
|
|
104
108
|
data = {k: v for k, v in data.items() if v is not None}
|
@@ -212,6 +216,10 @@ class Texture(Component):
|
|
212
216
|
|
213
217
|
self._weights_dir = self.game.weights_dir_path(self.map_directory)
|
214
218
|
self.logger.debug("Weights directory: %s.", self._weights_dir)
|
219
|
+
self.procedural_dir = os.path.join(self._weights_dir, "masks")
|
220
|
+
os.makedirs(self.procedural_dir, exist_ok=True)
|
221
|
+
self.logger.debug("Procedural directory: %s.", self.procedural_dir)
|
222
|
+
|
215
223
|
self.info_save_path = os.path.join(self.map_directory, "generation_info.json")
|
216
224
|
self.logger.debug("Generation info save path: %s.", self.info_save_path)
|
217
225
|
|
@@ -251,11 +259,56 @@ class Texture(Component):
|
|
251
259
|
return layer
|
252
260
|
return None
|
253
261
|
|
254
|
-
def process(self):
|
262
|
+
def process(self) -> None:
|
263
|
+
"""Processes the data to generate textures."""
|
255
264
|
self._prepare_weights()
|
256
265
|
self._read_parameters()
|
257
266
|
self.draw()
|
258
267
|
self.rotate_textures()
|
268
|
+
self.copy_procedural()
|
269
|
+
|
270
|
+
def copy_procedural(self) -> None:
|
271
|
+
"""Copies some of the textures to use them as mask for procedural generation.
|
272
|
+
Creates an empty blockmask if it does not exist."""
|
273
|
+
blockmask_path = os.path.join(self.procedural_dir, "BLOCKMASK.png")
|
274
|
+
if not os.path.isfile(blockmask_path):
|
275
|
+
self.logger.debug("BLOCKMASK.png not found, creating an empty file.")
|
276
|
+
img = np.zeros((self.map_size, self.map_size), dtype=np.uint8)
|
277
|
+
cv2.imwrite(blockmask_path, img) # pylint: disable=no-member
|
278
|
+
|
279
|
+
pg_layers_by_type = defaultdict(list)
|
280
|
+
for layer in self.layers:
|
281
|
+
if layer.procedural:
|
282
|
+
# Get path to the original file.
|
283
|
+
texture_path = layer.get_preview_or_path(self._weights_dir)
|
284
|
+
for procedural_layer_name in layer.procedural:
|
285
|
+
pg_layers_by_type[procedural_layer_name].append(texture_path)
|
286
|
+
|
287
|
+
if not pg_layers_by_type:
|
288
|
+
self.logger.debug("No procedural layers found.")
|
289
|
+
return
|
290
|
+
|
291
|
+
for procedural_layer_name, texture_paths in pg_layers_by_type.items():
|
292
|
+
procedural_save_path = os.path.join(self.procedural_dir, f"{procedural_layer_name}.png")
|
293
|
+
if len(texture_paths) > 1:
|
294
|
+
# If there are more than one texture, merge them.
|
295
|
+
merged_texture = np.zeros((self.map_size, self.map_size), dtype=np.uint8)
|
296
|
+
for texture_path in texture_paths:
|
297
|
+
# pylint: disable=E1101
|
298
|
+
texture = cv2.imread(texture_path, cv2.IMREAD_UNCHANGED)
|
299
|
+
merged_texture[texture == 255] = 255
|
300
|
+
cv2.imwrite(procedural_save_path, merged_texture) # pylint: disable=no-member
|
301
|
+
self.logger.debug(
|
302
|
+
"Procedural file %s merged from %s textures.",
|
303
|
+
procedural_save_path,
|
304
|
+
len(texture_paths),
|
305
|
+
)
|
306
|
+
elif len(texture_paths) == 1:
|
307
|
+
# Otherwise, copy the texture.
|
308
|
+
shutil.copyfile(texture_paths[0], procedural_save_path)
|
309
|
+
self.logger.debug(
|
310
|
+
"Procedural file %s copied from %s.", procedural_save_path, texture_paths[0]
|
311
|
+
)
|
259
312
|
|
260
313
|
def rotate_textures(self) -> None:
|
261
314
|
"""Rotates textures of the layers which have tags."""
|
@@ -507,7 +560,7 @@ class Texture(Component):
|
|
507
560
|
cv2.imwrite(sublayer_path, sublayer)
|
508
561
|
self.logger.debug("Sublayer %s saved.", sublayer_path)
|
509
562
|
|
510
|
-
self.logger.
|
563
|
+
self.logger.debug("Dissolved layer %s.", layer.name)
|
511
564
|
|
512
565
|
def draw_base_layer(self, cumulative_image: np.ndarray) -> None:
|
513
566
|
"""Draws base layer and saves it into the png file.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: maps4fs
|
3
|
-
Version: 1.6.
|
3
|
+
Version: 1.6.6
|
4
4
|
Summary: Generate map templates for Farming Simulator from real places.
|
5
5
|
Author-email: iwatkot <iwatkot@gmail.com>
|
6
6
|
License: MIT License
|
@@ -131,6 +131,7 @@ docker run -d -p 8501:8501 --name maps4fs iwatkot/maps4fs
|
|
131
131
|
```
|
132
132
|
And open [http://localhost:8501](http://localhost:8501) in your browser.<br>
|
133
133
|
If you don't know how to use Docker, navigate to the [Docker version](#option-2-docker-version), it's really simple.<br>
|
134
|
+
Check out the [Docker FAQ](docs/FAQ_docker.md) if you have any questions.<br>
|
134
135
|
|
135
136
|
### 🤯 For developers
|
136
137
|
**Option 3:** Python package. Install the package using the following command:
|
@@ -185,6 +186,7 @@ Using it is easy and doesn't require any guides. Enjoy!
|
|
185
186
|
🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
|
186
187
|
⚙️ Advanced settings: enabled.
|
187
188
|
🖼️ Texture dissolving: enabled.
|
189
|
+
Check out the [Docker FAQ](docs/FAQ_docker.md) if you have any questions.<br>
|
188
190
|
You can launch the project with minimalistic UI in your browser using Docker. Follow these steps:
|
189
191
|
|
190
192
|
1. Install [Docker](https://docs.docker.com/get-docker/) for your OS.
|
@@ -421,6 +423,7 @@ Let's have a closer look at the fields:
|
|
421
423
|
- `background` - set it to True for the textures, which should have impact on the Background Terrain, by default it's used to subtract the water depth from the DEM and background terrain.
|
422
424
|
- `info_layer` - if the layer is saving some data in JSON format, this section will describe it's name in the JSON file. Used to find the needed JSON data, for example for fields it will be `fields` and as a value - list of polygon coordinates.
|
423
425
|
- `invisible` - set it to True for the textures, which should not be drawn in the files, but only to save the data in the JSON file (related to the previous field).
|
426
|
+
- `procedural` - is a list of corresponding files, that will be used for a procedural generation. For example: `"procedural": ["PG_meadow", "PG_acres"]` - means that the texture will be used for two procedural generation files: `masks/PG_meadow.png` and `masks/PG_acres.png`. Note, that the one procuderal name can be applied to multiple textures, in this case they will be merged into one mask.
|
424
427
|
|
425
428
|
## Background terrain
|
426
429
|
The tool now supports the generation of the background terrain. If you don't know what it is, here's a brief explanation. The background terrain is the world around the map. It's important to create it because if you don't, the map will look like it's floating in the void. The background terrain is a simple plane that can (and should) be textured to look fine.<br>
|
@@ -467,17 +470,12 @@ List of the important DDS files:
|
|
467
470
|
- `mapsUS/overview.dds` - 4096x4096 pixels, the overview image of the map (in-game map)
|
468
471
|
|
469
472
|
## Advanced settings
|
470
|
-
The tool supports the custom size of the map. To use this feature select `Custom` in the `Map size` dropdown and enter the desired size. The tool will generate a map with the size you entered.<br>
|
471
473
|
|
472
|
-
|
473
|
-
|
474
|
-

|
475
|
-
|
476
|
-
You can also apply some advanced settings to the map generation process. Note that they're ADVANCED, so you don't need to use them if you're not sure what they do.<br>
|
474
|
+
You can also apply some advanced settings to the map generation process.<br>
|
477
475
|
|
478
476
|
### DEM Advanced settings
|
479
477
|
|
480
|
-
- Multiplier: the height of the map is multiplied by this value. So the DEM map is just a 16-bit grayscale image, which means that the maximum available value there is 65535, while the actual difference between the deepest and the highest point on Earth is about 20 km. Just note that this setting mostly does not matter, because you can always adjust it in the Giants Editor, learn more about the DEM file and the heightScale parameter in [docs](docs/dem.md).
|
478
|
+
- Multiplier: the height of the map is multiplied by this value. So the DEM map is just a 16-bit grayscale image, which means that the maximum available value there is 65535, while the actual difference between the deepest and the highest point on Earth is about 20 km. Just note that this setting mostly does not matter, because you can always adjust it in the Giants Editor, learn more about the DEM file and the heightScale parameter in [docs](docs/dem.md). To match the in-game heights with SRTM Data provider, the recommended value is 255 (if easy mode is disabled), but depending on the place, you will need to play with both multiplier and the height scale in Giants Editor to find the best values.
|
481
479
|
|
482
480
|
- Blur radius: the radius of the Gaussian blur filter applied to the DEM map. By default, it's set to 21. This filter just makes the DEM map smoother, so the height transitions will be more natural. You can set it to 1 to disable the filter, but it will result in a Minecraft-like map.
|
483
481
|
|
@@ -493,6 +491,15 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
493
491
|
|
494
492
|
- Resize factor - the factor by which the background terrain will be resized. It will be used as 1 / resize_factor while generating the models. Which means that the larger the value the more the terrain will be resized. The lowest value is 1, in this case background terrain will not be resized. Note, than low values will lead to long processing and enormous size of the obj files.
|
495
493
|
|
494
|
+
- Remove center - if enabled, the playable region (map terrain) will be removed from the background terrain. Note, that it will require low resize factors, to avoid gaps between the map and the background terrain.
|
495
|
+
|
496
|
+
- Apply decimation - if enabled, the mesh will be simplified to reduce the number of faces.
|
497
|
+
|
498
|
+
- Decimation percent - the target percentage of decimation. The higher the value, the more simplified the mesh will be. Note, that high values will break the 3D model entirely.
|
499
|
+
|
500
|
+
- Decimation agression - the aggression of the decimation. The higher the value, the more aggressive the
|
501
|
+
decimation will be, which means the higher it will affect the geometry. It's not recommended to make it higher than the default value, otherwise the background terrain will not match the map terrain.
|
502
|
+
|
496
503
|
### GRLE Advanced settings
|
497
504
|
|
498
505
|
- Farmlands margin - this value (in meters) will be applied to each farmland, making it bigger. You can use the value to adjust how much the farmland should be bigger than the actual field. By default, it's set to 3.
|
@@ -534,6 +541,8 @@ The tool also supports the expert settings. Do not use them until you read the d
|
|
534
541
|
|
535
542
|
- Show schemas - you'll be able to edit or define your own texture or tree schemas. It's useful if you want to add some custom textures or trees to the map. Refer to the [Texture schema](#texture-schema) section to learn more about the schema structure. Any incorrect value here will lead to the completely broken map.
|
536
543
|
|
544
|
+
- Upload custom background image - if you have an image, which represents the map and background terrain you can use it for generation. Note, that the image should meet the following requirements: 1:1 aspect ratio, size = map size + 2048 * 2, it should be uint16 (unsigned 16-bit integer) grayscale (single channel) image. The image should be in the PNG format. If any of the requirements are not met, the tool raises an error. If you're using rotation, the image should already be rotated.
|
545
|
+
|
537
546
|
## Resources
|
538
547
|
In this section, you'll find a list of the resources that you need to create a map for the Farming Simulator.<br>
|
539
548
|
To create a basic map, you only need the Giants Editor. But if you want to create a background terrain - the world around the map, so it won't look like it's floating in the void - you also need Blender and the Blender Exporter Plugins. To create realistic textures for the background terrain, the QGIS is required to obtain high-resolution satellite images.<br>
|
@@ -1,18 +1,18 @@
|
|
1
1
|
maps4fs/__init__.py,sha256=WbT36EzJ_74GN0RUUrLIYECdSdtRiZaxKl17KUt7pjA,492
|
2
2
|
maps4fs/logger.py,sha256=B-NEYpMjPAAqlV4VpfTi6nbBFnEABVtQOaYe6nMpidg,1489
|
3
3
|
maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
4
|
-
maps4fs/generator/background.py,sha256=
|
4
|
+
maps4fs/generator/background.py,sha256=K2HSYENPtJNSlG9M3XGkvUjtYyyI3oWwLMNYPpY3IBQ,25824
|
5
5
|
maps4fs/generator/component.py,sha256=GrTI7803gOQFhqocdjFG-wh0HOkC6HWoyKr8pR2Xp28,20409
|
6
6
|
maps4fs/generator/config.py,sha256=0QmK052B8bxyHVhg3jzCORLfOBMMmqVfhhbqXKf6OMk,4383
|
7
7
|
maps4fs/generator/dem.py,sha256=20gx0dzX0LyO6ipvDitst-BwGfcKogFqgQf9Q2qMH5U,10933
|
8
8
|
maps4fs/generator/game.py,sha256=QHgVnyGYvEnfwGZ84-u-dpbCRr3UeVVqBbrwr5WG8dE,7992
|
9
|
-
maps4fs/generator/grle.py,sha256=
|
10
|
-
maps4fs/generator/i3d.py,sha256=
|
11
|
-
maps4fs/generator/map.py,sha256=
|
9
|
+
maps4fs/generator/grle.py,sha256=rU84Q1PBHr-V-JzdHJ7BXLHC_LztGw6Z1FS2w_1HIF0,17848
|
10
|
+
maps4fs/generator/i3d.py,sha256=D1QBHCFygTkml6GZmLRlUagWEVQb0tNeyZ-MAY-Uf0Q,24945
|
11
|
+
maps4fs/generator/map.py,sha256=P8wHrCLhLcv2W5zJmMGjpM1TAMR8c7yVFzm_n-5ZTHQ,10084
|
12
12
|
maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
|
13
13
|
maps4fs/generator/satellite.py,sha256=_7RcuNmR1mjxEJWMDsjnzKUIqWxnGUn50XtjB7HmSPg,3661
|
14
|
-
maps4fs/generator/settings.py,sha256=
|
15
|
-
maps4fs/generator/texture.py,sha256=
|
14
|
+
maps4fs/generator/settings.py,sha256=TGavqPG-sULpB7_SeOzFZ5mWZUq8d2sHfVu5aBbmx5E,5011
|
15
|
+
maps4fs/generator/texture.py,sha256=jWorYVOzBI-plzy_mh42O2NZuB13M5yDaCOfrpX6Dck,33836
|
16
16
|
maps4fs/generator/dtm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
maps4fs/generator/dtm/dtm.py,sha256=azy-RWsc5PgenKDtgG0lrddMwWEw1hYzdng9V8zphMk,9167
|
18
18
|
maps4fs/generator/dtm/srtm.py,sha256=2-pX6bWrJX6gr8IM7ueX6mm_PW7_UQ58MtdzDHae2OQ,9030
|
@@ -20,8 +20,8 @@ maps4fs/generator/dtm/usgs.py,sha256=ZTi10RNDA3EBrsVg2ZoYrdN4uqiG1Jvk7FzdcKdgNkU
|
|
20
20
|
maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
21
21
|
maps4fs/toolbox/background.py,sha256=9BXWNqs_n3HgqDiPztWylgYk_QM4YgBpe6_ZNQAWtSc,2154
|
22
22
|
maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
|
23
|
-
maps4fs-1.6.
|
24
|
-
maps4fs-1.6.
|
25
|
-
maps4fs-1.6.
|
26
|
-
maps4fs-1.6.
|
27
|
-
maps4fs-1.6.
|
23
|
+
maps4fs-1.6.6.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
|
24
|
+
maps4fs-1.6.6.dist-info/METADATA,sha256=REJVmAJBVXkg5_Gk-3BpU4JbEol1pewc4_AZeWsb6fw,37687
|
25
|
+
maps4fs-1.6.6.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
26
|
+
maps4fs-1.6.6.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
|
27
|
+
maps4fs-1.6.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|