Stalker 2 - joric/maps GitHub Wiki

The PDA tileset is from 1.0.3. Markers were updated to game version 1.1.1 (2024-12-20).

Resources

  • Download FModel, add undetected game, UE5_1 (you need 5.1!), press plus.
  • Add AES key (Directory - AES): 0x33...
  • Add mapping (Settings - General - Local Mapping File): .usmap Mappings file.
  • Select all packages (pack, utoc, etc), press "Load". The game directory tree appears in "Folders".
  • For binary resources in the object root (e.g. cfg files) select object in the tree, press packages.
  • Use "export Raw Data" to save. Exported resources appear in the "Exports" directory by default.

See https://rentry.org/TravesS2moddingBible for details.

Tiles

There is a bunch of maps, the PDA map is in T_WorldMap_UDIM.uasset, it's a large virtual texture (over 3GB).

LongerWarrior from S.T.A.L.K.E.R. 2 Moding Community Discord managed to export Stalker 2 (1.0.3 at the time) PDA map in full resolution (64k x 64k) in 8 horizontal chunks.

The bitmaps for each region for high/low/medium mips are in one of the paks. You can't extract it normally, it is not an asset FModel can process, you need to extract raw bitmap data and convert it to typical container/format.

  • that world map is from T_WorldMap_UDIM.uasset it's virtual texture and all mips data are in ubulk i did modify fmodel source to extract tiles, cause otherwise it can't handle that texture ... i think i deleted everything, i was just a challenge to get that mip0 texture

Asset in question: Stalker2/Content/GameLite/FPS_Game/UIRemaster/UITextures/PDA/WorldMap/T_WorldMap_UDIM.uasset it is in pakchunk16-Windows.utoc. All the data is in ubulk packed with oogle.

Stock FModel says: [ERR] System.OverflowException: Array dimensions exceeded supported range. at CUE4Parse.UE4.IO.IoStoreReader.Read(Int64 offset, Int64 length)

Related issues:

I tried to rollback and rebuild FModel with patch #127 it opens T_WorldMap_UDIM.uasset now but still says Value cannot be null. (Parameter 'sourceArray'). Still needs fixing.

public static bool AlwaysUseChunkedReader = true;
public static bool AllowLargeFiles = true;

With this it reads like this, but still fails at image saving ([ERR] System.NullReferenceException: Object reference not set to an instance of an object. at FModel.ViewModels.TabItem.SaveImage(TabImage image, String path))

[
  {
    "Type": "Texture2D",
    "Name": "T_WorldMap_UDIM",
    "Class": "UScriptClass'Texture2D'",
    "Properties": {
      "ImportedSize": {
        "X": 65536,
        "Y": 65536
      },
      "LightingGuid": "278B7F09-47408D2E-D7D028A8-5AD49DE4",
      "LODGroup": "TextureGroup::TEXTUREGROUP_UI",
      "VirtualTextureStreaming": true
    },
    "SizeX": 0,
    "SizeY": 0,
    "PackedData": 0,
    "PixelFormat": "PF_Unknown",
    "FirstMipToSerialize": -1
  }
]

I tried to read it with UEParse, it's incredlibly slow, the data is Oogle compressed, see IoStoreReader.py: def Read(self, chunkid: FIoChunkId) -> BinaryStream. It sure lacks progress indicator there. It takes a few minutes to unpack an ubulk and then fails. You can use ZenTools to extract the T_WorldMap_UDIM.ubulk (3GB) from pakchunk16-Windows.*, it's much faster than UETools: ZenTools.exe ExtractPackages "C:\\Temp\zentools\\Paks" "C:\\Temp\\zentools\\Output" -AES=0x33.. -ZenPackageVersion=Initial

Then you'd have to extract a texture from ubulk. Normally ubulk is just a renamed DDS but imagemagick fails. With UETools I tried to stop the ubulk reader early, and continue to texture conversion, but FTexturePlatformData.py throws exception "Virtual Textures are not implemented", so you'd have to run your own virtual texture reader, e.g. one from CUE4Parse. Virtual textures appear to be a bunch of DDS files linked together, see https://github.com/matyalatte/UE4-DDS-Tools/issues/30

Extras

There are other maps, see: https://github.com/joric/stalker2_tileset/wiki#extras

  • extras/wb: Stalker2/Content/_Stalker_2/maps/WorldMap/T_GLOBAL_MAP_BASE.uasset (12951x12951 -> 16384x16384, jpg)
  • extras/ld: Stalker2/Content/_Stalker_2/maps/WorldMap/T_WorldMap_LDScheme.uasset (4096x4096, png)
  • extras/s1: https://www.nexusmods.com/stalker2heartofchornobyl/images/212 (8599x7452 -> 8192x8192, png)

"LD" in T_WorldMap_LDScheme.uasset possibly means "Low Detail".

Regions

The region markers are in /Stalker2/Content/GameLite/GameData/MarkerPrototypes.cfg.

Also see Stalker2/Content/LevelBitmaps/T_Regions_Map.uasset it's a texture that marks regions. Every region is different color. It's not very web friendly because it needs pixel manipulation. The png file (T_Regions_Map.png) is just 20 kb though.

Regions were autotraced from T_Regions_Map.uasset to svg https://joric.github.io/stalker/scripts/T_Regions_Map.svg, edited to match T_GLOBAL_MAP_BASE.uasset and exported to geojson https://joric.github.io/stalker/regions.json with svg2geojson.

To calculate polygon centroid (NOT the average of polygon bounds) to place a label, leaflet polygons have .getCenter(), but the polygon has to be added to the map (I had to add/remove it on loading). To calculate if point is in polygon you can use either mouse events (which are not always usable), or the Leaflet.PointInPolygon plugin, leaflet doesn't have this function.

Markers

Stalker 2 uses UE5 blueprints with a proprietary plugin that stores all the metainfo in .cfg files. You don't have to read .umap, most of the data is in the .cfg files that are in the "Stalker2/Content/GameLite/GameData/SpawnActorPrototypes" folder.

For the markers you'd have to scan all .cfg files in GameData and extract spawn coordinates and other properties. I personally just use FModel to export all .cfg files as raw data, then read them from the disk.

I've made a gzipped marker set with 60k markers. It does not include desctuctible objects (ESpawnType::DestructibleObject, e.g. pots), because it would be 120k+ markers. Still lacks reference info such as quests and container spawns.

To identify the markers, draw them all in the square CRS (about 812900 units wide) and compare them to the existing maps. Drawing 50k+ markers would need an OpenGL layer (e.g. Leaflet.PixiOverlay) or Leaflet.markercluster.

The 812900 is the largest landscape allowed in UE5 (8129x8129, NOT 8192) with 100x scaling, see UE5 Techincal Guide.

Items

There are a few markers in MarkerPrototypes.cfg and probably SpawnActorPrototypes but the vast majority is probably still in umap as blueprints. It's just easier to use built in UE map layout rather than something else.

I use cfg files in json format, see scripts directory. I just linked them all together in a 400Mb file to browse.

Weapon

Use file search (Packages - Search) to find files by name. Most object properties are in the GameLite/GameData directory.

  • Item descriptions use *Prototypes.cfg, akin to YAML but nested, parse it line by line (scripts).
  • Base weapon descriptions are in Content/GameLite/GameData/ItemPrototypes/WeaponPrototypes.cfg.
  • LocalizationDB.uasset needs S2HOC Multi Localization Utility to convert ubulk file to JSON.
  • Weapon shooting patterns use ordinary JSON files, search for ShootingPatterns. Shotgun uses 8 bullet patterns (apparently randomly selected).
  • There is csv about weapon properties Exports\Stalker2\Content\GameLite\GameData\xls\WeaponPrototypes.csv
  • Also a csv about faction relations: Exports\Stalker2\Content\GameLite\GameData\Relations.csv
  • Caliber upgrade, see ChangeCaliber045Effect in UpgradePrototypes.cfg

Personal Items

Still figuring out. E.g. CA_lie_bed contextual action determines a usable bed, e.g.:

  1. Bed in Zalissya, 6542E7984A2F86D2E97F6A8488D2A6D7, PlaceholderActorGuid F41XBKQINTQ23K56GKAYJ6EFQ
  2. NPC-only bed nearby, E873DBF94CF4F0BE91893D819020D912, PlaceholderActorGuid A65CG0953EQ02GA2BCGWHVGZ8

Configurations look totally identical and there are no cross references. Maybe scripted?

In Rookie Village (search for sid 8F127B07488EDA6B91F2559277D5E7C2, it's a pack of items nearby) bed and chest markers seems to be missing. Either they are in nested structs (I only scan top level) or in .umap.

Map:

image

Game:

Untitled

All the small random stuff spawns are there, but no personal bed/stash markers, which is weird. They are not in the destructable items either.

Looks like even with 60k markers the map lacks quite a lot of stuff. E.g. in Rookie Village. Sidorovich is not marked as trader, there is only CA_Quest_Hub_Survey_PDA (DD0AE5FB49F0CD9DC8807DA8B35783A6) in his place. This seems important:

  • Content/GameLite/GameData/ContextualActionBlueprintPrototypes/CA_Quest_Hub_Survey_PDA.cfg
  • Content/GameLite/GameData/ContextualActionNodePrototypes/CA_Quest_Hub_Survey_PDA.cfg

There's a trigger volume 48716F37408178733ECBE58FB6F4613B in the basement that has references from other files, e.g. Content/GameLite/GameData/SpawnActorPrototypes/WorldMap_WP/46E399AC4C52E90CC5AA0CA869E16653.cfg (ESpawnType::Shelter) it's referred as one of 5 "volumes" that are probably a list of shelters, scattered around the village:

            "[5]": {
              "data": {
                "Volume": "48716F37408178733ECBE58FB6F4613B",
                "ShowMarker": "true",
                "NumOfContextualActions": 0,
                "RestrictorVolume": "0E1EBF084B4DC5EF59FC55A3366ED8D1"
              }
            }

The "RestrictorVolume" doesn't appear in .cfg files either.

Triggers

The trigger next to the player's bed in Zalissya (CD0767DC4762AD400AE9C695678C180C) appears to be a door trigger.

Looks like it's not a chest, but rather a door. The chest marker coordinates appear to be elsewhere, not in cfg files.

  "SpawnActorPrototypes/WorldMap_WP/Zalesie_Hub_LogicLevel_WP/CD0767DC4762AD400AE9C695678C180C.cfg": {
    "CD0767DC4762AD400AE9C695678C180C": {
      "comment": "BP_TriggerPlaceholder_C_UAID_F02F748759C804E201_1557333093",
      "data": {
        "SID": "CD0767DC4762AD400AE9C695678C180C",
        "NodePrototypeVersion": 10,
        "SpawnOnStart": "false",
        "LevelName": "WorldMap_WP/Zalesie_Hub_LogicLevel_WP",
        "PlaceholderActorGuid": "AG76FBPJFAK1U6BDF139727E2",
        "PlaceholderMapPath": "/Game/_Stalker_2/maps/_Stalker2_WorldMap/QuestLevels/Zalesie_Hub_LogicLevel_WP",
        "SpawnType": "ESpawnType::Trigger",
        "TriggerShape": "ETriggerShape::Cylinder"
      }
    }
  },

It is cross-referenced in a quest Content\GameLite\GameData\QuestNodePrototypes\Zalesie_Hub.cfg:

    "Zalesie_Hub_OnTriggerExitEvent_5": {
      "data": {
        "SID": "Zalesie_Hub_OnTriggerExitEvent_5",
        "NodePrototypeVersion": 1,
        "Repeatable": "true",
        "QuestSID": "Zalesie_Hub",
        "NodeType": "EQuestNodeType::Trigger",
        "LaunchOnQuestStart": "true",
        "EventType": "EQuestEventType::OnTriggerExit",
        "TrackBeforeActive": "false",
        "TargetQuestGuid": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        "TriggerQuestGuid": "CD0767DC4762AD400AE9C695678C180C",
        "bTriggersByAnybody": "false",
        "TriggerAction": 1,
        "RequiredSquadMembers": "ERequiredSquadMembers::AnyMember",
        "ReactType": "ETriggerReact::ReactOnAlive"
      }
    },

Misc

  • items on the ground are split into ~80k cfg files, not all of them are items tho, but its still thousands or tens of thousands of individual cfgs that contain the loose items pakchunk0-Windows\Stalker2\Content\GameLite\GameData\SpawnActorPrototypes\WorldMap_WP

Note markers have SpawnType = ESpawnType::Marker, see 44DE8E9A4E838F5C0051AAB546F5A247.cfg

  • I don't remember exactly, but I think XShowUnitAndSquadUIDs RADIUS might show SIDs of items ingame, including stashes

XShowUnitAndSquadUIDs does not work. But it's an interesting idea to use UE4SS lua scripts to find items with raycasting.

  • the active WP landscape size is 816000x816000 ue units, UI view scaled size is 32512x32512 the map texture projected on a plane which 32.512x32.512 units and then rendered in sections to UI. I simply measured it with live coordinates. This scale is what my teleport-anywhere-on-the-map-by-click mod uses.

I actually use 812900 and 65536x65536. At 816000 everything will be off (pot/non-pot textures?).

References