Code Monkey home page Code Monkey logo

vdf's People

Contributors

bubylou avatar lasa01 avatar rossengeorgiev avatar rosuav avatar sleepprogger avatar smcv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

vdf's Issues

Provide an generator function for the iterative parser

  1. This would be useful for parsing large files. Avoid using a ton of memory, especially when only a small section of the file is needed
  2. function that yields tuple of key path and valuie
  3. function that user can provide a target key path, and it will return a mapper for everything under that location

Getting `SyntaxError: Unterminated cstring (offset: 1)` when trying to load shortcuts

I'm trying to read and edit the shortcuts.vdf file, but something is going wrong, as I get the error SyntaxError: Unterminated cstring (offset: 1). Is it me that is doing something wrong, or is this a bug?

My code:

import vdf

shortcutsFileLocation = "/home/user/.steam/steam/userdata/1234/config/localconfig.vdf"
shortcutsFile = open(shortcutsFileLocation, "rb")
shortcutsBytes = shortcutsFile.read()

shortcuts = vdf.binary_loads(shortcutsBytes)

Parsing error when escaped inside a string

Trying to use this for my build tool, I'm getting some errors when the parser tries to deal with Paths such as when parsing:

"appbuild"
{
"appid" "111111111"
"desc" "Description you want"
"buildoutput" "D:\SteamSDK\tools\ContentBuilder\output"
"contentroot" ""
"setlive" "internaltest"
"preview" "0"
"local" ""
"depots"
{
"111111111" "D:\SteamSDK\tools\ContentBuilder\scripts\generic_depot.vdf"
}
}

This is what it's returning

"appbuild"
{
"appid" "111111111"
"desc" "Description you want"
"buildoutput" "D:\\SteamSDK\tools\\ContentBuilder\\output"
"contentroot" ""
"setlive" "internaltest"
"preview" "0"
"local" ""
"depots"
{
"111111111" "D:\\SteamSDK\tools\\ContentBuilder\\scripts\\generic_depot.vdf"
}
}

Notice D:\SteamSDK\tools\ContentBuilder\scripts\generic_depot.vdf

Where \tools it's only giving one backslash because \t is an escape command.

Adding utf-8 as a supported string encoding when dumping

I am using this library to read and write to shortcuts.vdf which Steam uses to store non-Steam game shortcuts. While testing, I found that encoded non-ASCII strings were using utf-16 which caused Steam to incorrectly parse the file.

def _binary_dump_gen(obj, level=0, alt_format=False):

I propose adding a new optional parameter to binary_dumps() (with utf-16 as a default) to allow encoding using utf-8. I have tested this in my fork of this library and Steam successfully parsed the resulting vdf file.

Nested groups with duplicate keys trivially do not work, even with VDFDict

Input file demo.vdf:

"controller_mappings"
{
	"group"
	{
		"id"		"0"
	}
	"group"
	{
		"id"		"1"
	}
}

Test script:

import vdf
with open("demo.vdf") as fp:
    v = vdf.load(fp, mapper=vdf.VDFDict)
    print(type(v))
    print(type(v['controller_mappings']))
    print(vdf.dumps(v, pretty=True))

Expected output:
(demo.vdf)

Actual output:

<class 'vdf.vdict.VDFDict'>
<class 'vdf.vdict.VDFDict'>
"controller_mappings"
{
        "group"
        {
                "id" "0"
                "id" "1"
        }
}

Not only is this incorrect, but no error is thrown: the resulting data structure is silently malformed and passed along.

Exception while trying the example on readme

Hello

I got an exception while trying the example on duplicates.
When reassigning a duplicate and after printing the duplicate, get_all_for('key') fails with


>>> d[(1, 'key')] = 123  # reassign specific duplicate
>>> d.get_all_for('key')

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files\Python310\lib\site-packages\vdf\vdict.py", line 190, in get_all_for
    return [self[(idx, key)] for idx in _range(self.__kcount[key])]
  File "C:\Program Files\Python310\lib\site-packages\vdf\vdict.py", line 190, in <listcomp>
    return [self[(idx, key)] for idx in _range(self.__kcount[key])]
  File "C:\Program Files\Python310\lib\site-packages\vdf\vdict.py", line 87, in __getitem__
    return super(VDFDict, self).__getitem__(self._normalize_key(key))
KeyError: (2, 'key')

is it a bug or the examples are not up to date?

BinaryVDF.test_loads_utf16 not passed

Some tests not passed in Fedora 32:

=================================== FAILURES ===================================
__________________________ BinaryVDF.test_loads_utf16 __________________________
self = <tests.test_binary_vdf.BinaryVDF testMethod=test_loads_utf16>
    def test_loads_utf16(self):
>       self.assertEqual({'aaa': b'b\x00b\x00\xff\xffb\x00b\x00'.decode('utf-16le')}, vdf.binary_loads(b'\x05aaa\x00b\x00b\x00\xff\xffb\x00b\x00\x00\x00\x08'))
E       AssertionError: {'aaa': 'bb\uffffbb'} != {'aaa': 'ๆˆ€ๆˆ€\uffffๆˆ€ๆˆ€'}
E       - {'aaa': 'bb\uffffbb'}
E       ?          ^^      ^^
E       
E       + {'aaa': 'ๆˆ€ๆˆ€\uffffๆˆ€ๆˆ€'}
E       ?          ^^      ^^
tests/test_binary_vdf.py:188: AssertionError

But tests passed in Fedora 33 and no such issue. Full F32 build log.

Additional information:

  • OS: Fedora 32
  • Python ver: 3.8.7

Should \x02 be UINT32?

From my shortcuts.vdf file, Halo Infinite has the appid C0 83 BF F8 which in python when read is displayed as the following.
`

print(d["shortcuts"]["103"]["appid"])
-121666624
`

Steam uses the appid for grid images. It seems like the byte data is being read as uint32 instead of int32 by steam. The same thing happens with all shortcuts ids I've checked.
`

print(d["shortcuts"]["103"]["icon"])
C:\Program Files (x86)\Steam\userdata\XYZ\config\grid\4173300672_icon.ico
`

Alternative binary keyvalue

The alternative format uses 0x0b as END instead of 0x08, otherwise it exactly the same. I have no idea why that is. Is it a programming typo, 0x0B looks like 0x08? Maybe it's supposed to be different. Say a format for on disk, rather than just data interchange over the steam network. Explains the CRC32, but why change the format?

Samples files:

  • 0x08 - [steamdir]/appcache/appinfo.vdf
  • 0x0B - [steamdir]/userdata/[account id]/570/remote/cfg/chat.cfg
    File starts with VBKV, followed by 4 bytes CRC32 of the rest, then binary vdf

Handling for #base and #include

Apparently the VDF format supports definitions for merging files.

  • #base will merge KVs from the specified file with the ones from the current
  • #include will append

I don't see how that could be implemented in the module reliably. It should be fairly simple to implement at application level for the specific use case. That leaves allowing # symbol to be used as unquoted key or value, which is currently not supported.

Building python-vdf version 3.3 with python 3.10 fails

Building python-vdf version 3.3 with python 3.10 at at https://build.opensuse.org/package/show/games:tools/python-vdf fails with the following error:

  • /usr/bin/python3.10 setup.py build '--executable=/usr/bin/python3.10 -s'
    [ 50s] Traceback (most recent call last):
    [ 50s] File "/home/abuild/rpmbuild/BUILD/python-vdf-3.3/setup.py", line 6, in
    [ 50s] import vdf
    [ 50s] File "/home/abuild/rpmbuild/BUILD/python-vdf-3.3/vdf/init.py", line 19, in
    [ 50s] from vdf.vdict import VDFDict
    [ 50s] File "/home/abuild/rpmbuild/BUILD/python-vdf-3.3/vdf/vdict.py", line 9, in
    [ 50s] class _kView(_c.KeysView):
    [ 50s] AttributeError: module 'collections' has no attribute 'KeysView'
    [ 50s] error: Bad exit status from /var/tmp/rpm-tmp.kZk3A8 (%build)

Failure reading binary VDF files

When I try to read binary files such as appcache/appinfo.vdf or appcache/packageinfo.vdf, I always see the same error:

SyntaxError: Unknown data type at index 5: b"'"

I tried using alt_format=True but it just errors too :/

import vdf
with open('~/.steam/root/appcache/appinfo.vdf', 'rb') as appinfo:
    data = vdf.binary_lods(appinfo.read())

Failure parsing binary VDF fields with invalid UTF-8 strings

vdf fails to parse binary VDF files which contain fields with invalid UTF-8. One such invalid field was discovered in an entry for Spore inside appinfo.vdf. The exception that occurs is:

  File "/home/matoking/git/protontricks/env/lib/python3.7/site-packages/vdf/__init__.py", line 337, in binary_loads
    stack[-1][key], idx = read_string(s, idx)
  File "/home/matoking/git/protontricks/env/lib/python3.7/site-packages/vdf/__init__.py", line 305, in read_string
    result = result.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 12: invalid start byte

I've uploaded a snippet that can be used to reproduce this error here:

https://gist.github.com/Matoking/e2dfe281386ff4eac9022eb0f02d80cd

SteamDB seems to replace the invalid character with a question mark:

https://steamdb.info/app/24720/history/ (the faulty string here is Moje Spore v๏ฟฝtvory)

A similar fix in vdf would mean replacing the result.decode('utf-8') call with result.decode('utf-8', errors='replace') or letting the developer decide how to handle errors by passing an optional errors kwarg.

unexpected EOF (open key quote?)

Unfortunately vdf does not point me to the line responsible for this (or does it via EOF (last lines)?.

I'm was looking for a validate function but couldn't find it. I'm not sure if the file I'm working with is actually a VDF file.

playlists
{
	version stable
	versionNum 214
	Gamemodes
	{
		defaults
		{
			vars
			{
				///////////////////////////////////////////////////////////////////////////////////
				//// Code Required Vars
				///////////////////////////////////////////////////////////////////////////////////
				max_players                                    60
				max_teams                                      20

				bsp_build_warnings_off                         0
				cmdlineMapLoad                                 1

				faq_community_count                            1
				faq_community_url_00                           ""
				faq_community_version                          0
				faq_patchnotes_count                           1
				faq_patchnotes_version                         0

				idleKickTime_minutes                           0
				mixtape_onboarding                             "survival"
				observer_mode_check_same_team                  1
				hover_tank_revive_fix                          1
				player_freefall_job_enable                     1

				enable_report                                  2
				enable_three_weapons                           0
				charselect_intro_countdown_duration            5
				wait_for_players_forever                       0


				///////////////////////////////////////////////////////////////////////////////////
				//// Script Required Vars
				///////////////////////////////////////////////////////////////////////////////////
				canyonlands_hovertanks_circle_index            1

				loot_main_weapon_energy_ar_edition             20
				loot_main_weapon_lstar_edition                 30

				waiting_for_players_countdown_seconds          5
				waiting_for_players_min_wait                   0
				waiting_for_players_timeout_seconds            60
				waiting_for_players_has_black_screen           1
				survival_enable_gladiator_intros               0
				character_select_time_max                      6
				character_select_time_min                      6


				///////////////////////////////////////////////////////////////////////////////////
				//// Character Configurations
				///////////////////////////////////////////////////////////////////////////////////
				character_dummie                               hide
				character_wattson                              lock
				character_crypto                               lock
				character_random                               lock
				//============= Hide from Normal Use ============//


				///////////////////////////////////////////////////////////////////////////////////
				//// Character Damage Balances
				///////////////////////////////////////////////////////////////////////////////////
				leg_hitbox_override_character_wraith           "20 21"
				leg_hitbox_override_character_lifeline         "20 21"
				leg_hitbox_override_character_wattson          "20 21"
				leg_hitbox_override_character_pathfinder       "16 26 25 12"


				///////////////////////////////////////////////////////////////////////////////////
				//// Deathfield
				///////////////////////////////////////////////////////////////////////////////////
				deathfield_damagePercent_0                     0.02
				deathfield_damagePercent_1                     0.10
				deathfield_damagePercent_2                     0.15
				deathfield_damagePercent_3                     0.20
				deathfield_damagePercent_4                     0.20
				deathfield_damagePercent_5                     0.25
				deathfield_damagePercent_6                     0.25
				deathfield_damagePercent_7                     0.25
				deathfield_preShrinkDuration_0                 180
				deathfield_preShrinkDuration_1                 145
				deathfield_preShrinkDuration_2                 135
				deathfield_preShrinkDuration_3                 120
				deathfield_preShrinkDuration_4                 90
				deathfield_preShrinkDuration_5                 60
				deathfield_preShrinkDuration_6                 20
				deathfield_preShrinkDuration_7                 20
				deathfield_radius_0                            22000
				deathfield_radius_1                            13000
				deathfield_radius_2                            8000
				deathfield_radius_3                            4000
				deathfield_radius_4                            1500
				deathfield_radius_5                            750
				deathfield_radius_6                            100
				deathfield_radius_7                            1
				deathfield_shrinkSpeed_0                       160
				deathfield_shrinkSpeed_1                       130
				deathfield_shrinkSpeed_2                       120
				deathfield_shrinkSpeed_3                       100
				deathfield_shrinkSpeed_4                       80
				deathfield_shrinkSpeed_5                       80
				deathfield_shrinkSpeed_6                       100
				deathfield_shrinkSpeed_7                       100


				///////////////////////////////////////////////////////////////////////////////////
				//// Airdrops
				///////////////////////////////////////////////////////////////////////////////////
				//"type:dropCount:preWait:contentsLeft:contentsRight:contentsCenter"
				// contents can be expanded with: "contentsL1,contentsL2,contentsL3 ...:contentsR1:contentsC1" using "," as a delimiter
				// multiple airdrops can be added per round using " " as a delimiter
				//=====================================================================================================================
				airdrop_data_round_0                           "2:30:care_package_1_L:care_package_1_R:care_package_1_C"
				airdrop_data_round_1                           "1:15:care_package_2_L:care_package_2_R:care_package_2_C"
				airdrop_data_round_2                           "1:0:care_package_3_L:care_package_3_R:care_package_3_C"


				///////////////////////////////////////////////////////////////////////////////////
				//// MTX and Progression
				///////////////////////////////////////////////////////////////////////////////////
				xp_first_game_amount                           0
				xp_champion_amount                             500
				xp_damage_dealt_amount                         0.25
				xp_friend_amount                               3.0
				xp_friend_frac                                 0.05
				xp_kill_amount                                 50
				xp_kill_champion_amount                        500
				xp_kill_leader_amount                          50
				xp_loot_master_amount                          50
				xp_respawn_ally_amount                         200
				xp_revive_ally_amount                          25
				xp_survival_duration_amount                    3.0
				xp_top_five_amount                             300
				xp_win_match_amount                            900
				xp_first_kill_amount                           500
				xp_challenge_completed_amount                  1

				grx_currency_bundle_crafting_common_count      15
				grx_currency_bundle_crafting_epic_count        200
				grx_currency_bundle_crafting_legendary_count   600
				grx_currency_bundle_crafting_rare_count        30


				///////////////////////////////////////////////////////////////////////////////////
				//// Dialogs
				///////////////////////////////////////////////////////////////////////////////////
				generic_dialog_header_30                       "#MATCHMAKING_PENALTY_ACTIVE"
				generic_dialog_message_31                      "#MATCHMAKING_PENALTY_1"
				generic_dialog_message_32                      "#MATCHMAKING_PENALTY_2"
				generic_dialog_message_33                      "#MATCHMAKING_PENALTY_3"
				generic_dialog_message_34                      "#MATCHMAKING_PENALTY_4"
				generic_dialog_message_35                      "#MATCHMAKING_PENALTY_5"
				generic_dialog_message_36                      "#MATCHMAKING_PENALTY_GE_5"


				///////////////////////////////////////////////////////////////////////////////////
				//// Hovertanks
				///////////////////////////////////////////////////////////////////////////////////
				hovertanks_count_intro                         1
				hovertanks_count_mid                           1
				hovertanks_chance_intro                        1.00
				hovertanks_chance_mid                          0.33


				///////////////////////////////////////////////////////////////////////////////////
				//// Gamemodes
				///////////////////////////////////////////////////////////////////////////////////
				mode_fall_ltm                                  0


				///////////////////////////////////////////////////////////////////////////////////
				//// Events
				///////////////////////////////////////////////////////////////////////////////////
				valentines_event                               0
				halloween_event                                0

				///////////////////////////////////////////////////////////////////////////////////
				//// Aim Assist
				///////////////////////////////////////////////////////////////////////////////////
				aimassist_adspull_disabled                     1
				aimassist_magnet_pc                            0.40
				aimassist_magnet                               0.55


				///////////////////////////////////////////////////////////////////////////////////
				//// Battlepass
				///////////////////////////////////////////////////////////////////////////////////
				//battlepass_character_max_xp                    25000
				//battlepass_character_max_weekly_xp             25000


				///////////////////////////////////////////////////////////////////////////////////
				//// Misc Configuration
				///////////////////////////////////////////////////////////////////////////////////
				enable_grx                                     1
				enable_battlepass                              1
				enable_wraith_alert_effect                     1
				disable_hud_score_display                      0
				ranked_in_match_check_party                    0
				ranked_in_match_check_party_force_team         0
				quick_melee_enabled                            1
				require_training                               0
				timelimit                                      30
				survival_shields                               1
				octane_preview                                 0
				player_revive_enabled                          1
				match_ending_enabled                           1
				battlechatter_enabled                          1

				///////////////////////////////////////////////////////////////////////////////////
				//// Player Reporting
				///////////////////////////////////////////////////////////////////////////////////
				report_player_reason_pc_friendly_count         4
				report_player_reason_pc_friendly_1             "#REPORT_PLAYER_REASON_LOS"
				report_player_reason_pc_friendly_2             "#REPORT_PLAYER_REASON_AIMSNAP"
				report_player_reason_pc_friendly_3             "#REPORT_PLAYER_REASON_WEIRDMOVING"
				report_player_reason_pc_friendly_4             "#REPORT_PLAYER_REASON_AMMOORRECOIL"

				report_player_reason_pc_enemy_count            4
				report_player_reason_pc_enemy_1                "#REPORT_PLAYER_REASON_LOS"
				report_player_reason_pc_enemy_2                "#REPORT_PLAYER_REASON_AIMSNAP"
				report_player_reason_pc_enemy_3                "#REPORT_PLAYER_REASON_WEIRDMOVING"
				report_player_reason_pc_enemy_4                "#REPORT_PLAYER_REASON_AMMOORRECOIL"

				report_player_reason_console_friendly_count    5
				report_player_reason_console_friendly_1        "#REPORT_PLAYER_REASON_OFFENSIVE"
				report_player_reason_console_friendly_2        "#REPORT_PLAYER_REASON_SPAWN"
				report_player_reason_console_friendly_3        "#REPORT_PLAYER_REASON_HARRASMENT"
				report_player_reason_console_friendly_4        "#REPORT_PLAYER_REASON_HATE"
				report_player_reason_console_friendly_5        "#REPORT_PLAYER_REASON_SUICIDE"

				report_player_reason_console_enemy_count       4
				report_player_reason_console_enemy_1           "#REPORT_PLAYER_REASON_LOS"
				report_player_reason_console_enemy_2           "#REPORT_PLAYER_REASON_AIMSNAP"
				report_player_reason_console_enemy_3           "#REPORT_PLAYER_REASON_WEIRDMOVING"
				report_player_reason_console_enemy_4           "#REPORT_PLAYER_REASON_AMMOORRECOIL"


				///////////////////////////////////////////////////////////////////////////////////
				//// Unknown
				///////////////////////////////////////////////////////////////////////////////////
				color "254 184 0 255"


				///////////////////////////////////////////////////////////////////////////////////
				//// Season start/end datetimes (don't delete these)
				///////////////////////////////////////////////////////////////////////////////////
				season03_reveal_unixtime                       1626656230
				season03_start_unixtime                        1626656230
				season03_finish_unixtime                       1637272618
				season03_hide_unixtime                         1637272618


				///////////////////////////////////////////////////////////////////////////////////
				//// Dev Playlist Vars
				///////////////////////////////////////////////////////////////////////////////////
				gamemode_select_v2_enable                      1 // Enable gamemode select version 2 over 1
				beta_watermark                                 1 // Enable Beta Watermark
				survival_quick_chat_enabled                    1 // Quips
				desertlands_script_train_enable                1 // World's Edge Train
				thirdperson_match                              0 // Third Person Mode
				enable_nessies                                 1 // Kings Canyon Easter Egg

				///////////////////////////////////////////////////////////////////////////////////
				///////////////////////////////////////////////////////////////////////////////////
			}
			maps
			{
			}
		}

		survival
		{
			inherit defaults
		}
		
		custom_tdm 
		{
			inherit defaults
		}
	}

// START OF MP GAMEMODES LINE --------------------------------------------------

	Playlists
	{
		survival_staging_baseline
		{
			inherit survival
			vars
			{
				max_teams                                      20
				max_players                                    20
				min_players                                    1
				num_squads_in_staging                          1
				waiting_for_players_spawning_enabled           1
				jump_from_plane_enabled                        0
				wait_for_players_forever                       1
				scorebar_hide_squads_remaining                 1
				scorebar_hide_waiting_for_players              1
				airdrop_enabled                                0
				num_static_loot_ticks_to_spawn                 0
				loot_preprocessing_should_be_skipped           1

				charge_pylons_raise_time_override              15 //Shorter time in training

				survival_staging_area_enabled                  1

				make_room_for_new_players                      1

				//Reconnect is disabled in firing range!
				reconnect_disabled                             1
			}
			gamemodes { survival { maps {
				mp_rr_canyonlands_staging                      1
			} } }
		}

		survival_training
		{
			inherit survival_firingrange
			vars
			{
				visible                                        1
				ui_slot                                        training
				video                                          _temp
				name                                           #PL_TRAINING
				description                                    #PL_TRAINING_DESC
				image                                          training

				//
				survival_training                              1
				survival_firingrange                           0
				pin_match_type                                 training
			}
		}

		survival_firingrange
		{
			inherit survival_staging_baseline
			vars
			{
				visible                                        1
				ui_slot                                        firing_range
				image                                          firing_range
				name                                           #PL_FIRINGRANGE
				description                                    #PL_FIRINGRANGE_DESC
				video                                          _temp

				// match teams will not fill with more than one party, up to max_teams of size max_team_size (or less) -- not exceeding max_players
				visible                                        1

				// Skip intros:
				waiting_for_players_spawning_enabled           1
				waiting_for_players_countdown_seconds          0
				waiting_for_players_timeout_seconds            1
				character_select_time_max                      0.0
				character_select_time_min                      0.0
				survival_enable_gladiator_intros               0
				jump_from_plane_enabled                        0

				// No circle:
				sur_circle_start_paused                        1

				// Can change loadouts:
				dev_loadout_changeable_at_any_time             1
				sur_dev_unrestricted_character_changes         1
				character_reselect_enabled                     1
				charselect_enabled                             1

				// Bots:
				sur_bots_spawn_with_random_weapons             1
				
				//General Gamemode Settings
				match_ending_enabled                           0
				max_teams                                      1
				max_players                                    3
				min_players                                    1
				
				// Firing Range:
				survival_firingrange                           1
				staging_ultimates_enabled                      1
				survival_staging_area_enabled                  0
				//survival_infinite_ammo                       1
				
				pin_match_type                                 firing_range
			}
		}

		///////////////////////////////////
		///////////   SURVIVAL  ///////////
		///////////////////////////////////

		survival
		{
			inherit defaults
			vars
			{
				visible                                        0
				battlechatter_enabled                          1
				name                                           #PL_PLAY_APEX
				description                                    #PL_SURVIVAL_SQUADS_DESC
				abbreviation                                   #PL_PLAY_APEX

				pin_match_type                                 survival
				enable_nessies                                 1
				max_teams                                      20
				max_players                                    60
				min_players                                    60
				survival_shields                               1
				is_ranked_game                                 0
				player_revive_enabled                          1
				enable_apex_screens                            1
				skydive_ziplines_enabled                       1
			}
			gamemodes { survival { maps {
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}

		///////////////////////////////////
		/////////// CANYONLANDS ///////////
		///////////////////////////////////

		defaults
		{
			vars
			{
			}
		}

		ranked
		{
			inherit defaults
			vars
			{
				panel_image                                    panel_worlds_edge
				visible                                        1
				battlechatter_enabled                          1
				name                                           #PL_Ranked_Leagues
				description                                    #PL_survival_ranked_desc
				abbreviation                                   #PL_Ranked_Leagues
				map_name                                       #MP_RR_DESERTLANDS_64K_X_64K
				visible_schedule_block_0                       "2021-06-15 10:00:00 -07:00 | 2021-12-03 10:00:00 -07:00"
				image                                          ranked_2
				video                                          ranked_2
				max_teams                                      20
				max_players                                    60
				min_players                                    60
				survival_shields                               1
				freelance_enabled                              1
				is_ranked_game                                 1
				ui_slot                                        regular_2
				pin_match_type                                 survival
				player_revive_enabled                          1
				enable_apex_screens                            1
				skydive_ziplines_enabled                       1
			}
			gamemodes { survival { maps {
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}

		///////////////////////////////////
		/////////////  LTMs  //////////////
		///////////////////////////////////

		FallLTM
		{
			inherit defaults
			vars
			{
				name                                           #SHADOW_SQUAD_MODE
				description                                    #SHADOW_SQUAD_MODE_DESC
				abbreviation                                   #SHADOW_SQUAD_MODE_ABOUT
				image                                          shadow_squad
				video                                          shadow_squad
				visible                                        1
				show_ltm_about_button                          1
				max_teams                                      60
				max_players                                    60
				min_players                                    60
				survival_shields                               1
				freelance_enabled                              1
				is_ranked_game                                 0
				//ui_slot                                      ltm
				mode_fall_ltm                                  1
				evil_leviathans                                1
				player_revive_enabled                          0
				battlechatter_enabled                          1
				showLTMAboutButton                             1
				character_select_time_max                      4.0
				character_select_time_min                      4.0
			}
			gamemodes { survival { maps {
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
			} } }
		}
		
		duos
		{
			inherit defaults
			vars
			{
				name                                           #PL_DES_DUO
				description                                    #PL_DES_DUO_SHORT
				abbreviation                                   #PL_DES_DUO_LONG
				image                                          duos
				video                                          duos
				sur_bots_spawn_with_random_weapons             1
				enable_nessies                                 1
				max_teams                                      30
				max_players                                    60
				min_players                                    60
				survival_shields                               1
				freelance_enabled                              1
				visible                                        1
				is_ranked_game                                 0
				player_revive_enabled                          1
				enable_apex_screens                            1
				showLTMAboutButton                             1
				//ui_slot                                      ltm
				
				character_select_time_max                      6.0
				character_select_time_min                      6.0

				pin_match_type duo
			}
			gamemodes { survival { maps {
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}
		
		custom_tdm
		{
			inherit defaults
			vars
			{
				//ui_slot                                      regular_2
				image                                          worlds_edge
				video                                          worlds_edge
				panel_image                                    panel_worlds_edge
				visible                                        1
				battlechatter_enabled                          1
				name                                           custom_tdm
				description                                    "You, against them, in a variety of gamemodes"
				abbreviation                                   "Team Deathmatch"
				lobbytitle                                     "Team Deathmatch"

				pin_match_type                                 survival
				enable_nessies                                 0
				max_teams                                      2
				max_players                                    12
				min_players                                    6

				survival_shields                               1
				skydive_ziplines_enabled                       0
				
				//TDM Settings
				survival_jumpkit_enabled                       1
				survival_wallrun_enabled                       1
				survival_infinite_ammo                         1
				survival_custom_deploy                         1
				replay_enabled                                 1
				replay_delay                                   2
				default_shield_hp                              75
				ground_loot_enable                             0
				lootbin_loot_enable                            0

				//whitelisted_weapon_0                         "mp_weapon_mastiff"

				// Intro Settings:
				character_select_time_min                      3
				character_select_time_max                      3
				charselect_picking_delay_after_all             0
				survival_enable_squad_intro                    0
				survival_enable_gladiator_intros               0

				jump_from_plane_enabled                        0
				match_ending_enabled                           0
				sur_circle_start_paused                        1


			}
			gamemodes { custom_tdm { maps {
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}
		
		custom_tdm_tps
		{
			inherit custom_tdm
			vars
			{
				thirdperson_match                              1
			}
			gamemodes { custom_tdm { maps {
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}
		
		survival_dev
		{
			inherit survival
			vars
			{
				// Skip intros:
				waiting_for_players_spawning_enabled           1
				waiting_for_players_countdown_seconds          0
				waiting_for_players_timeout_seconds            1
				character_select_time_max                      0.0
				character_select_time_min                      0.0
				survival_enable_gladiator_intros               0
				jump_from_plane_enabled                        0
				// No circle:
				sur_circle_start_paused                        1
				// Can change loadouts:
				dev_loadout_changeable_at_any_time             1
				sur_dev_unrestricted_character_changes         1
				// Bots:
				sur_bots_spawn_with_random_weapons             1
				match_ending_enabled                           0
			}
			gamemodes { survival { maps {
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}

		dev_default
		{
			inherit survival_dev
			vars
			{
				// The "cmdlineMapLoad" var here makes this playlist be the default in dev:
				cmdlineMapLoad                                 1
				// R5DEV-196963
				reconnect_disabled                             1
			}
			gamemodes { survival { maps {
				mp_rr_canyonlands_64k_x_64k                    1
				mp_rr_canyonlands_mu1                          1
				mp_rr_desertlands_64k_x_64k                    1
				mp_rr_desertlands_64k_x_64k_nx                 1
				mp_rr_canyonlands_mu1_night                    1
				mp_rr_canyonlands_staging                      1
			} } }
		}
		
		menufall
		{
			vars
			{
				menu_fall_ltm                                  1
			}

			gamemodes { survival { maps {
				mp_lobby                                       1
			} } }
		}

// END OF MP GAMEMODES LINE ----------------------------------------------------

		///////////////////////////////////
		//////////////  DEV  //////////////
		///////////////////////////////////
	}
	"LocalizedStrings"
	{
	  "lang"
		{
			"Language" "english"
			"Tokens"
			{
				"MP_RR_DESERTLANDS_64K_X_64K_NX" "World's Edge After Dark"
				"WORLDS_EDGE_NIGHT" "SHADOWFALL WORLD'S EDGE"
				"WORLDS_EDGE_NIGHT_DESC" "Dead Legends respawn as Shadows.\nSurvive and escape with final 10 Legends."
				"Kings_Canyon_OG" "Kings Canyon"
				"KC_MU1" "Kings Canyon Season 2"
				"KCAD" "Kings Canyon After Dark"
				"Playtest" "Playtest"
				"Playtest_Only" "Playtest"
				"BETA_BUILD_WATERMARK" "R5Reloaded v1.6-beta"
			}
		}
	}
	"KVFileOverrides"
	{
		
	}
}

Does not work on lists of objects

Some of the files I am parsing have objects inside of a list and it throws [ vdf.parse: expected openning bracket ] as an error pointing to the line with [

"Object"
{
    "Key" "Val"
    "Object"
    [ // <-- Error points to this line
        {
            "Object"
            {
                "Key" "Val"
            }
            "Key" "Val"
        }
        {
            "Object"
            {
                "Key" "Val"
            }
            "Key" "Val"
        }
    ]
}

Fails to parse gameinfo.txt files

Attempting to parse a Source 2013 gameinfo.txt file will fail due to '+' characters in some of the subkeys in the SearchPaths key. Here's an example from Team Fortress 2's gameinfo.txt:

"SearchPaths"
{

	// First, mount all user customizations.  This will search for VPKs and subfolders
	// and mount them in alphabetical order.  The easiest way to distribute a mod is to
	// pack up the custom content into a VPK.  To "install" a mod, just drop it in this
	// folder.
	//
	// Note that this folder is scanned only when the game is booted.
	"game+mod+custom_mod"	"tf/custom/*"

Here, the parser should at least be capable of registering game+mod+custom_mod as a key, but ideally it should separate it into 3 keys for ease-of-use, like so:
{ "game": "tf/custom/*", "mod": "tf/custom/*", "custom_mod": "tf/custom/*" }

Test fails with new Python 3.11

=================================== FAILURES ===================================
__________________________ BinaryVDF.test_loads_utf16 __________________________
self = <tests.test_binary_vdf.BinaryVDF testMethod=test_loads_utf16>
    def test_loads_utf16(self):
>       self.assertEqual({'aaa': b'b\x00b\x00\xff\xffb\x00b\x00'.decode('utf-16le')}, vdf.binary_loads(b'\x05aaa\x00b\x00b\x00\xff\xffb\x00b\x00\x00\x00\x08'))
E       AssertionError: {'aaa': 'bb\uffffbb'} != {'aaa': 'ๆˆ€ๆˆ€\uffffๆˆ€ๆˆ€'}
E       - {'aaa': 'bb\uffffbb'}
E       ?          ^^      ^^
E       
E       + {'aaa': 'ๆˆ€ๆˆ€\uffffๆˆ€ๆˆ€'}
E       ?          ^^      ^^
tests/test_binary_vdf.py:188: AssertionError
=========================== short test summary info ============================
FAILED tests/test_binary_vdf.py::BinaryVDF::test_loads_utf16 - AssertionError...
========================= 1 failed, 98 passed in 0.17s =========================
  • Python version: 3.11.0rc1
  • OS: Fedora 37, Fedora Rawhide
  • Full build log

Error when parsing Dota 2 item schema

I'm trying to write a script that uses information from Dota 2's item schema, but when I try to use the vdf module to parse the schema it gives me this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.9/site-packages/vdf/__init__.py", line 208, in load
    return parse(fp, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/vdf/__init__.py", line 175, in parse
    stack[-1][key] = _unescape(val) if escaped else val
TypeError: 'str' object does not support item assignment

I downloaded the schema from here (and I got that URL from Steam's WebAPI), and I get the same error on the PyPI and GitHub versions of the vdf module.

I appreciate any insight or help!

"One too many closing parenthasis" error when there isn't any extra closing parenthasis

This was when I was using vdf.parse() on a large .res file (around 5k lines). At first, I kept getting the error when it got to a key like this:

TestParentKey
{
}

The error mentions the line where the closing bracket is.
After removing the problem key, the error then mentioned the closing bracket of the parent key for all the other keys. A VSCode extension that also supports VDF files can collapse the file just fine, and shows there doesn't seem to be any extra closing brackets.

I can provide the file that is causing this if need be.

Arch User Repository packages

I packaged python-vdf for Arch GNU/Linux in AUR:

Packages: python2-vdf-git, python-vdf-git, python2-vdf, python-vdf

Packages suffixed with -git are built from git source, others are built from the lastest release tarball

Packages prefixed with python- are built for Python 3.x, and prefixed with python2- are built for Python 2.x

You can install them using any AUR helper (the recommended one is pacaur):

pacaur -S python-vdf

You can also install them manually:

git clone https://aur.archlinux.org/python-vdf.git
cd python-vdf
makepkg -sic

It would be great if you added them to your readme

Add Type Hinting support/ Implement PEP 561

It would be useful for users who wish to use tools such as MyPy to have typing support. Ideally, the calls would be fully type-hinted, and with the inclusion of py.typed, the package would be fully compatible with PEP 561.

If instead, you prefer to do it using stubs, as noted in https://peps.python.org/pep-0561/#stub-only-packages , I have generated some stubs that i use in projects i help maintain. They are available at https://github.com/ABaumher/VDF_Typing . If you have a proper destination for the stubs i can probably draft up a Pull Request to add them in.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.