diff --git a/AMBuilder b/AMBuilder index 033d025c..b79020ae 100644 --- a/AMBuilder +++ b/AMBuilder @@ -70,6 +70,8 @@ for sdk_target in MMSPlugin.sdk_targets: 'src/buttonwatch.cpp', 'src/topdefender.cpp', 'src/idlemanager.cpp', + 'src/cvarwhitelist.cpp', + 'src/cfgparser.cpp', 'src/mapmigrations.cpp', 'sdk/entity2/entitysystem.cpp', 'sdk/entity2/entityidentity.cpp', diff --git a/CS2Fixes.vcxproj b/CS2Fixes.vcxproj index d82eb31b..9b0b1648 100644 --- a/CS2Fixes.vcxproj +++ b/CS2Fixes.vcxproj @@ -213,6 +213,8 @@ + + @@ -291,6 +293,8 @@ + + diff --git a/CS2Fixes.vcxproj.filters b/CS2Fixes.vcxproj.filters index 23ee92a5..ecb355ea 100644 --- a/CS2Fixes.vcxproj.filters +++ b/CS2Fixes.vcxproj.filters @@ -179,6 +179,12 @@ Source Files + + Source Files + + + Source Files + Source Files\utils @@ -394,6 +400,12 @@ Header Files + + Header Files + + + Header Files + Header Files\cs2_sdk\entity diff --git a/PackageScript b/PackageScript index 6e96f562..b68cbc84 100644 --- a/PackageScript +++ b/PackageScript @@ -115,7 +115,9 @@ for task in MMSPlugin.binaries: builder.AddCopy(os.path.join('configs', 'admins.jsonc.example'), configs_folder) builder.AddCopy(os.path.join('configs', 'discordbots.jsonc.example'), configs_folder) builder.AddCopy(os.path.join('configs', 'maplist.jsonc.example'), configs_folder) + builder.AddCopy(os.path.join('configs', 'cvar_whitelist.jsonc.example'), configs_folder) builder.AddCopy(os.path.join('cfg', MMSPlugin.metadata['name'], 'cs2fixes.cfg'), cfg_folder) + builder.AddCopy(os.path.join('cfg', MMSPlugin.metadata['name'], 'server.cfg.example'), cfg_folder) builder.AddCopy(os.path.join('cfg', MMSPlugin.metadata['name'], 'maps', 'de_somemap.cfg'), mapcfg_folder) builder.AddCopy(os.path.join('configs', 'zr', 'playerclass.jsonc.example'), zr_folder) builder.AddCopy(os.path.join('configs', 'zr', 'weapons.cfg.example'), zr_folder) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index e7cdac87..3efc1a4a 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -24,6 +24,7 @@ cs2f_prevent_using_players 0 // Whether to prevent +use from hitting players ( cs2f_map_steamids_enable 0 // Whether to make Steam ID's available to maps cs2f_fix_game_bans 0 // Whether to fix CS2 game bans spreading to all new joining players cs2f_free_armor 0 // Whether kevlar (1+) and/or helmet (2) are given automatically +cs2f_cvarwhitelist_enable 0 // Whether to enable the custom ConVar whitelist for maps cs2f_block_particle_msgs 0 // Whether to block CUserMsg_ParticleManager messages to fix lag/crashes, experimental cs2f_disable_setmodel 0 // Whether to disable SetModel usage from maps (custom input, cs_script function) cs2f_allow_duck_spam 0 // Whether to allow duck spamming by removing the duck slowdown, clients will only partially predict [0 = disabled, 1 = both teams, 2 = T only, 3 = CT only] diff --git a/cfg/cs2fixes/server.cfg.example b/cfg/cs2fixes/server.cfg.example new file mode 100644 index 00000000..927a578f --- /dev/null +++ b/cfg/cs2fixes/server.cfg.example @@ -0,0 +1,3 @@ +// This config is executed every map start like cfg/server.cfg, but fixes a bug for properly bypassing the ConVar whitelist +// Like exec, use exec_custom to execute another cfg through this custom cfg parser: +// exec_custom gamemode_casual_custom diff --git a/configs/cvar_whitelist.jsonc.example b/configs/cvar_whitelist.jsonc.example new file mode 100644 index 00000000..e2efb939 --- /dev/null +++ b/configs/cvar_whitelist.jsonc.example @@ -0,0 +1,563 @@ +{ + // Since maps can change cvars that are enabled here, make sure they all get reset to desired values on map change by server config(s)! + + /* Map specific overrides can also be set up as so: + "ze_my_first_ze_map": + { + "sv_airaccelerate": false, + "sv_noclipspeed": true + }, + "ze_last_man_standing_p": + { + "zr_infect_spawn_mz_ratio": true + }, + */ + + // Default whitelist, from workshop_cvar_whitelist.txt + // We disable several of these in our default config, because they don't make sense to be whitelisted, explanations are commented + "ammo_grenade_limit_default": true, + "ammo_grenade_limit_flashbang": true, + "ammo_grenade_limit_total": true, + "ammo_item_limit_healthshot": true, + "annotation_auto_load": true, + "annotation_load": true, + "bot_add": false, // Not suitable for Zombie Escape servers, bots usually not supported outside of debug + "bot_add_ct": false, // Not suitable for Zombie Escape servers, bots usually not supported outside of debug + "bot_add_t": false, // Not suitable for Zombie Escape servers, bots usually not supported outside of debug + "bot_allow_grenades": true, + "bot_allow_machine_guns": true, + "bot_allow_pistols": true, + "bot_allow_rifles": true, + "bot_allow_rogues": true, + "bot_allow_shotguns": true, + "bot_allow_snipers": true, + "bot_allow_sub_machine_guns": true, + "bot_auto_vacate": true, + "bot_autodifficulty_threshold_high": true, + "bot_autodifficulty_threshold_low": true, + "bot_chatter": true, + "bot_controllable": true, + "bot_coop_idle_max_vision_distance": true, + "bot_crouch": true, + "bot_defer_to_human_goals": true, + "bot_defer_to_human_items": true, + "bot_difficulty": true, + "bot_dont_shoot": true, + "bot_eco_limit": true, + "bot_flipout": true, + "bot_force_duck": true, + "bot_freeze": true, + "bot_ignore_enemies": true, + "bot_ignore_players": true, + "bot_join_after_player": true, + "bot_join_delay": true, + "bot_join_in_warmup": true, + "bot_join_team": true, + "bot_kick": true, + "bot_kill": true, + "bot_knives_only": true, + "bot_max_visible_smoke_length": true, + "bot_max_vision_distance_override": true, + "bot_mimic": true, + "bot_prefix": true, + "bot_quota": false, // Not suitable for Zombie Escape servers, bots usually not supported outside of debug + "bot_quota_mode": true, + "bot_stop": true, + "bot_walk": true, + "bot_zombie": true, + "buddha": true, + "buddha_reset_hp": true, + "callvote": true, + "cash_player_bomb_defused": true, + "cash_player_bomb_planted": true, + "cash_player_damage_hostage": true, + "cash_player_get_killed": true, + "cash_player_interact_with_hostage": true, + "cash_player_killed_enemy_default": true, + "cash_player_killed_enemy_factor": true, + "cash_player_killed_hostage": true, + "cash_player_killed_teammate": true, + "cash_player_rescued_hostage": true, + "cash_player_respawn_amount": true, + "cash_team_bonus_shorthanded": true, + "cash_team_elimination_bomb_map": true, + "cash_team_elimination_hostage_map_ct": true, + "cash_team_elimination_hostage_map_t": true, + "cash_team_hostage_alive": true, + "cash_team_hostage_interaction": true, + "cash_team_loser_bonus": true, + "cash_team_loser_bonus_consecutive_rounds": true, + "cash_team_per_dead_enemy": true, + "cash_team_planted_bomb_but_defused": true, + "cash_team_rescued_hostage": true, + "cash_team_terrorist_win_bomb": true, + "cash_team_win_by_defusing_bomb": true, + "cash_team_win_by_hostage_rescue": true, + "cash_team_win_by_time_running_out_bomb": true, + "cash_team_win_by_time_running_out_hostage": true, + "cl_crosshair_drawoutline": true, + "cl_crosshair_dynamic_maxdist_splitratio": true, + "cl_crosshair_dynamic_splitalpha_innermod": true, + "cl_crosshair_dynamic_splitalpha_outermod": true, + "cl_crosshair_dynamic_splitdist": true, + "cl_crosshair_friendly_warning": true, + "cl_crosshair_outlinethickness": true, + "cl_crosshair_recoil": true, + "cl_crosshair_sniper_show_normal_inaccuracy": true, + "cl_crosshair_sniper_width": true, + "cl_crosshair_t": true, + "cl_crosshairalpha": true, + "cl_crosshaircolor": true, + "cl_crosshaircolor_b": true, + "cl_crosshaircolor_g": true, + "cl_crosshaircolor_r": true, + "cl_crosshairdot": true, + "cl_crosshairgap": true, + "cl_crosshairgap_useweaponvalue": true, + "cl_crosshairsize": true, + "cl_crosshairstyle": true, + "cl_crosshairthickness": true, + "cl_crosshairusealpha": true, + "cl_draw_only_deathnotices": true, + "cl_drawhud": true, + "cl_drawhud_force_deathnotices": true, + "cl_frametime_summary_report_detailed": true, + "cl_hud_color": true, + "cl_hud_radar_scale": true, + "cl_hud_telemetry_frametime_show": true, + "cl_lock_camera": true, + "cl_player_ragdolls_collide": true, + "cl_prefer_lefthanded": true, + "cl_radar_always_centered": true, + "cl_radar_icon_scale_min": true, + "cl_radar_rotate": true, + "cl_radar_scale": true, + "cl_radar_square_with_scoreboard": true, + "cl_showfps": true, + "cl_teamcounter_playercount_instead_of_avatars": true, + "cl_teamid_overhead_colors_show": true, + "contributionscore_assist": true, + "contributionscore_assist_reqs": true, + "contributionscore_bomb_defuse_major": true, + "contributionscore_bomb_defuse_minor": true, + "contributionscore_bomb_exploded": true, + "contributionscore_bomb_planted": true, + "contributionscore_cash_bundle": true, + "contributionscore_crate_break": true, + "contributionscore_hostage_kill": true, + "contributionscore_hostage_rescue_major": true, + "contributionscore_hostage_rescue_minor": true, + "contributionscore_kill": true, + "contributionscore_kill_factor": true, + "contributionscore_kill_reqs": true, + "contributionscore_objective_kill": true, + "contributionscore_participation": true, + "contributionscore_suicide": true, + "contributionscore_team_kill": true, + "crosshair": true, + "custom_bot_difficulty": true, + "disconnect": true, + "dsp_volume": true, + "echo": true, + "ent_create": true, + "ent_fire": true, + "ent_fire_output": true, + "ent_setname": true, + "exec": true, + "execifexists": true, + "ff_damage_bullet_penetration": true, + "ff_damage_reduction_bullets": true, + "ff_damage_reduction_grenade": true, + "ff_damage_reduction_grenade_self": true, + "ff_damage_reduction_other": true, + "fps_max": true, + "game_alias": false, // Server command, should not be controlled by maps + "game_mode": false, // Server setting, should not be controlled by maps + "game_type": false, // Server setting, should not be controlled by maps + "give": true, + "god": true, + "healthshot_allow_use_at_full": true, + "healthshot_health": true, + "healthshot_healthboost_damage_multiplier": true, + "healthshot_healthboost_speed_multiplier": true, + "healthshot_healthboost_time": true, + "hinttext_displaytime": true, + "host_timescale": true, + "host_writeconfig_with_prompt": true, + "hostage_debug": true, + "hostname": false, // Server setting, should not be controlled by maps + "hud_scaling": true, + "hud_showtargetid": true, + "inferno_child_spawn_max_depth": true, + "inferno_max_flames": true, + "inferno_max_range": true, + "log_color": false, // Server command, should not be controlled by maps + "log_flags": false, // Server command, should not be controlled by maps + "log_verbosity": false, // Server command, should not be controlled by maps + "map_workshop": false, // Server command, should not be executed by maps + "molotov_throw_detonate_time": true, + "mp_afterroundmoney": true, + "mp_allowspectators": true, + "mp_anyone_can_pickup_c4": true, + "mp_autokick": false, // Server setting, should not be controlled by maps + "mp_autoteambalance": false, // Not suitable for Zombie Escape servers + "mp_bot_ai_bt": true, + "mp_bot_ai_bt_clear_cache": true, + "mp_buy_allow_grenades": true, + "mp_buy_allow_guns": true, + "mp_buy_anywhere": true, + "mp_buy_during_immunity": true, + "mp_buytime": true, + "mp_c4_cannot_be_defused": true, + "mp_c4timer": true, + "mp_consecutive_loss_max": true, + "mp_coop_force_join_t": true, + "mp_coopmission_bot_difficulty_offset": true, + "mp_ct_default_grenades": true, + "mp_ct_default_melee": true, + "mp_ct_default_primary": true, + "mp_ct_default_secondary": true, + "mp_damage_headshot_only": true, + "mp_damage_scale_ct_body": true, + "mp_damage_scale_ct_head": true, + "mp_damage_scale_t_body": true, + "mp_damage_scale_t_head": true, + "mp_damage_vampiric_amount": true, + "mp_death_drop_c4": true, + "mp_death_drop_defuser": true, + "mp_death_drop_grenade": true, + "mp_death_drop_gun": true, + "mp_death_drop_healthshot": true, + "mp_deathcam_skippable": true, + "mp_default_team_winner_no_objective": true, + "mp_defuser_allocation": true, + "mp_disconnect_kills_bots": false, // Server setting, should not be controlled by maps + "mp_disconnect_kills_players": false, // Server setting, should not be controlled by maps + "mp_display_kill_assists": true, + "mp_dm_bonus_percent": true, + "mp_dm_bonusweapon_dogtags": true, + "mp_dm_dogtag_score": true, + "mp_dm_kill_base_score": true, + "mp_dm_teammode": true, + "mp_dm_teammode_bonus_score": true, + "mp_dm_teammode_dogtag_score": true, + "mp_dm_teammode_kill_score": true, + "mp_dogtag_despawn_on_killer_death": true, + "mp_dogtag_despawn_time": true, + "mp_dogtag_pickup_rule": true, + "mp_drop_grenade_enable": true, + "mp_drop_knife_enable": true, + "mp_economy_reset_rounds": true, + "mp_endmatch_votenextleveltime": false, // Server setting, should not be controlled by maps + "mp_endmatch_votenextmap": false, // Server setting, should not be controlled by maps + "mp_endmatch_votenextmap_keepcurrent": false, // Server setting, should not be controlled by maps + "mp_equipment_reset_rounds": true, + "mp_force_pick_time": false, // Server setting, should not be controlled by maps + "mp_forcecamera": true, + "mp_forcerespawn": true, + "mp_fraglimit": false, // Server setting, should not be controlled by maps + "mp_free_armor": false, // Breaks buy menu rebuys, cs2f_free_armor doesn't + "mp_freezetime": true, + "mp_friendlyfire": true, + "mp_give_player_c4": true, + "mp_global_damage_per_second": true, + "mp_guardian_ai_bt_difficulty_adjust_wave_interval": true, + "mp_guardian_ai_bt_difficulty_cap_beginning_round": true, + "mp_guardian_ai_bt_difficulty_initial_value": true, + "mp_guardian_ai_bt_difficulty_max_next_level_bots": true, + "mp_guardian_bomb_plant_custom_x_mark_location": true, + "mp_guardian_bot_money_per_wave": true, + "mp_guardian_player_dist_max": true, + "mp_guardian_player_dist_min": true, + "mp_guardian_special_kills_needed": true, + "mp_guardian_special_weapon_needed": true, + "mp_guardian_target_site": true, + "mp_halftime": false, // Not suitable for Zombie Escape servers + "mp_halftime_pausetimer": true, + "mp_hostagepenalty": true, + "mp_hostages_max": true, + "mp_hostages_rescuetime": true, + "mp_hostages_spawn_force_positions": true, + "mp_hostages_spawn_force_positions_xyz": true, + "mp_hostages_spawn_same_every_round": true, + "mp_humanteam": false, // Not suitable for Zombie Escape servers + "mp_ignore_round_win_conditions": false, // Not suitable for Zombie Escape servers + "mp_items_prohibited": true, + "mp_join_grace_time": false, // Not suitable for Zombie Escape servers + "mp_limitteams": false, // Not suitable for Zombie Escape servers + "mp_match_can_clinch": false, // Server setting, should not be controlled by maps + "mp_match_end_changelevel": false, // Server setting, should not be controlled by maps + "mp_match_end_restart": false, // Server setting, should not be controlled by maps + "mp_match_restart_delay": false, // Server setting, should not be controlled by maps + "mp_max_armor": true, + "mp_maxmoney": true, + "mp_maxrounds": false, // Server setting, should not be controlled by maps + "mp_only_cts_rescue_hostages": true, + "mp_plant_c4_anywhere": true, + "mp_playercashawards": false, // Not suitable for Zombie Escape servers + "mp_promoted_item_enabled": true, + "mp_randomspawn": true, + "mp_randomspawn_dist": true, + "mp_randomspawn_los": true, + "mp_respawn_immunitytime": true, + "mp_respawn_on_death_ct": false, // Not suitable for Zombie Escape servers + "mp_respawn_on_death_t": false, // Not suitable for Zombie Escape servers + "mp_respawnwavetime_ct": true, + "mp_respawnwavetime_t": true, + "mp_restartgame": false, // Also resets timeleft, which should not be controlled by maps, just use a nuke or an info_map_parameters>FireWinCondition>10 input (won't add score to either team) + "mp_retake_ct_loadout_bonus_card": true, + "mp_retake_ct_loadout_bonus_card_availability": true, + "mp_retake_ct_loadout_default_pistol_round": true, + "mp_retake_ct_loadout_enemy_card": true, + "mp_retake_ct_loadout_full_buy_round": true, + "mp_retake_ct_loadout_light_buy_round": true, + "mp_retake_ct_loadout_upgraded_pistol_round": true, + "mp_retake_max_consecutive_rounds_same_target_site": true, + "mp_retake_t_loadout_bonus_card": true, + "mp_retake_t_loadout_bonus_card_availability": true, + "mp_retake_t_loadout_default_pistol_round": true, + "mp_retake_t_loadout_enemy_card": true, + "mp_retake_t_loadout_full_buy_round": true, + "mp_retake_t_loadout_light_buy_round": true, + "mp_retake_t_loadout_upgraded_pistol_round": true, + "mp_round_restart_delay": true, + "mp_roundtime": true, + "mp_roundtime_defuse": true, + "mp_roundtime_deployment": true, + "mp_roundtime_hostage": true, + "mp_solid_enemies": true, + "mp_solid_teammates": true, + "mp_spawnprotectiontime": false, // Server setting, should not be controlled by maps + "mp_spectators_max": true, + "mp_starting_losses": true, + "mp_startmoney": true, + "mp_suicide_penalty": true, + "mp_t_default_grenades": true, + "mp_t_default_melee": true, + "mp_t_default_primary": true, + "mp_t_default_secondary": true, + "mp_tagging_scale": false, // Server setting, should not be controlled by maps + "mp_taser_recharge_time": true, + "mp_team_intro_time": false, // Server setting, should not be controlled by maps + "mp_teamcashawards": true, + "mp_teammatchstat_holdtime": true, + "mp_teammates_are_enemies": true, + "mp_teamname_1": true, + "mp_teamname_2": true, + "mp_technical_timeout_duration_s": true, + "mp_technical_timeout_per_team": true, + "mp_timelimit": false, // Server setting, should not be controlled by maps + "mp_use_respawn_waves": false, // Not suitable for Zombie Escape servers + "mp_warmup_end": true, + "mp_warmup_items_drop_policy": true, + "mp_warmup_items_nocost": true, + "mp_warmup_items_nocount_policy": true, + "mp_warmup_offline_enabled": true, + "mp_warmup_online_enabled": true, + "mp_warmup_pausetimer": true, + "mp_warmuptime": true, + "mp_warmuptime_all_players_connected": true, + "mp_warmuptime_match_cancelled": true, + "mp_weapon_self_inflict_amount": true, + "mp_weapons_allow_heavy": true, + "mp_weapons_allow_heavyassaultsuit": true, + "mp_weapons_allow_map_placed": true, + "mp_weapons_allow_pistols": true, + "mp_weapons_allow_rifles": true, + "mp_weapons_allow_smgs": true, + "mp_weapons_allow_typecount": true, + "mp_weapons_allow_zeus": true, + "mp_weapons_max_gun_purchases_per_weapon_per_match": true, + "mp_win_panel_display_time": true, + "noclip": true, + "player_ping_token_cooldown": true, + "r_csgo_render_decals": true, + "r_csgo_render_decals_on_translucent": true, + "r_decals_overide_fadestarttime_params": true, + "r_drawviewmodel": true, + "r_fullscreen_gamma": true, + "regenerate_weapon_skins": true, + "restart": true, + "safezonex": true, + "safezoney": true, + "say": true, + "say_team": true, + "setang": true, + "setpos": true, + "slot1": true, + "slot2": true, + "slot3": true, + "slot4": true, + "slot5": true, + "slot6": true, + "slot7": true, + "slot8": true, + "slot9": true, + "snd_deathcamera_volume": true, + "snd_gamevolume": true, + "snd_headphone_eq": true, + "snd_mapobjective_volume": true, + "snd_menumusic_volume": true, + "snd_musicvolume": true, + "snd_mvp_volume": true, + "snd_roundaction_volume": true, + "snd_roundend_volume": true, + "snd_roundstart_volume": true, + "snd_spatialize_lerp": true, + "snd_steamaudio_enable_perspective_correction": true, + "snd_tensecondwarning_volume": true, + "spawn_group_load": true, + "spawn_group_unload": true, + "speaker_config": true, + "spec_freeze_deathanim_time": true, + "spec_freeze_time": true, + "spec_freeze_time_lock": true, + "spec_freeze_traveltime": true, + "spec_replay_bot": true, + "spec_replay_enable": false, // Server setting, should not be controlled by maps + "spec_replay_leadup_time": true, + "subclass_create": true, + "sv_accelerate": true, + "sv_accelerate_use_weapon_speed": true, + "sv_airaccelerate": true, + "sv_allow_annotations_access_level": true, + "sv_allow_votes": false, // Server setting, should not be controlled by maps + "sv_alltalk": false, // Server setting, should not be controlled by maps + "sv_alternateticks": true, + "sv_auto_adjust_bot_difficulty": true, + "sv_auto_full_alltalk_during_warmup_half_end": true, + "sv_autobunnyhopping": true, + "sv_autobuyammo": true, + "sv_autoexec_mapname_cfg": true, + "sv_bot_buy_decoy_weight": true, + "sv_bot_buy_flash_weight": true, + "sv_bot_buy_grenade_chance": true, + "sv_bot_buy_hegrenade_weight": true, + "sv_bot_buy_molotov_weight": true, + "sv_bot_buy_smoke_weight": true, + "sv_bots_get_easier_each_win": true, + "sv_bounce": true, + "sv_buy_status_override": true, + "sv_cheats": false, // Server setting, should not be controlled by maps + "sv_deadtalk": false, // Server setting, should not be controlled by maps + "sv_disable_immunity_alpha": true, + "sv_disable_radar": true, + "sv_disable_teamselect_menu": false, // Server setting, should not be controlled by maps + "sv_disconnected_players_cleanup_delay": false, // Server setting, should not be controlled by maps + "sv_enablebunnyhopping": true, + "sv_extract_ammo_from_dropped_weapons": true, + "sv_falldamage_scale": true, + "sv_falldamage_to_below_player_multiplier": true, + "sv_falldamage_to_below_player_ratio": true, + "sv_friction": true, + "sv_game_mode_flags": false, // Server setting, should not be controlled by maps + "sv_gameinstructor_disable": true, + "sv_gameinstructor_enable": true, + "sv_give_item": true, + "sv_gravity": true, + "sv_grenade_trajectory_prac_pipreview": true, + "sv_grenade_trajectory_prac_trailtime": true, + "sv_grenade_trajectory_time_spectator": true, + "sv_guardian_extra_equipment_ct": true, + "sv_guardian_extra_equipment_t": true, + "sv_guardian_refresh_ammo_for_items_on_waves": true, + "sv_guardian_spawn_health_ct": true, + "sv_guardian_spawn_health_t": true, + "sv_health_approach_enabled": true, + "sv_health_approach_speed": true, + "sv_hegrenade_damage_multiplier": true, + "sv_hegrenade_radius_multiplier": true, + "sv_hide_roundtime_until_seconds": true, + "sv_highlight_distance": true, + "sv_highlight_duration": true, + "sv_human_autojoin_team": false, // Server setting, should not be controlled by maps + "sv_ignoregrenaderadio": true, + "sv_infinite_ammo": true, + "sv_jump_impulse": true, + "sv_jump_spam_penalty_time": true, + "sv_kick_ban_duration": false, // Server setting, should not be controlled by maps + "sv_ladder_scale_speed": true, + "sv_max_deathmatch_respawns_per_tick": true, + "sv_maxspeed": true, + "sv_maxvelocity": true, + "sv_minimum_desired_chicken_count": true, + "sv_outofammo_indicator": true, + "sv_pure": false, // Server command, should not be controlled by maps + "sv_pure_kick_clients": false, // Server setting, should not be controlled by maps + "sv_radio_throttle_window": false, // Server setting, should not be controlled by maps + "sv_regeneration_force_on": true, + "sv_regeneration_wait_time": true, + "sv_show_team_equipment_force_on": true, + "sv_showbullethits": true, + "sv_showhitregistration": true, + "sv_showimpacts": true, + "sv_showimpacts_penetration": true, + "sv_skirmish_id": true, + "sv_staminajumpcost": true, + "sv_staminalandcost": true, + "sv_staminamax": true, + "sv_staminarecoveryrate": true, + "sv_steamauth_enforce": false, // Server setting, should not be controlled by maps + "sv_stopspeed": true, + "sv_talk_enemy_dead": false, // Server setting, should not be controlled by maps + "sv_talk_enemy_living": false, // Server setting, should not be controlled by maps + "sv_teamid_overhead_maxdist": false, // Server setting, should not be controlled by maps + "sv_teamid_overhead_maxdist_spec": false, // Server setting, should not be controlled by maps + "sv_versus_screen_scene_id": true, + "sv_vote_to_changelevel_before_match_point": false, // Server setting, should not be controlled by maps + "sv_vote_to_changelevel_rndmin": false, // Server setting, should not be controlled by maps + "sv_warmup_to_freezetime_delay": true, + "sv_wateraccelerate": true, + "sv_waterfriction": true, + "tv_delay": false, // Server setting, should not be controlled by maps + "tv_delay1": false, // Server setting, should not be controlled by maps + "viewmodel_fov": true, + "viewmodel_offset_x": true, + "viewmodel_offset_y": true, + "viewmodel_offset_z": true, + "viewmodel_presetpos": true, + "weapon_accuracy_nospread": true, + "weapon_air_spread_scale": true, + "weapon_auto_cleanup_time": true, + "weapon_max_before_cleanup": true, + "weapon_recoil_scale": true, + "weapon_reticle_knife_show": true, + "weapon_sound_falloff_multiplier": true, + "sv_legacy_jump": false, // Server setting, should not be controlled by maps + "radio": true, + "radio1": true, + "radio2": true, + "radio3": true, + "player_ping": true, + "mp_teamlogo_1": true, + "mp_teamlogo_2": true, + "noclip_fixup": true, + "fov_cs_debug": true, + "sv_show_teammate_death_notification": true, + "sv_standable_normal": true, + "sv_walkable_normal": true, + "+jump": true, + "-jump": true, + "+duck": true, + "-duck": true, + "+forward": true, + "-forward": true, + "+back": true, + "-back": true, + "+left": true, + "-left": true, + "+right": true, + "-right": true, + "+sprint": true, + "-sprint": true, + + // Custom stuff + "endround": true, + "cs2f_use_old_push": true, + "cs2f_infinite_reserve_ammo": true, + "cs2f_free_armor": true, + // Often over-abused but still have some legitimate uses, recommend either setting up map specific overrides or just globally enabling these + "zr_infect_spawn_time_min": false, + "zr_infect_spawn_time_max": false, + "zr_infect_spawn_mz_ratio": false +} \ No newline at end of file diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index f3515276..982ff121 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -395,6 +395,13 @@ "library": "server", "windows": "48 8B C4 48 89 58 ? 57 48 81 EC ? ? ? ? 0F 29 70 ? 48 8B FA 0F 29 78 ? 48 8B D9", "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 F4 53 48 89 FB 48 81 EC ? ? ? ? 66 0F 1F 44 00" + }, + // Only called in an if statement by function with "DISALLOWED WORKSHOP CONVAR: %s" string + "IsCommandWhitelisted": + { + "library": "server", + "windows": "48 83 EC ? 4C 8B C2 48 8D 0D ? ? ? ? 48 8D 54 24 ? FF", + "linux": "55 48 89 F2 48 8D 35 ? ? ? ? 48 89 E5 48 83 EC" } }, "Offsets": diff --git a/src/cfgparser.cpp b/src/cfgparser.cpp new file mode 100644 index 00000000..adfe3adf --- /dev/null +++ b/src/cfgparser.cpp @@ -0,0 +1,80 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "cfgparser.h" +#include "commands.h" + +#include + +CCfgParser* g_pCfgParser = nullptr; + +CON_COMMAND_F(exec_custom, " - Execute a cfg through the custom cfg parser", FCVAR_SPONLY | FCVAR_LINKED_CONCOMMAND) +{ + if (args.ArgC() < 2) + { + Message("Usage: exec_custom \n"); + return; + } + + g_pCfgParser->ParseCfg(args[1]); +} + +void CCfgParser::ApplyGameSettings(const char* pszMapName) +{ + // Run plugin cfg + g_pCfgParser->ParseCfg("cs2fixes/cs2fixes"); + + // Run custom server cfg + g_pCfgParser->ParseCfg("cs2fixes/server"); + + if (!V_strcmp(pszMapName, "")) + return; + + // Run map cfg (if present) + // We call ParseCfg indirectly through exec_custom, so any commands within the map cfg will be added to the command buffer after nested executes in previous configs + char cmd[MAX_PATH]; + V_snprintf(cmd, sizeof(cmd), "exec_custom cs2fixes/maps/%s", pszMapName); + g_pEngineServer2->ServerCommand(cmd); +} + +void CCfgParser::ParseCfg(const char* pszCfgPath) +{ + char szPath[MAX_PATH]; + V_snprintf(szPath, sizeof(szPath), "%s/csgo/cfg/%s.cfg", Plat_GetGameDirectory(), pszCfgPath); + std::ifstream cfgFile(szPath); + + if (!cfgFile.is_open()) + { + Message("Unable to open & execute custom cfg file \"%s\"\n", pszCfgPath); + return; + } + + Message("Executing custom cfg file \"%s\"\n", pszCfgPath); + + std::string strCommand; + + while (std::getline(cfgFile, strCommand)) + { + if (!strCommand.empty() && strCommand.back() == '\r') + strCommand.pop_back(); + + if (!strCommand.empty()) + g_pEngineServer2->ServerCommand(strCommand.c_str()); + } +} diff --git a/src/cfgparser.h b/src/cfgparser.h new file mode 100644 index 00000000..78433b7d --- /dev/null +++ b/src/cfgparser.h @@ -0,0 +1,29 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#pragma once + +class CCfgParser +{ +public: + void ApplyGameSettings(const char* pszMapName); + void ParseCfg(const char* pszCfgPath); +}; + +extern CCfgParser* g_pCfgParser; diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 4b3ff5a6..6017f9eb 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -22,10 +22,12 @@ #include "adminsystem.h" #include "appframework/IAppSystem.h" +#include "cfgparser.h" #include "commands.h" #include "common.h" #include "cs_gameevents.pb.h" #include "ctimer.h" +#include "cvarwhitelist.h" #include "detours.h" #include "discord.h" #include "entities.h" @@ -355,6 +357,8 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool g_pIdleSystem = new CIdleSystem(); g_pPanoramaVoteHandler = new CPanoramaVoteHandler(); g_pEWHandler = new CEWHandler(); + g_pConvarWhitelist = new CConVarWhitelist(); + g_pCfgParser = new CCfgParser(); g_pMapMigrations = new CMapMigrations(); RegisterWeaponCommands(); @@ -378,7 +382,7 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool }); // run our cfg - g_pEngineServer2->ServerCommand("exec cs2fixes/cs2fixes"); + g_pCfgParser->ParseCfg("cs2fixes/cs2fixes"); srand(time(0)); @@ -504,6 +508,12 @@ bool CS2Fixes::Unload(char* error, size_t maxlen) delete g_pEWHandler; } + if (g_pConvarWhitelist) + delete g_pConvarWhitelist; + + if (g_pCfgParser) + delete g_pCfgParser; + if (g_pMapMigrations) delete g_pMapMigrations; @@ -1031,8 +1041,22 @@ void CS2Fixes::Hook_CheckTransmit(CCheckTransmitInfo** ppInfoList, int infoCount void CS2Fixes::Hook_ApplyGameSettings(KeyValues* pKV) { - g_pMapVoteSystem->ApplyGameSettings(pKV); - g_pMapMigrations->ApplyGameSettings(pKV); + const char* pszMapName; + uint64 iWorkshopId; + + if (pKV->FindKey("launchoptions") && pKV->FindKey("launchoptions")->FindKey("levelname")) + pszMapName = pKV->FindKey("launchoptions")->GetString("levelname"); + else + pszMapName = ""; + + if (pKV->FindKey("launchoptions") && pKV->FindKey("launchoptions")->FindKey("customgamemode")) + iWorkshopId = pKV->FindKey("launchoptions")->GetUint64("customgamemode"); + else + iWorkshopId = 0; + + g_pCfgParser->ApplyGameSettings(pszMapName); + g_pMapVoteSystem->ApplyGameSettings(pszMapName, iWorkshopId); + g_pMapMigrations->ApplyGameSettings(iWorkshopId); } void CS2Fixes::Hook_CreateWorkshopMapGroup(const char* name, const CUtlStringList& mapList) @@ -1321,14 +1345,6 @@ void CS2Fixes::OnLevelInit(char const* pMapName, { Message("OnLevelInit(%s)\n", pMapName); - // run our cfg - g_pEngineServer2->ServerCommand("exec cs2fixes/cs2fixes"); - - // Run map cfg (if present) - char cmd[MAX_PATH]; - V_snprintf(cmd, sizeof(cmd), "exec cs2fixes/maps/%s", pMapName); - g_pEngineServer2->ServerCommand(cmd); - // Only patch BotNavIgnore while a map is loaded, else adding bots will crash if (V_strcmp(pMapName, "error")) g_CommonPatches[1].PerformPatch(g_GameConfig); diff --git a/src/cvarwhitelist.cpp b/src/cvarwhitelist.cpp new file mode 100644 index 00000000..3fe5a958 --- /dev/null +++ b/src/cvarwhitelist.cpp @@ -0,0 +1,122 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "cvarwhitelist.h" +#include "commands.h" +#include "utils.h" +#undef snprintf +#include "vendor/nlohmann/json.hpp" +#include + +CConVarWhitelist* g_pConvarWhitelist = nullptr; + +CConVar g_cvarConVarWhitelistEnable("cs2f_cvarwhitelist_enable", FCVAR_NONE, "Whether to enable the custom ConVar whitelist for maps", false); + +CON_COMMAND_CHAT_FLAGS(cvarwhitelist_reload, "- Reload the ConVar whitelist config file", ADMFLAG_ROOT) +{ + if (!g_cvarConVarWhitelistEnable.Get()) + return; + + if (g_pConvarWhitelist->LoadConfig()) + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "ConVar whitelist config reloaded!"); + else + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Failed to reload ConVar whitelist config!"); +} + +bool CConVarWhitelist::LoadConfig() +{ + m_bConfigLoaded = false; + m_vecGlobalWhitelist.clear(); + m_mapOverrides.clear(); + + const char* pszCvarWhitelistPath = "addons/cs2fixes/configs/cvar_whitelist.jsonc"; + char szPath[MAX_PATH]; + V_snprintf(szPath, sizeof(szPath), "%s%s%s", Plat_GetGameDirectory(), "/csgo/", pszCvarWhitelistPath); + std::ifstream cvarWhitelistFile(szPath); + + if (!cvarWhitelistFile.is_open()) + { + Panic("Failed to open %s, ConVar whitelist not loaded!\n", pszCvarWhitelistPath); + return false; + } + + json jsonWhitelist = json::parse(cvarWhitelistFile, nullptr, false, true); + + if (jsonWhitelist.is_discarded() || !jsonWhitelist.is_object()) + { + Panic("Failed parsing JSON from %s, ConVar whitelist not loaded!\n", pszCvarWhitelistPath); + return false; + } + + for (auto& [strKey, jsonValue] : jsonWhitelist.items()) + { + if (jsonValue.is_boolean()) + { + m_vecGlobalWhitelist.push_back({StringToLower(strKey), jsonValue.get()}); + } + else if (jsonValue.is_object()) + { + std::vector vecWhitelist; + + for (auto& [strConvar, jsonInnerValue] : jsonValue.items()) + { + if (!jsonInnerValue.is_boolean()) + { + Panic("Found invalid value in %s, ConVar whitelist not loaded!\n", pszCvarWhitelistPath); + return false; + } + + vecWhitelist.push_back({StringToLower(strConvar), jsonInnerValue.get()}); + } + + m_mapOverrides[strKey] = vecWhitelist; + } + else + { + Panic("Found invalid value in %s, ConVar whitelist not loaded!\n", pszCvarWhitelistPath); + return false; + } + } + + m_bConfigLoaded = true; + return true; +} + +bool CConVarWhitelist::IsWhitelisted(std::string strName) +{ + auto globalIt = std::find_if(m_vecGlobalWhitelist.begin(), m_vecGlobalWhitelist.end(), [strName](const auto& wv) { + return wv.strConVar == StringToLower(strName); + }); + + // Cannot load map overrides, only check global whitelist + if (!GetGlobals()) + return globalIt != m_vecGlobalWhitelist.end() && globalIt->bEnabled; + + auto mapVector = m_mapOverrides[GetGlobals()->mapname.ToCStr()]; + auto mapIt = std::find_if(mapVector.begin(), mapVector.end(), [strName](const auto& wv) { + return wv.strConVar == StringToLower(strName); + }); + + // If a map override is present, it takes priority + if (mapIt != mapVector.end()) + return mapIt->bEnabled; + + // Or fall back to global whitelist + return globalIt != m_vecGlobalWhitelist.end() && globalIt->bEnabled; +} \ No newline at end of file diff --git a/src/cvarwhitelist.h b/src/cvarwhitelist.h new file mode 100644 index 00000000..ecb77a70 --- /dev/null +++ b/src/cvarwhitelist.h @@ -0,0 +1,54 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#pragma once + +#include "convar.h" +#undef snprintf +#include "vendor/nlohmann/json_fwd.hpp" + +using json = nlohmann::json; + +extern CConVar g_cvarConVarWhitelistEnable; + +struct WhitelistValue +{ + std::string strConVar; + bool bEnabled; +}; + +class CConVarWhitelist +{ +public: + CConVarWhitelist() + { + LoadConfig(); + } + + bool LoadConfig(); + bool IsWhitelisted(std::string strName); + bool IsConfigLoaded() { return m_bConfigLoaded; }; + +private: + bool m_bConfigLoaded = false; + std::vector m_vecGlobalWhitelist; + std::map> m_mapOverrides; +}; + +extern CConVarWhitelist* g_pConvarWhitelist; \ No newline at end of file diff --git a/src/detours.cpp b/src/detours.cpp index 3d21b9fc..eea5ac10 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -29,6 +29,7 @@ #include "common.h" #include "ctimer.h" #include "customio.h" +#include "cvarwhitelist.h" #include "detours.h" #include "entities.h" #include "entity/cbasemodelentity.h" @@ -92,6 +93,7 @@ DECLARE_DETOUR(CBaseModelEntity_SetModel, Detour_CBaseModelEntity_SetModel); DECLARE_DETOUR(CCSGameRules_GoToIntermission, Detour_CCSGameRules_GoToIntermission); DECLARE_DETOUR(SetBeamOrigin, Detour_SetBeamOrigin); DECLARE_DETOUR(SetBeamEndPos, Detour_SetBeamEndPos); +DECLARE_DETOUR(IsCommandWhitelisted, Detour_IsCommandWhitelisted); CConVar g_cvarBlockMolotovSelfDmg("cs2f_block_molotov_self_dmg", FCVAR_NONE, "Whether to block self-damage from molotovs", false); CConVar g_cvarBlockAllDamage("cs2f_block_all_dmg", FCVAR_NONE, "Whether to block all damage to players", false); @@ -892,6 +894,14 @@ void FASTCALL Detour_SetBeamEndPos(CBeam* pThis, const Vector* pVecPosition) pThis->m_vecEndPos = *(VectorWS*)(pVecPosition); } +bool FASTCALL Detour_IsCommandWhitelisted(void* pAddonManager, const char* pszCommandName) +{ + if (!g_cvarConVarWhitelistEnable.Get() || !g_pConvarWhitelist->IsConfigLoaded()) + return IsCommandWhitelisted(pAddonManager, pszCommandName); + + return g_pConvarWhitelist->IsWhitelisted(pszCommandName); +} + bool InitDetours(CGameConfig* gameConfig) { bool success = true; diff --git a/src/detours.h b/src/detours.h index b48e7b05..19f4cdc7 100644 --- a/src/detours.h +++ b/src/detours.h @@ -118,4 +118,5 @@ void FASTCALL Detour_CS_Script_SetModel(uint64_t unk1); void FASTCALL Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, const char* pszModel); void FASTCALL Detour_CCSGameRules_GoToIntermission(CCSGameRules* pThis, bool bAbortedMatch); void FASTCALL Detour_SetBeamOrigin(CBeam* pThis, const Vector* pVecWorldPosition); -void FASTCALL Detour_SetBeamEndPos(CBeam* pThis, const Vector* pVecWorldPosition); \ No newline at end of file +void FASTCALL Detour_SetBeamEndPos(CBeam* pThis, const Vector* pVecWorldPosition); +bool FASTCALL Detour_IsCommandWhitelisted(void* pAddonManager, const char* pszCommandName); \ No newline at end of file diff --git a/src/map_votes.cpp b/src/map_votes.cpp index 148b159a..6005b524 100644 --- a/src/map_votes.cpp +++ b/src/map_votes.cpp @@ -1136,24 +1136,11 @@ void CMapVoteSystem::ClearInvalidNominations() } } -void CMapVoteSystem::ApplyGameSettings(KeyValues* pKV) +void CMapVoteSystem::ApplyGameSettings(const char* pszMapName, uint64 iWorkshopId) { if (!g_cvarVoteManagerEnable.Get()) return; - const char* pszMapName; - uint64 iWorkshopId; - - if (pKV->FindKey("launchoptions") && pKV->FindKey("launchoptions")->FindKey("levelname")) - pszMapName = pKV->FindKey("launchoptions")->GetString("levelname"); - else - pszMapName = ""; - - if (pKV->FindKey("launchoptions") && pKV->FindKey("launchoptions")->FindKey("customgamemode")) - iWorkshopId = pKV->FindKey("launchoptions")->GetUint64("customgamemode"); - else - iWorkshopId = 0; - auto pair = GetMapInfoByIdentifiers(pszMapName, iWorkshopId); if (pair.first != -1) diff --git a/src/map_votes.h b/src/map_votes.h index 136bfbdf..178f65cc 100644 --- a/src/map_votes.h +++ b/src/map_votes.h @@ -210,7 +210,7 @@ class CMapVoteSystem std::shared_ptr GetForcedNextMap() { return m_pForcedNextMap; } void SetForcedNextMap(std::shared_ptr pForcedNextMap) { m_pForcedNextMap = pForcedNextMap; } std::unordered_map GetNominatedMaps(); - void ApplyGameSettings(KeyValues* pKV); + void ApplyGameSettings(const char* pszMapName, uint64 iWorkshopId); void OnLevelShutdown(); std::vector> GetMapCooldowns() { return m_vecCooldowns; } std::string ConvertFloatToString(float fValue, int precision); diff --git a/src/mapmigrations.cpp b/src/mapmigrations.cpp index 5de64a0e..03db6b16 100644 --- a/src/mapmigrations.cpp +++ b/src/mapmigrations.cpp @@ -33,15 +33,13 @@ const time_t g_time20260420 = 1776725888; CConVar g_cvarMapMigrations20260121("cs2f_mapmigrations_20260121", FCVAR_NONE, "Current mode for 2026-01-21 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-01-21 & disabled if updated after]", 2); CConVar g_cvarMapMigrations20260420("cs2f_mapmigrations_20260420", FCVAR_NONE, "Current mode for 2026-04-20 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-04-20 & disabled if updated after]", 2); -void CMapMigrations::ApplyGameSettings(KeyValues* pKV) +void CMapMigrations::ApplyGameSettings(uint64 iWorkshopId) { m_timeMapUpdated = std::numeric_limits::max(); // Don't run on default maps - if (!pKV->FindKey("launchoptions") || !pKV->FindKey("launchoptions")->FindKey("customgamemode")) - return; - - CMapMigrationWorkshopDetailsQuery::Create(pKV->FindKey("launchoptions")->GetUint64("customgamemode")); + if (iWorkshopId != 0) + CMapMigrationWorkshopDetailsQuery::Create(iWorkshopId); } void CMapMigrations::OnRoundPrestart() diff --git a/src/mapmigrations.h b/src/mapmigrations.h index c19fde12..6d4cca13 100644 --- a/src/mapmigrations.h +++ b/src/mapmigrations.h @@ -52,7 +52,7 @@ class CMapMigrationWorkshopDetailsQuery : public std::enable_shared_from_this