diff --git a/.editorconfig b/.editorconfig
index 63251a3b296..c79c816e35c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -15,3 +15,7 @@ indent_style = space
 [{*.{yml,yaml},.clang{-format,-tidy,d}}]
 indent_size = 2
 indent_style = space
+
+[{*.props,*.vcxproj}]
+indent_size = 2
+indent_style = space
diff --git a/methods.py b/methods.py
index dd7a46e05ed..cb3fb118587 100644
--- a/methods.py
+++ b/methods.py
@@ -14,6 +14,7 @@ from pathlib import Path
 from typing import Generator, List, Optional, Union, cast
 
 from misc.utility.color import print_error, print_info, print_warning
+from platform_methods import detect_arch
 
 # Get the "Godot" folder name ahead of time
 base_folder = Path(__file__).resolve().parent
@@ -1067,8 +1068,22 @@ def generate_vs_project(env, original_args, project_name="godot"):
     platform = env["platform"]
     target = env["target"]
     arch = env["arch"]
+    host_arch = detect_arch()
+
+    host_platform = "windows"
+    if (
+        sys.platform.startswith("linux")
+        or sys.platform.startswith("dragonfly")
+        or sys.platform.startswith("freebsd")
+        or sys.platform.startswith("netbsd")
+        or sys.platform.startswith("openbsd")
+    ):
+        host_platform = "linuxbsd"
+    elif sys.platform == "darwin":
+        host_platform = "macos"
 
     vs_configuration = {}
+    host_vs_configuration = {}
     common_build_prefix = []
     confs = []
     for x in sorted(glob.glob("platform/*")):
@@ -1097,6 +1112,12 @@ def generate_vs_project(env, original_args, project_name="godot"):
             if platform == platform_name:
                 common_build_prefix = msvs.get_build_prefix(env)
                 vs_configuration = vsconf
+            if platform_name == host_platform:
+                host_vs_configuration = vsconf
+                for a in vsconf["arches"]:
+                    if host_arch == a["architecture"]:
+                        host_arch = a["platform"]
+                        break
         except Exception:
             pass
 
@@ -1254,12 +1275,11 @@ def generate_vs_project(env, original_args, project_name="godot"):
             properties.append(
                 ";%s;" % (x, ";".join(itemlist[x]), x)
             )
-        output = f"bin\\godot{env['PROGSUFFIX']}"
+        output = os.path.join("bin", f"godot{env['PROGSUFFIX']}")
 
         with open("misc/msvs/props.template", "r", encoding="utf-8") as file:
             props_template = file.read()
 
-        props_template = props_template.replace("%%VSCONF%%", vsconf)
         props_template = props_template.replace("%%CONDITION%%", condition)
         props_template = props_template.replace("%%PROPERTIES%%", "\n    ".join(properties))
         props_template = props_template.replace("%%EXTRA_ITEMS%%", "\n    ".join(extraItems))
@@ -1272,6 +1292,7 @@ def generate_vs_project(env, original_args, project_name="godot"):
 
         proplist = [str(j) for j in env["CPPPATH"]]
         proplist += [str(j) for j in env.get("VSHINT_INCLUDES", [])]
+        proplist += [str(j) for j in get_default_include_paths(env)]
         props_template = props_template.replace("%%INCLUDES%%", ";".join(proplist))
 
         proplist = env["CCFLAGS"]
@@ -1307,17 +1328,17 @@ def generate_vs_project(env, original_args, project_name="godot"):
 
         commands = "scons"
         if len(common_build_prefix) == 0:
-            commands = "echo Starting SCons && cmd /V /C " + commands
+            commands = "echo Starting SCons & " + commands
         else:
-            common_build_prefix[0] = "echo Starting SCons && cmd /V /C " + common_build_prefix[0]
+            common_build_prefix[0] = "echo Starting SCons & " + common_build_prefix[0]
 
-        cmd = " ^& ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
+        cmd = " ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
         props_template = props_template.replace("%%BUILD%%", cmd)
 
-        cmd = " ^& ".join(common_build_prefix + [" ".join([commands] + cmd_rebuild)])
+        cmd = " ".join(common_build_prefix + [" ".join([commands] + cmd_rebuild)])
         props_template = props_template.replace("%%REBUILD%%", cmd)
 
-        cmd = " ^& ".join(common_build_prefix + [" ".join([commands] + cmd_clean)])
+        cmd = " ".join(common_build_prefix + [" ".join([commands] + cmd_clean)])
         props_template = props_template.replace("%%CLEAN%%", cmd)
 
         with open(
@@ -1348,18 +1369,45 @@ def generate_vs_project(env, original_args, project_name="godot"):
     section2 = []
     for conf in confs:
         godot_platform = conf["platform"]
+        has_editor = "editor" in conf["targets"]
+
+        # Skip any platforms that can build the editor and don't match the host platform.
+        #
+        # When both Windows and Mac define an editor target, it's defined as platform+target+arch (windows+editor+x64 for example).
+        # VS only supports two attributes, a "Configuration" and a "Platform", and we currently map our target to the Configuration
+        # (i.e. editor/template_debug/template_release), and our architecture to the "Platform" (i.e. x64, arm64, etc).
+        # Those two are not enough to disambiguate multiple godot targets for different godot platforms with the same architecture,
+        # i.e. editor|x64 would currently match both windows editor intel 64 and linux editor intel 64.
+        #
+        # TODO: More work is needed in order to support generating VS projects that unambiguously support all platform+target+arch variations.
+        # The VS "Platform" has to be a known architecture that VS recognizes, so we can only play around with the "Configuration" part of the combo.
+        if has_editor and godot_platform != host_vs_configuration["platform"]:
+            continue
+
         for p in conf["arches"]:
             sln_plat = p["platform"]
             proj_plat = sln_plat
             godot_arch = p["architecture"]
 
-            # Redirect editor configurations for non-Windows platforms to the Windows one, so the solution has all the permutations
-            # and VS doesn't complain about missing project configurations.
+            # Redirect editor configurations for platforms that don't support the editor target to the default editor target on the
+            # active host platform, so the solution has all the permutations and VS doesn't complain about missing project configurations.
             # These configurations are disabled, so they show up but won't build.
-            if godot_platform != "windows":
+            if not has_editor:
                 section1 += [f"editor|{sln_plat} = editor|{proj_plat}"]
-                section2 += [
-                    f"{{{proj_uuid}}}.editor|{proj_plat}.ActiveCfg = editor|{proj_plat}",
+                section2 += [f"{{{proj_uuid}}}.editor|{proj_plat}.ActiveCfg = editor|{host_arch}"]
+
+                configurations += [
+                    f'',
+                    "  editor",
+                    f"  {proj_plat}",
+                    "",
+                ]
+
+                properties += [
+                    f"",
+                    "  editor",
+                    f"  {proj_plat}",
+                    "",
                 ]
 
             for t in conf["targets"]:
@@ -1383,21 +1431,6 @@ def generate_vs_project(env, original_args, project_name="godot"):
                     "",
                 ]
 
-                if godot_platform != "windows":
-                    configurations += [
-                        f'',
-                        "  editor",
-                        f"  {proj_plat}",
-                        "",
-                    ]
-
-                    properties += [
-                        f"",
-                        "  editor",
-                        f"  {proj_plat}",
-                        "",
-                    ]
-
                 p = f"{project_name}.{godot_platform}.{godot_target}.{godot_arch}.generated.props"
                 imports += [
                     f''
@@ -1606,3 +1639,18 @@ def to_raw_cstring(value: Union[str, List[str]]) -> str:
     else:
         # Wrap multiple segments in parenthesis to suppress `string-concatenation` warnings on clang.
         return "({})".format(" ".join(f'R"({segment.decode()})"' for segment in split))
+
+
+def get_default_include_paths(env):
+    if env.msvc:
+        return []
+    compiler = env.subst("$CXX")
+    target = os.path.join(env.Dir("#main").abspath, "main.cpp")
+    args = [compiler, target, "-x", "c++", "-v"]
+    ret = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
+    output = ret.stdout
+    match = re.search(r"#include <\.\.\.> search starts here:([\S\s]*)End of search list.", output)
+    if not match:
+        print_warning("Failed to find the include paths in the compiler output.")
+        return []
+    return [x.strip() for x in match[1].strip().splitlines()]
diff --git a/misc/msvs/nmake.substitution.props b/misc/msvs/nmake.substitution.props
new file mode 100644
index 00000000000..05a155eb9eb
--- /dev/null
+++ b/misc/msvs/nmake.substitution.props
@@ -0,0 +1,19 @@
+
+
+  
+      
+      
+    Unknown
+    $(NMakeOutput)
+  
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+
diff --git a/misc/msvs/props.template b/misc/msvs/props.template
index 82e3e81f182..57483703056 100644
--- a/misc/msvs/props.template
+++ b/misc/msvs/props.template
@@ -1,6 +1,6 @@
 
 
-  
+  
     %%BUILD%%
     %%REBUILD%%
     %%CLEAN%%
@@ -18,6 +18,9 @@
   
     %%EXTRA_ITEMS%%
   
+
+  
+  
 
 
+     
     $(SolutionDir)\bin\$(GodotPlatform)\$(GodotConfiguration)\
     obj\$(GodotPlatform)\$(GodotConfiguration)\
     $(OutDir)\Layout
   
-  
+  
   
   
   
-    
+    
   
   
+  %%IMPORTS%%
   
     <_ProjectFileVersion>10.0.30319.1
     
   
-  %%IMPORTS%%
   
     %%DEFAULT_ITEMS%%
   
-  
+  
   
   
 
diff --git a/platform/linuxbsd/msvs.py b/platform/linuxbsd/msvs.py
new file mode 100644
index 00000000000..5dae4e4781c
--- /dev/null
+++ b/platform/linuxbsd/msvs.py
@@ -0,0 +1,11 @@
+# Tuples with the name of the arch
+def get_platforms():
+    return [("x64", "x86_64")]
+
+
+def get_configurations():
+    return ["editor", "template_debug", "template_release"]
+
+
+def get_build_prefix(env):
+    return []
diff --git a/platform/macos/msvs.py b/platform/macos/msvs.py
new file mode 100644
index 00000000000..39bc3c59748
--- /dev/null
+++ b/platform/macos/msvs.py
@@ -0,0 +1,11 @@
+# Tuples with the name of the arch
+def get_platforms():
+    return [("arm64", "arm64"), ("x64", "x86_64")]
+
+
+def get_configurations():
+    return ["editor", "template_debug", "template_release"]
+
+
+def get_build_prefix(env):
+    return []
diff --git a/platform/windows/msvs.py b/platform/windows/msvs.py
index 2d5ebe811a4..ff8a379867d 100644
--- a/platform/windows/msvs.py
+++ b/platform/windows/msvs.py
@@ -12,9 +12,13 @@ def get_configurations():
 
 
 def get_build_prefix(env):
+    if not env.msvc:
+        return []
     batch_file = methods.find_visual_c_batch_file(env)
     return [
+        "cmd /V /C",
         "set "plat=$(PlatformTarget)"",
-        "(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))",
-        f"call "{batch_file}" !plat!",
+        "^& (if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))",
+        f"^& call "{batch_file}" !plat!",
+        "^&",
     ]