CfgService.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using SlamCross.Models;
  6. namespace SlamCross.Services;
  7. public static class CfgService
  8. {
  9. public static void WriteCfgFiles(SourceGame game, string steamAppsPath, AppSettings settings)
  10. {
  11. var sep = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? '\\' : '/';
  12. var gameDir = Path.Combine(steamAppsPath, game.Directory.Replace('\\', sep));
  13. var cfgFolder = Path.Combine(gameDir, game.ToCfg.Replace('\\', sep));
  14. if (!Directory.Exists(cfgFolder))
  15. throw new Exception($"CS2 cfg folder not found: {cfgFolder}\nCheck your Steam/CS2 installation path.");
  16. var lines = new List<string>();
  17. lines.Add("alias slam_play \"slam_updatecfg;slam_play_on;\"");
  18. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  19. {
  20. lines.Add("alias slam_play_on \"alias slam_play slam_play_off; slam_nonce; slam_updatecfg; voice_loopback 1; +voicerecord\"");
  21. lines.Add("alias slam_play_off \"alias slam_play slam_play_on; -voicerecord; voice_loopback 0;\"");
  22. }
  23. else
  24. {
  25. var virtualMicOut = string.IsNullOrEmpty(settings.VirtualMicOutDeviceName) ? "CABLE Output (VB-Audio Virtual Cable)" : settings.VirtualMicOutDeviceName.Trim();
  26. var regularMic = string.IsNullOrEmpty(settings.RegularMicDeviceName) ? "Microphone" : settings.RegularMicDeviceName.Trim();
  27. lines.Add($"alias slam_play_on \"alias slam_play slam_play_off; slam_nonce; slam_updatecfg; voice_loopback 1; voice_device_override {virtualMicOut}; +voicerecord\"");
  28. lines.Add($"alias slam_play_off \"alias slam_play slam_play_on; -voicerecord; voice_loopback 0; voice_device_override {regularMic};\"");
  29. }
  30. lines.Add("alias slam_updatecfg \"host_writeconfig\"");
  31. // the relay bind flips between _a/_b on each play press, so the app can tell a real
  32. // press apart from CS2 rewriting the vcfg on its own (round start, buy menu)
  33. lines.Add("alias slam_nonce slam_nonce_a");
  34. lines.Add("alias slam_nonce_a \"alias slam_nonce slam_nonce_b; slam_bind_a\"");
  35. lines.Add("alias slam_nonce_b \"alias slam_nonce slam_nonce_a; slam_bind_b\"");
  36. lines.Add("alias slam_bind_a \"\"");
  37. lines.Add("alias slam_bind_b \"\"");
  38. lines.Add("alias slam_none \"\"");
  39. lines.Add($"bind {settings.RelayKey} slam_none");
  40. if (settings.HoldToPlay)
  41. {
  42. lines.Add("alias +slam_hold_play slam_play_on");
  43. lines.Add("alias -slam_hold_play slam_play_off");
  44. lines.Add($"bind {settings.PlayKey} +slam_hold_play");
  45. }
  46. else
  47. {
  48. lines.Add($"bind {settings.PlayKey} slam_play");
  49. }
  50. lines.Add("alias slam_listtracks \"exec slam_tracklist.cfg\"");
  51. lines.Add("alias slam_curtrack \"exec slam_curtrack.cfg\"");
  52. lines.Add("alias slam_saycurtrack \"exec slam_saycurtrack.cfg\"");
  53. lines.Add("alias slam_sayteamcurtrack \"exec slam_sayteamcurtrack.cfg\"");
  54. for (int i = 0; i < game.Tracks.Count; i++)
  55. {
  56. var n = i + 1;
  57. var track = game.Tracks[i];
  58. lines.Add($"alias slam_bindcmd_{n}_a \"bind {settings.RelayKey} slam_r_{n}_a\"");
  59. lines.Add($"alias slam_bindcmd_{n}_b \"bind {settings.RelayKey} slam_r_{n}_b\"");
  60. lines.Add($"alias slam_r_{n}_a \"\"");
  61. lines.Add($"alias slam_r_{n}_b \"\"");
  62. var select = $"alias slam_bind_a slam_bindcmd_{n}_a; alias slam_bind_b slam_bindcmd_{n}_b";
  63. lines.Add($"alias {n} \"{select}\"");
  64. if (settings.WriteTags)
  65. foreach (var tag in track.Tags)
  66. lines.Add($"alias {tag} \"{select}\"");
  67. if (!string.IsNullOrEmpty(track.Hotkey))
  68. lines.Add($"bind {track.Hotkey} \"{select}; slam_play_on;\"");
  69. }
  70. var footer = "voice_modenable 1; con_enable 1";
  71. if (game.VoiceFadeOut) footer += "; voice_fadeouttime 0.0";
  72. footer += "; host_writeconfig";
  73. lines.Add(footer);
  74. // CS2 limits exec files to 200 lines; chain into slam2, slam3, etc. if needed.
  75. const int chunkSize = 199;
  76. int fileIdx = 1;
  77. for (int written = 0; written < lines.Count; written += chunkSize)
  78. {
  79. var fileName = fileIdx == 1 ? "slam.cfg" : $"slam{fileIdx}.cfg";
  80. var chunk = lines.GetRange(written, Math.Min(chunkSize, lines.Count - written));
  81. if (written + chunkSize < lines.Count)
  82. chunk.Add($"exec slam{fileIdx + 1}");
  83. File.WriteAllLines(Path.Combine(cfgFolder, fileName), chunk);
  84. fileIdx++;
  85. }
  86. using var trackList = new StreamWriter(Path.Combine(cfgFolder, "slam_tracklist.cfg"));
  87. trackList.WriteLine("echo \"You can select tracks by tag or number.\"");
  88. trackList.WriteLine("echo \"--------------------Tracks--------------------\"");
  89. for (int i = 0; i < game.Tracks.Count; i++)
  90. {
  91. var t = game.Tracks[i];
  92. var tagStr = settings.WriteTags && t.Tags.Count > 0
  93. ? $" ['{string.Join("', '", t.Tags)}']" : "";
  94. trackList.WriteLine($"echo \"{i + 1}. {t.Name}{tagStr}\"");
  95. }
  96. trackList.WriteLine("echo \"----------------------------------------------\"");
  97. }
  98. public static void DeleteCfgFiles(SourceGame game, string steamAppsPath)
  99. {
  100. var sep = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? '\\' : '/';
  101. var cfgFolder = Path.Combine(steamAppsPath, game.Directory.Replace('\\', sep), game.ToCfg.Replace('\\', sep));
  102. string[] files = ["slam.cfg", "slam_tracklist.cfg", "slam_relay.cfg",
  103. "slam_curtrack.cfg", "slam_saycurtrack.cfg", "slam_sayteamcurtrack.cfg"];
  104. foreach (var f in files)
  105. {
  106. var path = Path.Combine(cfgFolder, f);
  107. if (File.Exists(path)) try { File.Delete(path); } catch { }
  108. }
  109. }
  110. public static void WriteTrackCfgs(SourceGame game, string steamAppsPath, Track track)
  111. {
  112. var sep = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? '\\' : '/';
  113. var cfgFolder = Path.Combine(steamAppsPath, game.Directory.Replace('\\', sep), game.ToCfg.Replace('\\', sep));
  114. File.WriteAllText(Path.Combine(cfgFolder, "slam_curtrack.cfg"), $"echo \"[SLAM] Track name: {track.Name}\"\n");
  115. File.WriteAllText(Path.Combine(cfgFolder, "slam_saycurtrack.cfg"), $"say \"[SLAM] Track name: {track.Name}\"\n");
  116. File.WriteAllText(Path.Combine(cfgFolder, "slam_sayteamcurtrack.cfg"), $"say_team \"[SLAM] Track name: {track.Name}\"\n");
  117. }
  118. }