Skip to content
Beta: this is a preview of the new SplitScreen.Me. Data may be reset before launch.

Left 4 Dead 2 · handler “Left 4 Dead 2”

Version 8

Release notes

fixed native splitscreen option not working in 2 monitors.

Released
Size
302 KB
Downloads
8,448
Check
Verified
SHA-256
826dfc3b11ea0cbe7cb5667348dbeab71fc3449bd0cbd618ab72730bcb67ae97
Download v8 (.nc)All versions

Files 2

PathSize
handler.js13 KB
Left4Dead2/571568537.vpk3.9 MB

handler.js

Plain text
Hub.Handler.Version = 8; // Released at https://hub.splitscreen.me/ on Tue Jan 18 2022 08:34:01 GMT+0000 (Coordinated Universal Time).
Hub.Handler.Id = "wFsXDjoAkHpL4XZm8";
Hub.Maintainer.Name = "Talos91";
Hub.Maintainer.Id = "eeL7HAz8zJovChWw4";

var answers1 = ["No", "Yes"];
Game.AddOption("Will you use the game's native splitscreen?", "If yes only launch two instances, you need 3 or 4 gamepads.", "Native", answers1);

Game.KillMutex = ["hl2_singleton_mutex"];
Game.DirSymlinkExclusions = ["bin", "left4dead2", "left4dead2\\cfg", "left4dead2\\addons"];
Game.FileSymlinkExclusions = [
  "autoexec.cfg",
  "video.txt",
  "config.cfg",
  "steam_api.dll",
  "steam_appid.txt",
  "steam_interfaces.txt",
  "local_save.txt",
  "dinput8.dll",
  "xinput1_3.dll",
  "xinput1_4.dll",
  "571568537.vpk",
  "pak01_000.vpk"
];
Game.FileSymlinkCopyInstead = ["360controller.cfg"];
Game.HandlerInterval = 100;
Game.SymlinkExe = false;
Game.SymlinkGame = true;
Game.SymlinkFolders = true;
Game.SupportsKeyboard = true;
Game.ExecutableName = "left4dead2.exe";
Game.SteamID = "550";
Game.GUID = "Left 4 Dead 2";
Game.GameName = "Left 4 Dead 2";
Game.UseNucleusEnvironment = true;
Game.NeedsSteamEmulation = false;
Game.UseGoldberg = true;
Game.GoldbergNoLocalSave = true;
Game.CreateSteamAppIdByExe = true;
Game.LauncherTitle = "";
Game.WorkingFolder = "bin";
Game.StartArguments = "-steam -window -AlwaysFocus -nointro -novid";
Game.MaxPlayersOneMonitor = 8;
Game.MaxPlayers = 8;
Game.Hook.ForceFocus = false;
Game.Hook.ForceFocusWindowName = "Left 4 Dead 2 - Direct3D 9";
Game.HasDynamicWindowTitle = true;
Game.DPIHandling = Nucleus.DPIHandling.InvScaled;
Game.HookFocus = true;
Game.Hook.DInputEnabled = false;
Game.UseDInputBlocker = true;
Game.Hook.XInputEnabled = true;
Game.Hook.XInputReroute = false;
Game.XInputPlusDll = ["xinput1_3.dll", "xinput1_4.dll"];
Game.Hook.CustomDllEnabled = false;
Game.UserProfileSavePath = "AppData\\Roaming\\Goldberg SteamEmu Saves\\550\\remote";
Game.UserProfileSavePathNoCopy = true;
Game.Description =
  "Create a multiplayer game in the first instance, select campaign, play with friends, press X on your gamepad, create a new room, set it to public and in server type choose local, then the other players can join the room using the play with friends options too. Use the mouse cursor to navigate the menus in all instances if you have trouble navigating the menus using gamepads as the game lacks full gamepad support in menus. Alt-tab to the keyboard/mouse instance to control it.";
Game.PauseBetweenStarts = 25;

Game.Play = function() {
  var saveSrc = System.IO.Path.Combine(Context.RootInstallFolder, "left4dead2\\cfg\\video.txt");
  var savePath = System.IO.Path.Combine(Context.RootFolder, "left4dead2\\cfg\\video.txt");
  Context.ModifySaveFile(saveSrc, savePath, Nucleus.SaveType.CFG, [
    new Nucleus.CfgSaveInfo("config", "setting.fullscreen", "0"),
    new Nucleus.CfgSaveInfo("config", "setting.defaultres", Math.max(640, Context.Width)),
    new Nucleus.CfgSaveInfo("config", "setting.defaultresheight", Math.max(360, Context.Height)),
    new Nucleus.CfgSaveInfo("config", "setting.nowindowborder", "0"),
    new Nucleus.CfgSaveInfo("VideoConfig", "setting.fullscreen", "0"),
    new Nucleus.CfgSaveInfo("VideoConfig", "setting.defaultres", Math.max(640, Context.Width)),
    new Nucleus.CfgSaveInfo("VideoConfig", "setting.defaultresheight", Math.max(360, Context.Height)),
    new Nucleus.CfgSaveInfo("VideoConfig ", "setting.nowindowborder", "0")
  ]);

  //copy config.cfg
  System.IO.File.Copy(System.IO.Path.Combine(Context.RootInstallFolder, "left4dead2\\cfg\\config.cfg"), System.IO.Path.Combine(Context.RootFolder, "left4dead2\\cfg\\config.cfg"), true);

  if (Context.IsKeyboardPlayer) {
    var txtPath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\config.cfg";
    var dict = [Context.FindLineNumberInTextFile(txtPath, 'joystick "1"', Nucleus.SearchType.StartsWith) + '|joystick "0"'];
    Context.ReplaceLinesInTextFile(txtPath, dict);
  } else {
    var txtPath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\config.cfg";
    var dict = [Context.FindLineNumberInTextFile(txtPath, 'joystick "0"', Nucleus.SearchType.StartsWith) + '|joystick "1"'];
    Context.ReplaceLinesInTextFile(txtPath, dict);
  }

  var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
  var lines = [
    "sv_lan 1",
    "sv_allow_lobby_connect_only 0",
    "engine_no_focus_sleep 0" // unlimited FPS on all screens
  ];

  if (Player.IsKeyboardPlayer) {
    lines.push("joystick 0");
    lines.push("exec undo360controller.cfg");
  } else {
    lines.push("exec 360controller.cfg");
  }
  Context.WriteTextFile(autoExec, lines);

  var native = Context.Options["Native"];

  if (native == "Yes") {
    Game.PromptAfterFirstInstance = true;

    var savePath = (Context.SavePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\addons\\571568537.vpk");
    var savePkgOrigin = System.IO.Path.Combine(Game.Folder, "571568537.vpk");
    System.IO.File.Copy(savePkgOrigin, savePath, true);

    var txtPath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\360controller.cfg";
    var dict = ["60|cmd2 +jlook "];
    Context.ReplaceLinesInTextFile(txtPath, dict);

    if (Player.Owner.IsDualHorizontal()) {
      //patch native splitscreen aspect ratio
      Context.PatchFile(
        System.IO.Path.Combine(Context.RootInstallFolder, "left4dead2\\pak01_000.vpk"),
        System.IO.Path.Combine(Context.RootFolder, "left4dead2\\pak01_000.vpk"),
        [0x09, 0x22, 0x38, 0x20, 0x62, 0x79, 0x20, 0x39],
        [0x09, 0x22, 0x39, 0x20, 0x62, 0x79, 0x20, 0x35]
      );

      if (Context.PlayerID == 0) {
        var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
        var lines = ["sv_lan 1", "sv_allow_lobby_connect_only 0", "engine_no_focus_sleep 0", "name2 " + Context.Nickname + "-B", "ss_splitmode 0"];
        Context.WriteTextFile(autoExec, lines);

        var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
        Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "1"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "2"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
        ]);
      }

      if (Context.PlayerID == 1) {
        Context.StartArguments = "-steam -window -AlwaysFocus -nointro -novid -console";

        var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
        var lines = [
          "sv_lan 1",
          "sv_allow_lobby_connect_only 0",
          "engine_no_focus_sleep 0",
          "name2 " + Context.Nickname + "-B",
          "ss_splitmode 0",
          "connect_splitscreen localhost " + Context.LocalIP + ":27015 2"
        ];
        Context.WriteTextFile(autoExec, lines);

        var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
        Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "3"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "4"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
        ]);
      }
    }

    if (Player.Owner.IsDualVertical()) {
      Context.PatchFile(
        System.IO.Path.Combine(Context.RootInstallFolder, "left4dead2\\pak01_000.vpk"),
        System.IO.Path.Combine(Context.RootFolder, "left4dead2\\pak01_000.vpk"),
        [0x09, 0x22, 0x38, 0x20, 0x62, 0x79, 0x20, 0x33],
        [0x09, 0x22, 0x37, 0x20, 0x62, 0x79, 0x20, 0x34]
      );

      if (Context.PlayerID == 0) {
        var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
        var lines = ["sv_lan 1", "sv_allow_lobby_connect_only 0", "engine_no_focus_sleep 0", "name2 " + Context.Nickname + "-B", "ss_splitmode 1"];
        Context.WriteTextFile(autoExec, lines);

        var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
        Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "1"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "3"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
        ]);
      }

      if (Context.PlayerID == 1) {
        Context.StartArguments = "-steam -window -AlwaysFocus -nointro -novid -console";

        var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
        var lines = [
          "sv_lan 1",
          "sv_allow_lobby_connect_only 0",
          "engine_no_focus_sleep 0",
          "name2 " + Context.Nickname + "-B",
          "ss_splitmode 1",
          "hud_reloadscheme",
          "connect_splitscreen localhost " + Context.LocalIP + ":27015 2"
        ];
        Context.WriteTextFile(autoExec, lines);

        var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
        Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "2"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "4"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
        ]);
      }
    }

    if (Player.Owner.IsFullscreen()) {
      System.IO.File.Copy(System.IO.Path.Combine(Context.RootInstallFolder, "left4dead2\\pak01_000.vpk"), System.IO.Path.Combine(Context.RootFolder, "left4dead2\\pak01_000.vpk"), true);

      if (Context.PlayerID == 0) {
        var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
        var lines = ["sv_lan 1", "sv_allow_lobby_connect_only 0", "engine_no_focus_sleep 0", "name2 " + Context.Nickname + "-B"];
        Context.WriteTextFile(autoExec, lines);

        var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
        Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "1"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "2"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
        ]);
      }

      if (Context.PlayerID == 1) {
        Context.StartArguments = "-steam -window -AlwaysFocus -nointro -novid -console";

        var autoExec = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\left4dead2\\cfg\\autoexec.cfg";
        var lines = ["sv_lan 1", "sv_allow_lobby_connect_only 0", "engine_no_focus_sleep 0", "name2 " + Context.Nickname + "-B", "connect_splitscreen localhost " + Context.LocalIP + ":27015 2"];
        Context.WriteTextFile(autoExec, lines);

        var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
        Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "3"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "4"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
          new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
        ]);
      }
    }
  }

  if (native == "No") {
    System.IO.File.Copy(System.IO.Path.Combine(Context.RootInstallFolder, "left4dead2\\pak01_000.vpk"), System.IO.Path.Combine(Context.RootFolder, "left4dead2\\pak01_000.vpk"), true);

    if (Player.IsKeyboardPlayer) {
      var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XinputPlus.ini";
      Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", "0"),
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", "0"),
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", "0"),
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", "0")
      ]);
    } else {
      var savePath = Context.GetFolder(Nucleus.Folder.InstancedGameFolder) + "\\XInputPlus.ini";
      Context.ModifySaveFile(savePath, savePath, Nucleus.SaveType.INI, [
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller1", Context.PlayerID + 1),
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller2", Context.PlayerID + 1),
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller3", Context.PlayerID + 1),
        new Nucleus.IniSaveInfo("ControllerNumber", "Controller4", Context.PlayerID + 1)
      ]);
    }
  }

  if (Context.NumControllers < 5) {
    Game.Hook.XInputReroute = false;
  } else {
    Game.Hook.UseAlpha8CustomDll = true;
    Game.Hook.CustomDllEnabled = true;
  }
};