XR和Steam VR项目合并问题

最近有一个项目是用Steam VR开发的,里面部分场景是用VRTK框架做的,还有一部分是用SteamVR SDK自带的Player预制直接开发的。

这样本身没有问题,因为最终都是通过SteamVR SDK处理的,VRTK也管理好了SteamVR的逻辑,并且支持动态切换,比如切换成Oculus的。

然后现在遇到一个问题,还有一个项目是用Unity自带的XR开发的,Package Manager导入XR相关的插件实现的。

 

需要将XR开发的项目移植到Steam VR项目来,然后事情就开始了。

SteamVR的场景可以运行,通过Pico以及Quest串流还有htc头盔都能正常识别,手柄也能控制。

但是XR场景就出现问题了,头盔无法识别。

经过一步步排查,发现是XR Plug-in Management这里需要设置不同的XRLoader。

而SteamVR是OpenVR Loader,而XR是OpenXR,因为OpenVR Loader在前,所以激活的是OpenVR Loader,这也是为什么SteamVR场景可以运行而XR场景不行。

我们看看unity的源代码是怎么写的,发现这里面是有activeLoader的概念,也就是一次只能一个Loader运行。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;

using UnityEditor;

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
using UnityEngine.Serialization;
using UnityEngine.XR.Management;

[assembly: InternalsVisibleTo("Unity.XR.Management.Tests")]
[assembly: InternalsVisibleTo("Unity.XR.Management.EditorTests")]
namespace UnityEngine.XR.Management
{
    /// <summary>
    /// Class to handle active loader and subsystem management for XR. This class is to be added as a
    /// ScriptableObject asset in your project and should only be referenced by the <see cref="XRGeneralSettings"/>
    /// instance for its use.
    ///
    /// Given a list of loaders, it will attempt to load each loader in the given order. The first
    /// loader that is successful wins and all remaining loaders are ignored. The loader
    /// that succeeds is accessible through the <see cref="activeLoader"/> property on the manager.
    ///
    /// Depending on configuration the <see cref="XRManagerSettings"/> instance will automatically manage the active loader
    /// at correct points in the application lifecycle. The user can override certain points in the active loader lifecycle
    /// and manually manage them by toggling the <see cref="automaticLoading"/> and <see cref="automaticRunning"/>
    /// properties. Disabling <see cref="automaticLoading"/> implies the the user is responsible for the full lifecycle
    /// of the XR session normally handled by the <see cref="XRManagerSettings"/> instance. Toggling this to false also toggles
    /// <see cref="automaticRunning"/> false.
    ///
    /// Disabling <see cref="automaticRunning"/> only implies that the user is responsible for starting and stopping
    /// the <see cref="activeLoader"/> through the <see cref="StartSubsystems"/> and <see cref="StopSubsystems"/> APIs.
    ///
    /// Automatic lifecycle management is executed as follows
    ///
    /// * Runtime Initialize -> <see cref="InitializeLoader"/>. The loader list will be iterated over and the first successful loader will be set as the active loader.
    /// * Start -> <see cref="StartSubsystems"/>. Ask the active loader to start all subsystems.
    /// * OnDisable -> <see cref="StopSubsystems"/>. Ask the active loader to stop all subsystems.
    /// * OnDestroy -> <see cref="DeinitializeLoader"/>. Deinitialize and remove the active loader.
    /// </summary>
    public sealed class XRManagerSettings : ScriptableObject
    {
        [HideInInspector]
        bool m_InitializationComplete = false;

#pragma warning disable 414
        // This property is only used by the scriptable object editing part of the system and as such no one
        // directly references it. Have to manually disable the console warning here so that we can
        // get a clean console report.
        [HideInInspector]
        [SerializeField]
        bool m_RequiresSettingsUpdate = false;
#pragma warning restore 414

        [SerializeField]
        [Tooltip("Determines if the XR Manager instance is responsible for creating and destroying the appropriate loader instance.")]
        [FormerlySerializedAs("AutomaticLoading")]
        bool m_AutomaticLoading = false;

        /// <summary>
        /// Get and set Automatic Loading state for this manager. When this is true, the manager will automatically call
        /// <see cref="InitializeLoader"/> and <see cref="DeinitializeLoader"/> for you. When false <see cref="automaticRunning"/>
        /// is also set to false and remains that way. This means that disabling automatic loading disables all automatic behavior
        /// for the manager.
        /// </summary>
        public bool automaticLoading
        {
            get { return m_AutomaticLoading; }
            set { m_AutomaticLoading = value; }
        }

        [SerializeField]
        [Tooltip("Determines if the XR Manager instance is responsible for starting and stopping subsystems for the active loader instance.")]
        [FormerlySerializedAs("AutomaticRunning")]
        bool m_AutomaticRunning = false;

        /// <summary>
        /// Get and set automatic running state for this manager. When set to true the manager will call <see cref="StartSubsystems"/>
        /// and <see cref="StopSubsystems"/> APIs at appropriate times. When set to false, or when <see cref="automaticLoading"/> is false
        /// then it is up to the user of the manager to handle that same functionality.
        /// </summary>
        public bool automaticRunning
        {
            get { return m_AutomaticRunning; }
            set { m_AutomaticRunning = value; }
        }


        [SerializeField]
        [Tooltip("List of XR Loader instances arranged in desired load order.")]
        [FormerlySerializedAs("Loaders")]
        List<XRLoader> m_Loaders = new List<XRLoader>();

        // Maintains a list of registered loaders that is immutable at runtime.
        [SerializeField]
        [HideInInspector]
        HashSet<XRLoader> m_RegisteredLoaders = new HashSet<XRLoader>();

        /// <summary>
        /// List of loaders currently managed by this XR Manager instance.
        /// </summary>
        /// <remarks>
        /// Modifying the list of loaders at runtime is undefined behavior and could result in a crash or memory leak.
        /// Use <see cref="activeLoaders"/> to retrieve the currently ordered list of loaders. If you need to mutate
        /// the list at runtime, use <see cref="TryAddLoader"/>, <see cref="TryRemoveLoader"/>, and
        /// <see cref="TrySetLoaders"/>.
        /// </remarks>
        [Obsolete("'XRManagerSettings.loaders' property is obsolete. Use 'XRManagerSettings.activeLoaders' instead to get a list of the current loaders.")]
        public List<XRLoader> loaders
        {
            get { return m_Loaders; }
#if UNITY_EDITOR
            set { m_Loaders = value; }
#endif
        }

        /// <summary>
        /// A shallow copy of the list of loaders currently managed by this XR Manager instance.
        /// </summary>
        /// <remarks>
        /// This property returns a read only list. Any changes made to the list itself will not affect the list
        /// used by this XR Manager instance. To mutate the list of loaders currently managed by this instance,
        /// use <see cref="TryAddLoader"/>, <see cref="TryRemoveLoader"/>, and/or <see cref="TrySetLoaders"/>.
        /// </remarks>
        public IReadOnlyList<XRLoader> activeLoaders => m_Loaders;

        /// <summary>
        /// Read only boolean letting us know if initialization is completed. Because initialization is
        /// handled as a Coroutine, people taking advantage of the auto-lifecycle management of XRManager
        /// will need to wait for init to complete before checking for an ActiveLoader and calling StartSubsystems.
        /// </summary>
        public bool isInitializationComplete
        {
            get { return m_InitializationComplete; }
        }

        ///<summary>
        /// Return the current singleton active loader instance.
        ///</summary>
        [HideInInspector]
        public XRLoader activeLoader { get; private set; }

        /// <summary>
        /// Return the current active loader, cast to the requested type. Useful shortcut when you need
        /// to get the active loader as something less generic than XRLoader.
        /// </summary>
        ///
        /// <typeparam name="T">Requested type of the loader</typeparam>
        ///
        /// <returns>The active loader as requested type, or null.</returns>
        public T ActiveLoaderAs<T>() where T : XRLoader
        {
            return activeLoader as T;
        }

        /// <summary>
        /// Iterate over the configured list of loaders and attempt to initialize each one. The first one
        /// that succeeds is set as the active loader and initialization immediately terminates.
        ///
        /// When complete <see cref="isInitializationComplete"/> will be set to true. This will mark that it is safe to
        /// call other parts of the API. This does not guarantee that init successfully created a loader. For that
        /// you need to check that ActiveLoader is not null.
        ///
        /// Note that there can only be one active loader. Any attempt to initialize a new active loader with one
        /// already set will cause a warning to be logged and immediate exit of this function.
        ///
        /// This method is synchronous and on return all state should be immediately checkable.
        ///
        /// <b>If manual initialization of XR is being done, this method can not be called before Start completes
        /// as it depends on graphics initialization within Unity completing.</b>
        /// </summary>
        public void InitializeLoaderSync()
        {
            if (activeLoader != null)
            {
                Debug.LogWarning(
                    "XR Management has already initialized an active loader in this scene." +
                    " Please make sure to stop all subsystems and deinitialize the active loader before initializing a new one.");
                return;
            }

            foreach (var loader in currentLoaders)
            {
                if (loader != null)
                {
                    if (CheckGraphicsAPICompatibility(loader) && loader.Initialize())
                    {
                        activeLoader = loader;
                        m_InitializationComplete = true;
                        return;
                    }
                }
            }

            activeLoader = null;
        }

        /// <summary>
        /// Iterate over the configured list of loaders and attempt to initialize each one. The first one
        /// that succeeds is set as the active loader and initialization immediately terminates.
        ///
        /// When complete <see cref="isInitializationComplete"/> will be set to true. This will mark that it is safe to
        /// call other parts of the API. This does not guarantee that init successfully created a loader. For that
        /// you need to check that ActiveLoader is not null.
        ///
        /// Note that there can only be one active loader. Any attempt to initialize a new active loader with one
        /// already set will cause a warning to be logged and immediate exit of this function.
        ///
        /// Iteration is done asynchronously and this method must be called within the context of a Coroutine.
        ///
        /// <b>If manual initialization of XR is being done, this method can not be called before Start completes
        /// as it depends on graphics initialization within Unity completing.</b>
        /// </summary>
        ///
        /// <returns>Enumerator marking the next spot to continue execution at.</returns>
        public IEnumerator InitializeLoader()
        {
            if (activeLoader != null)
            {
                Debug.LogWarning(
                    "XR Management has already initialized an active loader in this scene." +
                    " Please make sure to stop all subsystems and deinitialize the active loader before initializing a new one.");
                yield break;
            }

            foreach (var loader in currentLoaders)
            {
                if (loader != null)
                {
                    if (CheckGraphicsAPICompatibility(loader) && loader.Initialize())
                    {
                        activeLoader = loader;
                        m_InitializationComplete = true;
                        yield break;
                    }
                }

                yield return null;
            }

            activeLoader = null;
        }

        /// <summary>
        /// Attempts to append the given loader to the list of loaders at the given index.
        /// </summary>
        /// <param name="loader">
        /// The <see cref="XRLoader"/> to be added to this manager's instance of loaders.
        /// </param>
        /// <param name="index">
        /// The index at which the given <see cref="XRLoader"/> should be added. If you set a negative or otherwise
        /// invalid index, the loader will be appended to the end of the list.
        /// </param>
        /// <returns>
        /// <c>true</c> if the loader is not a duplicate and was added to the list successfully, <c>false</c>
        /// otherwise.
        /// </returns>
        /// <remarks>
        /// This method behaves differently in the Editor and during runtime/Play mode. While your app runs in the Editor and not in
        /// Play mode, attempting to add an <see cref="XRLoader"/> will always succeed and register that loader's type
        /// internally. Attempting to add a loader during runtime/Play mode will trigger a check to see whether a loader of
        /// that type was registered. If the check is successful, the loader is added. If not, the loader is not added and the method
        /// returns <c>false</c>.
        /// </remarks>
        public bool TryAddLoader(XRLoader loader, int index = -1)
        {
            if (loader == null || currentLoaders.Contains(loader))
                return false;

#if UNITY_EDITOR
            if (!EditorApplication.isPlaying && !m_RegisteredLoaders.Contains(loader))
                m_RegisteredLoaders.Add(loader);
#endif
            if (!m_RegisteredLoaders.Contains(loader))
                return false;

            if (index < 0 || index >= currentLoaders.Count)
                currentLoaders.Add(loader);
            else
                currentLoaders.Insert(index, loader);

            return true;
        }

        /// <summary>
        /// Attempts to remove the first instance of a given loader from the list of loaders.
        /// </summary>
        /// <param name="loader">
        /// The <see cref="XRLoader"/> to be removed from this manager's instance of loaders.
        /// </param>
        /// <returns>
        /// <c>true</c> if the loader was successfully removed from the list, <c>false</c> otherwise.
        /// </returns>
        /// <remarks>
        /// This method behaves differently in the Editor and during runtime/Play mode. During runtime/Play mode, the loader
        /// will be removed with no additional side effects if it is in the list managed by this instance. While in the
        /// Editor and not in Play mode, the loader will be removed if it exists and
        /// it will be unregistered from this instance and any attempts to add it during
        /// runtime/Play mode will fail. You can re-add the loader in the Editor while not in Play mode.
        /// </remarks>
        public bool TryRemoveLoader(XRLoader loader)
        {
            var removedLoader = true;
            if (currentLoaders.Contains(loader))
                removedLoader = currentLoaders.Remove(loader);

#if UNITY_EDITOR
            if (!EditorApplication.isPlaying && !currentLoaders.Contains(loader))
                m_RegisteredLoaders.Remove(loader);
#endif

            return removedLoader;
        }

        /// <summary>
        /// Attempts to set the given loader list as the list of loaders managed by this instance.
        /// </summary>
        /// <param name="reorderedLoaders">
        /// The list of <see cref="XRLoader"/>s to be managed by this manager instance.
        /// </param>
        /// <returns>
        /// <c>true</c> if the loader list was set successfully, <c>false</c> otherwise.
        /// </returns>
        /// <remarks>
        /// This method behaves differently in the Editor and during runtime/Play mode. While in the Editor and not in
        /// Play mode, any attempts to set the list of loaders will succeed without any additional checks. During
        /// runtime/Play mode, the new loader list will be validated against the registered <see cref="XRLoader"/> types.
        /// If any loaders exist in the list that were not registered at startup, the attempt will fail.
        /// </remarks>
        public bool TrySetLoaders(List<XRLoader> reorderedLoaders)
        {
            var originalLoaders = new List<XRLoader>(activeLoaders);
#if UNITY_EDITOR
            if (!EditorApplication.isPlaying)
            {
                registeredLoaders.Clear();
                currentLoaders.Clear();
                foreach (var loader in reorderedLoaders)
                {
                    if (!TryAddLoader(loader))
                    {
                        TrySetLoaders(originalLoaders);
                        return false;
                    }
                }

                return true;
            }
#endif
            currentLoaders.Clear();
            foreach (var loader in reorderedLoaders)
            {
                if (!TryAddLoader(loader))
                {
                    currentLoaders = originalLoaders;
                    return false;
                }
            }

            return true;
        }

        private bool CheckGraphicsAPICompatibility(XRLoader loader)
        {
            GraphicsDeviceType deviceType = SystemInfo.graphicsDeviceType;
            List<GraphicsDeviceType> supportedDeviceTypes = loader.GetSupportedGraphicsDeviceTypes(false);

            // To help with backward compatibility, if the compatibility list is empty we assume that it does not implement the GetSupportedGraphicsDeviceTypes method
            // Therefore we revert to the previous behavior of building or starting the loader regardless of gfx api settings.
            if (supportedDeviceTypes.Count > 0 && !supportedDeviceTypes.Contains(deviceType))
            {
                Debug.LogWarning(String.Format("The {0} does not support the initialized graphics device, {1}. Please change the preffered Graphics API in PlayerSettings. Attempting to start the next XR loader.", loader.name, deviceType.ToString()));
                return false;
            }

            return true;
        }

        /// <summary>
        /// If there is an active loader, this will request the loader to start all the subsystems that it
        /// is managing.
        ///
        /// You must wait for <see cref="isInitializationComplete"/> to be set to true prior to calling this API.
        /// </summary>
        public void StartSubsystems()
        {
            if (!m_InitializationComplete)
            {
                Debug.LogWarning(
                    "Call to StartSubsystems without an initialized manager." +
                    "Please make sure wait for initialization to complete before calling this API.");
                return;
            }

            if (activeLoader != null)
            {
                activeLoader.Start();
            }
        }

        /// <summary>
        /// If there is an active loader, this will request the loader to stop all the subsystems that it
        /// is managing.
        ///
        /// You must wait for <see cref="isInitializationComplete"/> to be set to tru prior to calling this API.
        /// </summary>
        public void StopSubsystems()
        {
            if (!m_InitializationComplete)
            {
                Debug.LogWarning(
                    "Call to StopSubsystems without an initialized manager." +
                    "Please make sure wait for initialization to complete before calling this API.");
                return;
            }

            if (activeLoader != null)
            {
                activeLoader.Stop();
            }
        }

        /// <summary>
        /// If there is an active loader, this function will deinitialize it and remove the active loader instance from
        /// management. We will automatically call <see cref="StopSubsystems"/> prior to deinitialization to make sure
        /// that things are cleaned up appropriately.
        ///
        /// You must wait for <see cref="isInitializationComplete"/> to be set to tru prior to calling this API.
        ///
        /// Upon return <see cref="isInitializationComplete"/> will be rest to false;
        /// </summary>
        public void DeinitializeLoader()
        {
            if (!m_InitializationComplete)
            {
                Debug.LogWarning(
                    "Call to DeinitializeLoader without an initialized manager." +
                    "Please make sure wait for initialization to complete before calling this API.");
                return;
            }

            StopSubsystems();
            if (activeLoader != null)
            {
                activeLoader.Deinitialize();
                activeLoader = null;
            }

            m_InitializationComplete = false;
        }

        // Use this for initialization
        void Start()
        {
            if (automaticLoading && automaticRunning)
            {
                StartSubsystems();
            }
        }

        void OnDisable()
        {
            if (automaticLoading && automaticRunning)
            {
                StopSubsystems();
            }
        }

        void OnDestroy()
        {
            if (automaticLoading)
            {
                DeinitializeLoader();
            }
        }

        // To modify the list of loaders internally use `currentLoaders` as it will return a list reference rather
        // than a shallow copy.
        // TODO @davidmo 10/12/2020: remove this in next major version bump and make 'loaders' internal.
        internal List<XRLoader> currentLoaders
        {
            get { return m_Loaders; }
            set { m_Loaders = value; }
        }

        // To modify the set of registered loaders use `registeredLoaders` as it will return a reference to the
        // hashset of loaders.
        internal HashSet<XRLoader> registeredLoaders
        {
            get { return m_RegisteredLoaders; }
        }
    }
}

事情变的有趣起来,我们知道了这样的原理之后,那鱼蛋我就想着尝试下,在Runtime里动态切换行吧,SteamVR场景切换到OpenVR Loader,而XR场景切换到OpenXR,代码如下。

using System.Collections.Generic;
using Unity.XR.OpenVR;
using UnityEngine;
using UnityEngine.XR.Management;
using UnityEngine.XR.OpenXR;

namespace EgoGame
{
    /// <summary>
    /// 该类有问题,废弃了
    /// </summary>
    public class AutoXRLoader:MonoBehaviour
    {
        public List<XRLoader> xrLoaders;
        public List<XRLoader> vrLoaders;
        public bool isXR;
        
        private void Awake()
        {
            SetLoader(isXR);
        }

        private void OnDestroy()
        {
            SetLoader(!isXR);
        }
        
        void SetLoader(bool xr)
        {
            //不这样,会频繁的退出loader,VR会没画面
            if (xr && XRGeneralSettings.Instance.Manager.activeLoader is OpenXRLoader)
            {
                return;
            }
            if (!xr && XRGeneralSettings.Instance.Manager.activeLoader is OpenVRLoader)
            {
                return;
            }
            var loaders = xr ? xrLoaders : vrLoaders;

            Debug.Log("切换Loader:" + xr+"=="+XRGeneralSettings.Instance.Manager.activeLoader);
            XRGeneralSettings.Instance.Manager.DeinitializeLoader();
            XRGeneralSettings.Instance.Manager.TrySetLoaders(loaders);
            XRGeneralSettings.Instance.Manager.InitializeLoaderSync();
            XRGeneralSettings.Instance.Manager.StartSubsystems();
        }
    }
}

果然奏效了,XR场景能在头盔里识别并运行了,手柄也能控制。但是,切到SteamVR场景就出现了问题,Steam VR SDK报错了,报错提示有另一个应用在使用SteamVR。

最后的结果就是,没法实现动态切换XR或VR,如果看到此处的人,有办法请告诉我,我尝试了两天用了各种办法,都没法做到。

最后推荐大家开发VR应用不要直接用SteamVR SDK或XR SDK或Oculus SDK开发,而是用那些集成的插件,如VR Interaction Framework、VRTK等,这样在多个VR设备也能快速部署。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/690004.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【YOLOV8】4.图片分类-训练自己的数据集

Yolo8出来一段时间了,包含了目标检测、实例分割、人体姿态预测、旋转目标检测、图像分类等功能,所以想花点时间总结记录一下这几个功能的使用方法和自定义数据集需要注意的一些问题,本篇是第四篇,图像分类功能,自定义数据集的训练。 YOLO(You Only Look Once)是一种流行的…

【生产排查】解决 Kettle 没有运行日志的问题

文章目录 背景排查解决第 1 步:修改 kettle-service.conf,添加日志配置第 2 步:使用最新配置文件重启 kettle第 3 步:验证日志配置是否生效背景 🚀 项目使用 Kettle 作为 ETL 工具,从外部系统中抽取数据、转换数据、并最终加载到本项目的数据库中。 😂 存在的问题:据…

Vue3【十】07使用ref创建基本类型的响应式数据以及ref和reactive区别

Vue3【十】07使用ref创建基本类型的响应式数据以及ref和reactive区别 ref 也可以创建对象类型的响应式数据&#xff0c;不过要使用.value ref 处理对象数据的时候&#xff0c;底层数据还是reactive格式的 reactive 重新分配一个新对象&#xff0c;会失去响应式可以使用Object.a…

重生奇迹MU格斗家技能

格斗家有9个技能&#xff0c;其中幽冥青狼拳.斗气爆裂拳.神圣气旋.这3个是武器上带的技能。 回旋踢.幽冥光速拳.炎龙拳.这3个是买羊皮纸学的技能&#xff08;回旋踢是格斗最强技能&#xff09;。 还有3个给自己加BUFF的技能&#xff0c;斗神破&#xff08;增加无视防御的状态&…

Linux lvm卷扩容之SSM

介绍 SSM&#xff08;System Storage Manager&#xff09;是系统存储管理器&#xff0c;它是一种统一的命令行界面&#xff0c;用于管理各种存储设备。通过SSM&#xff0c;用户可以方便地管理、配置和监控存储系统。检查关于可用硬驱和LVM卷的信息。显示关于现有磁盘存储设备、…

专为Mac设计的窗口管理Magnet 中文

Magnet是一款专为Mac设计的窗口管理工具软件。它具备强大的多窗口管理能力&#xff0c;支持用户通过简单的拖放操作&#xff0c;将应用程序窗口快速对齐、排列和分组。此外&#xff0c;Magnet还提供了预设的布局选项和自定义设置功能&#xff0c;帮助用户实现个性化的窗口布局。…

Html/HTML5常用标签的学习

课程目标 项目实战&#xff0c;肯定就需要静态网页。朝着做项目方式去学习静态网页。 01、编写第一个html工程结构化 cssjsimages/imgindex.html 归档存储和结构清晰就可以。 02、HTML标签分类 认知&#xff1a;标签为什么要分类&#xff0c;原因因为&#xff1a;分门别类…

【java】速度搭建一个springboot项目

使用软件&#xff1a;IDEA&#xff0c;mysql 使用框架&#xff1a;springboot mybatis-plus druid 坑点 使用IDEA搭建一个springboot项目的时候&#xff0c;需要考虑一下IDEA版本支持的JDK版本以及maven版本。否则再构建项目&#xff0c;引入pom的时候就会报错。 需要检查…

Tongweb7重置密码优化版*(by lqw )

如图所示&#xff0c;输入初始密码是会报错的&#xff0c;说明已经修改了密码 首先我们先备份一下tongweb的安装目录&#xff0c;避免因为修改过程中出现的差错而导致tongweb无法启动&#xff1a; 备份好了之后&#xff0c;我们关闭掉tongweb。 方式一&#xff1a; Cd 到tong…

近期面试HW中级蓝问题(非常详细)零基础入门到精通,收藏这一篇就够了

01 — HW问题 1.sqlmap拿shell的原理&#xff0c;需要什么条件&#xff0c;–os-shell的原理 2.冰蝎的流量特征 3.哥斯拉的流量特征 4.如果判断一个web是s2写的 5.fastjson了解嘛&#xff1f;Log4j了解嘛&#xff1f;如何在流量中发现Log4j的攻击特征 6.HW前的准备工作…

【爬虫】使用Python爬取百度学术页面的标题、作者、摘要和关键词

目录 安装所需库编写爬虫代码解释运行脚本结果 在本文中&#xff0c;我将介绍如何使用Python编写一个网络爬虫&#xff0c;从百度学术页面提取研究论文的标题、作者、摘要和关键词。我们将使用 requests和 BeautifulSoup库来实现这一目标。 安装所需库 首先&#xff0c;确保…

【Python错误】:AttributeError: ‘generator‘ object has no attribute ‘next‘解决办法

【Python错误】&#xff1a;AttributeError: ‘generator’ object has no attribute next’解决办法 在Python中&#xff0c;生成器是一种使用yield语句的特殊迭代器&#xff0c;它允许你在函数中产生一个值序列&#xff0c;而无需一次性创建并返回整个列表。然而&#xff0c;…

为什么说组合优于继承?

在编程中&#xff0c;继承和组合是用于在面向对象语言中设计和构建类和对象的两种基本技术。 继承&#xff0c;它允许一个类&#xff08;称为派生类或子类&#xff09;从另一个类&#xff08;称为基类或超类&#xff09;继承属性和行为。换句话说&#xff0c;子类“是”超类的…

防汛应急排涝泵车的特点,有哪些用途

一、产品概述 移动柴油水泵机组又称移动拖车泵&#xff0c;它采用柴油作为燃料&#xff0c;通过内燃机的工作原理将化学能转化为机械能&#xff0c;进而驱动水泵进行抽水或输送任务。这种机组广泛应用于消防、市政应急给水、农业灌溉、防洪抢险等多个领域&#xff0c;其灵活性…

Pyinstaller安装与使用

一、Pyinstaller简介 PyInstaller将Python应用程序冻结(打包)独立可执行文件中。它可以构建较小的可执行文件,它是完全多平台的,并且使用OS支持来加载动态库,从而确保完全兼容。 二、Pyinstaller安装 1、下载安装 首先安装“pip install pywin32” 其次“pip install …

从GPT-4提取关键特征:Extracting Concepts from GPT-4

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,所以创建了“AI信息Gap”这个公众号,专注于分享AI全维度知识,包括但不限于AI科普,AI工具测评,AI效率提升,AI行业洞察。关注我,AI之…

Visual Studio 调试 Win32 出现 Task Manager / Explorer 无法打开,无法关机/重启

现象 Access is denied 无法关机 无法通过开始 -> 关机/重启 进行关机或者重启 无法打开新的应用 无法通过开始 -> 双击应用打开新的应用 已打开应用的使用不受影响 已经打开的应用可以正常操作 原因 杀毒软件&#xff1b;关掉杀毒软件就好了 问题查找过程 参考…

了解光伏储能技术的应用场景和优势

光伏发电是指利用太阳能电池板将太阳光转化为电能的过程。其优点在于清洁、高效、可再生&#xff0c;但光伏发电需要同时也存在间歇性和不稳定性问题。为了解决这一问题&#xff0c;光伏储能技术得到了广泛应用。其基本原理是将白天无法消耗的电能储存起来&#xff0c;以供需要…

海宁代理记账公司-专业的会计服务

随着中国经济的飞速发展&#xff0c;企业的规模和数量日益扩大&#xff0c;在这个过程中&#xff0c;如何保证企业的财务活动合规、准确无误地进行&#xff0c;成为了每个企业面临的重要问题&#xff0c;专业、可靠的代理记账公司应运而生。 海宁代理记账公司的主要职责就是为各…

无人机电机选型

2306的意思是电机定子直径23MM&#xff0c;定子高度6MM.在相同KV值的情况下电机的定子体积越大&#xff0c;扭矩越大&#xff1a;KV的意思是每增加1V的电压电机转速增加多少。同参数的电机KV越低&#xff0c;在低速的情况下能带动更大的质量。这也就解释了竞速机选用更高KV值的…