跨游戏引擎的H5渲染解决方案(腾讯)

news2024/11/14 16:49:57

本文是腾讯的一篇H5 跨引擎解决方案的精炼。

介绍

本文通过实现基于精简版的HTML5(HyperText Mark Language 5)来屏蔽不同引擎,平台底层的差异。 好处: 采用H5的开发方式,可以将开发和运营分离,运营部门自主开发的运营活动不依赖于游戏发版本的节奏。

如需要开发游戏周边系统会遇到如下4个问题:

1  每个游戏使用不同引擎时,周边系统是否可以不考虑引擎差异

2  每个游戏都有自己的开发版本的节奏。运营开发是否可以不跟随。

3  不同游戏, 不同引擎 不同平台 开发方式是否可以保持一致

4 这套开发方式 是否可以和游戏引擎开发的系统在交互 操作 性能保持一致。

一个想法是在游戏内嵌入 WebView, 然而这种方式对于 4 这种方案不会支持。为了解决 4 这种方案,腾讯推出了新的解决方案。

H5 ES 标准提出(HTML 5 Embeded System)

精简的H5有如下能力

  HTML CSS JS 代码的解析能力

  核心标签的支持, 包括DIv, Script, Style, Img, Text.

  核心DOM API 支持,事件机制

   背景 边框 图片(GIF动图) 文本渲染

   FlexBox

   CSS Animation, Transform

    视频播放,直播

    WebSocket XMLHttpRequest  支持Wss Https。

为了实现上面提到的基元操作,可以考虑吧对应的操作抽象为一系列的接口,宿主程序实现对应的接口就可以完成对于的操作。有如下2中抽象模式

        完全自己渲染

        抽象为接口,要求宿主对应的实现

如果是完全自己渲染,则1需要考虑不同平台和图形系统,做法和游戏引擎自身实现的跨平台抽象是一致的。一般做法是抽象为RHI,RHI分装了 OpenGL Vulkan DirectX 等图形API,通过使用这样的抽象的APi来实现上层的UI渲染,吧UI渲染到RenderTarget,在不同引擎渲染RenderTarget,这样就可以实现不同引擎内跨平台的渲染一致的UI。

这样的作法有几个问题:

问题一: RHI的封装

要实现RHI,其实有很多问题。例如如何实现RHI, RHI需要多大Code Size, 如何保证RHI封装不会和其他的RHI引擎冲突。

首先我们使用的是GitHub上的一个开源的bgfx,它实现了对所有API封装,非常聚焦。

bgfx总共2.2MB代码段同时提供了 bimg和bx2个库,用于图形解码和函数基础库,这正好做UI必备。

修改bgfx的创建设备流程,使他可以接受一个外部图形API运行时的指针。还需要修改一些Clear, Present等流程。让bgfx在RenderTarget上工作。

用bgfx来桥接的话,(会有问题)会不会对引擎RHI状态侵入?例如,引擎自身的RHI通过逻辑而不是查询硬件状态记录了RenderState,那么bgfx跳过了RHI进行渲染,会不会破坏渲染状态?

问题二: 额外的RenderTarget负担

将UI渲染到贴图是需要额外的RenderTarget内存开销,这部分开销随渲染的UI的尺寸不同而不同。如果1024 * 768像素渲染一个整屏的UI,那么将需要 3MB 的内存, 目前主流手机分辨率一般都在2K以上,那么这部分内存可能超过10MB,这无论如何都无法接受。

如果不使用RenderTarget会怎么样?如果不使用RenderTarget,可以考虑的方案是吧UI直接渲染到BackBuffer上,一般在Present之前,就将UI覆盖在引擎所有画面之上,包括引擎自身的UI。

这种问题无法控制UI与现有的游戏引擎UI的层级关系,也无法让他嵌入现有的UI系统里协同工作,只能硬生生的覆盖在上面,这在实际的工作中是无法接受的。为此只能使用RenderTarget,从而避免UI层级和UI协同的问题,因为通过RenderTarget可以把UI渲染到任何现有UI层级之上,甚至渲染到3D场景中。

问题三: 抽象为接口问题

如果将绘制能力抽象为少数接口,并由宿主来完成,就不需要实现整套的RHI解决方案,这样能

减少运行时的代码段,不需要RenderTarget,减小运行时内存,还能灵活运用现有引擎的UI交互能力,不会出现层级问题,

        在这里有3种思路, 如下:

        * 抽象为RHI,要求宿主实现RHI

        *抽象为对象接口,要求宿主实现图元对象

        *抽象为图元绘制接口,要求宿主实现图元绘制能力

抽象RHI的代码如下:

class RHI
{
public:
    virtual VertexBuffer* CreateVertexBuffer(...) = 0;
    virtual Texture* CreateTexture(...) = 0;
    ...
};

基本想法就是要求宿主实现RHI,基于这些RHI完成绘制,并将最终的渲染指令流转到引擎的渲染管线。这个想法简单直接,非常易于集成,如果单独考虑Unreal Engine,那么基本上使用这种抽象就可以了。这种抽象形式时Unity引擎里不太容易控制,虽然Unity 提供了Low LevelPlugin 系统,但这套系统尚不完善,没有完成RHI的封装,需要自己制作,而且Low Level Plugin结果很难控制,无法和Unity本身的UI系统很好的结合。在Unity 5 之后,Unity引入一套Command Buffer系统,这套系统也可以完成自定义渲染,但问题是和Low LevelPlugin类似。

        抽象为对象接口的代码如下:

class IH5Host
{
    public:
        Text* createText(...);
        Image* createImage(...);
        Border* createBorder(...);
}

这样抽象适合于Unity系统,可以把基本图元转换为·Unity系统里的Text,Image对象。这样抽象后会产生对象管理问题(生命周期, 对象控制),会产生不一致。

一种折中方案时根据DOM对象树来建立一颗渲染树,2边基于渲染树来渲染。

抽象为图元绘制接口:

class IH5Render
{
   public:
        void paintText(...);
        void paintImage(...); 
        void paintBackGround(...);
        void paintBorder(...); 
}

图元绘制接口和对象接口的差别是,图元绘制接口每帧都有需要调用,无状态,而对象接口构造调用一次,析构调用一次,有状态,需要自行管理生命周期。UE4就采用了我图元绘制接口,在FSlateDrawElement类种,抽象为图元绘制接口如下

class FSlateElement
{
	SLATECORE_API static void MakeBox( 
		FSlateWindowElementList& ElementList,
		uint32 InLayer,
		const FPaintGeometry& PaintGeometry,
		const FSlateBrush* InBrush,
		ESlateDrawEffect InDrawEffects = ESlateDrawEffect::None,
		const FLinearColor& InTint = FLinearColor::White );


	UE_DEPRECATED(4.20, "Storing and passing in a FSlateResourceHandle to MakeBox is no longer necessary.")
	SLATECORE_API static void MakeBox(
		FSlateWindowElementList& ElementList,
		uint32 InLayer, 
		const FPaintGeometry& PaintGeometry, 
		const FSlateBrush* InBrush, 
		const FSlateResourceHandle& InRenderingHandle, 
		ESlateDrawEffect InDrawEffects = ESlateDrawEffect::None, 
		const FLinearColor& InTint = FLinearColor::White );

	SLATECORE_API static void MakeRotatedBox(
		FSlateWindowElementList& ElementList,
		uint32 InLayer, 
		const FPaintGeometry& PaintGeometry, 
		const FSlateBrush* InBrush, 
		ESlateDrawEffect,
		float Angle,
		TOptional<FVector2d> InRotationPoint,
		ERotationSpace RotationSpace = RelativeToElement,
		const FLinearColor& InTint = FLinearColor::White );

	SLATECORE_API static void MakeRotatedBox(
		FSlateWindowElementList& ElementList,
		uint32 InLayer,
		const FPaintGeometry& PaintGeometry,
		const FSlateBrush* InBrush,
		ESlateDrawEffect InDrawEffects = ESlateDrawEffect::None,
		float Angle = 0.0f,
		TOptional<FVector2f> InRotationPoint = TOptional<FVector2f>(),
		ERotationSpace RotationSpace = RelativeToElement,
		const FLinearColor& InTint = FLinearColor::White);

........
}

这个类时图元绘制接口,UE4中的空间都是基于这个类提供的方法来绘制UI元素的,同时会根据绘制的调用顺序来考虑合批操作(Batch),这样调用的接口就自动具备了合批能力。

考虑到不同引擎的实现复杂度,包括在·自研引擎这种没有很好的对象体系来说明的引擎中容易集成,最终的做法是抽象为图元绘制接口。在UE4中可以无缝衔接,在Unity有点麻烦。

我们吧H5 ES页面的解析,加载,排版,渲染抽象等接口统称为UI前端,把不同引擎实现的渲染接口统称为后端,如图

渲染后端的实现

讨论完了架构,下面介绍如何在当前主流的2个商业引擎和自研引擎上具体实现相关功能。

UE4

UE4引擎提供Plugin机制,能够轻松将扩展功能放入Plugin插件中,基于Plugin的模式可以很好的实现UE4后端渲染。作为UE4扩展UI的组件需要遵循以下3个原则:

        1 去除引擎定制化功能,版本需要通用。

        2 符合UE4的UI通用风格。

        3 保持渲染效率和性能一致性。

通过参考UE4的Slate UI的实现方式,在满足以上3个原则的同时可以自定义封装一个UMG的UI控件,用户可以在编辑蓝图的可视化时使用,并在蓝图中调用相关的接口功能。

1 UE4的渲染实现

        继承UWidget(UMG基类)和SWidget(SlateUI基类)这2个基类,并实现自定义Custom UI组件。

FSlateDrawElement::MakeText // 绘制字体
FSlateDrawElement::MakeLines // 绘制线条
FSlateDrawElement::MakeBox // 绘制图片 矩形

2 UE4的资源管理

核心的资源管理通过句柄来关联,资源的生命周期通过引用计数来控制,目前用到的句柄分为一下3种。

        绘制上下文:此外指临时上下文,由绘制方自行管理,H5的内核绘制·只进行上下文透传处理。

        贴图资源:贴图绘制的资源对象

        字体资源:文字绘制的资源对象

H5的内核通过句柄对象的引用计数来管理对应句柄的生命周期。例如,打开动态页面A使用font和image就会通过资源管理器获取是否存在,存在引用就会加加,如果则调用对应的创建接口来通知引擎需要创建资源,引擎通过创建返回句柄值。

绘制上下文是一个临时句柄对象,内核不需要创建此对象,并且使用比较简单。在UE4中由SWidget::OnPaint发起绘制时,调用H5::Paint(HANDLE device)就可以指定device对象对应绘制就会将此参数作为绘制参数传回。。如H5::DrawText(HANDLE device, ..);

资源使用如下:

贴图资源,(字体资源也一样)在UE4中,UTexture2D时用来管理贴图资源对象。当H5内核驱动来创建对象的时候,UE4端会将UTexture2D地址值最为参数传回给H5内核。将此贴图对象加入一个内核管理列表,通过H5的抽象绘制接口(DrawImage)将句柄信息关联到对应的UTexture2D对象,然后提供给FSlateDrawElement::DrawBox的渲染接口使用。

句柄销毁如下

如果关闭了页面,那么对对象的引用就会减1,如果引用计数为01就会销毁句柄,并通知UE4销毁资源。

3 UE4的特殊绘制

在H5中实际使用会用到一些特殊的图元,例如圆角头像,圆角边框等。在UE4中原始图元接口并不能直接支持,我们需要使用Shader才能高效实现。FSlateBrush支持Shader画刷, FSlateMaterialBrush数据FSlateBrush的派生类,可以通过Shader方式来特殊绘制。(实现细节可以查看 腾讯游戏开发精粹2 P254-257 )

4 UE4版本差异引发问题

接口变更可以根据不同宏去替换对应功能,以下是重点特例问题:

        问题1: FSlateBrsuh绘制参数的保持问题。

UE4 4.21之前版本使用FSlateBrush画刷绘制时,FSlateDrawElement并未保存画刷中的一些参数问题(Margin, Tiling, Mirror, UVRegion, DrawAs),支持有FSlateBrush本身的指针地址,这样会带来2个问题。

        FSlateBrush 安全性不能保证,因为游戏线程和渲染线程时不同的线程。

        相同的FSlateBrush不能使用在不同绘制参数上多次绘制。例如同一张贴图画刷 先绘制一张UVRegion从(0,0)到(1,1)的全图,在绘制一张 UVRegion(0.5,0.5)到(1,1)的半图,结果绘制了2张半图,因为在FSlateBrsh投递渲染指令到渲染队列的时候是以FSlateBrush指针的方式获取当前渲染指令的绘制参数的,所以相同的渲染队列里的相同FSlateBrush指针的渲染参数时相同的。

解决方案:

        在FSlateDrawElement中保存渲染参数并在提交渲染指令的时候使用FSlateDrawElement保持的渲染参数,(在UE4.21以后的版本修复了 FSlateDrawElement 使用DataPayload拷贝FSlateBrush绘制参数) 。

        当同一个FSlateBrush进行不同的渲染参数绘制时,使用新的FSlateBrush进行绘制;基本的方式是使用引用队列存储不同的绘制参数的FSlateBrush,并在绘制完成后Check FSlateBrsh引用情况,对于没有引用的进行安全的延迟释放。

        问题2:Slate UI的合批问题:

UE4.24之后的版本使用了新的合批算法,在进行文字合批的时候,遇到空格单字符 FSlateDrawElement不会计算字符绘制的顶点数和边数,而会把FSlateDrawElement当成一个未合批的缓存节点,如果最后一个绘制元素是字符空格,则此合批缓存节点的顶点偏移值恰好是缓存顶点队列的大小的值。在进行缓存节点合批时,不会判断需要合批节点是否是有效的值的顶点数,这样在合批的时候就会出现数组越界的情况,引发程序的Crash。

解决方案:

        修改源代码,将绘制顶点数为0的节点不进行合批操作。

        Plugin插件,使用H5页面绘制遇到空格单字符跳过绘制。

UE3

UE3不像UE4有系统UI管理模块,需要自己管理。所以采样动态库加载的方式(减少与引擎代码耦合度和资源管理) UE3绘制UI通过Canvas来绘制,因此我们需要自定义一类Canvas来管理,

Unity

UE4绘制接口可以称为  Immediate Mode接口,Unity UI系统提供了Immediate Mode接口的GUI系统,,由于效率,此系统只使用在编辑器模式下,在游戏环境中,使用UGUI,这样需要考虑将创建对象的接口转换为Immediate mode接口,同时也要考虑 C#和C++交互。

1 C++和C#通信

C#调用C++ 通过使用C++动态库导出方法符号在C#使用DllImport 指定导入的方法名称。

2 Unity3D渲染

Unity3D提供Low Level Plugin机制来扩展渲染,这套机制在早期由许多Bug所以不能很好的结合。

3 Unity3D和H5渲染结合

在Unity3D中,H5的渲染接口要对应RHI更上层机制,要按照下图方式来渲染。(渲染Box模型的基础图元)

       背景

       边框

       图片

       文字

因为使用的时Immediate mode模式接口来实现封装渲染指令,每一帧都要发送的话,太费了,所以我们使用渲染队列

4 接口转换

Unity3D提供了UI框架UGUI,渲染文本UGUI提供了渲染组件Text,Text基本满足大部分的渲染需求,当收到H5的渲染指令的同时,先根据渲染指令类型,创建对应的UGUI组件,然后渲染指令的信息应用到组件上。

5 渲染基本图形

除了图片文字等可以直接通过接口转换,还有一些接口,无法在UGUI找到合适的组件,如渲染线段,虚线,边框等,在这里我们使用UGUI中的渲染矢量图形,MaskableGraphics这个类型支持直接修改顶点信息功能,

6 控制信息

Unity3D通过使用Mask组件来控制一些空间是否显示。

7 性能优化

方案 :

       预先创建若干个组件。

       连接对应组件使用hash

       运算压力大的异步执行

       缓存预算结果

自研引擎

1 Present/Swap钩子

通过使用函数拦截可以在完成一帧渲染的同时执行额外的绘制指令,从而显示H5 UI

优点:

        宿主无感知

        没有额外的显存消耗

缺点:

        产出无中间态,永远覆盖在最上层。无法融入宿主UI

2 使用Render Target

RenderTarget本质时一个离屏输出区域,使用RenderTarget,宿主可以自由i的操作多个嵌入式窗口实例,并对其结构进行灵活组装,以实现各种复杂的融合效果。

3 使用RHI在包装

我们使用了bgfx的第三方渲染库来实现自研引擎扩展H5。方式类似于(UE)具体详见 腾讯游戏开发精粹2 P267-269

网络库

标准H5由2大网络设施,XmlHttpRequest和WebSocket前者解决单次调用问题,后者解决服务器推送问题,这2者本质都是HTTP,需要良好的封装,社区有大量有封装好的开源库例如libcurl/libwebsocket.但是作为一个嵌入式引擎,为减少代码体积,成为关注问题。

总结

在·介绍H5 UI设计抽象的IH5Render接口,在2大流行的商业引擎和自研引擎实现方式,对比3种方式的异同。

       在商业引擎中,我们关注如何找到商业引擎自带的绘制功能去表现H5的UI绘制单元,在自研引擎模式下,我们重做了一边商业引擎的路。

       同为商业引擎,在Unity3D和UE4也有很大的差别,UE4提供的接口更偏向于底层,而Unity3D中的接口更偏向于中层,基本上是通过生成场景图的节点加功能组件来承接IH5Render的输出。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新峰商城之订单(一):确认页面开发

新峰商城订单从生成到处理结束&#xff0c;主要以下几个流程&#xff1a; &#xff08;1&#xff09;提交订单&#xff08;商城用户发起&#xff09; &#xff08;2&#xff09;订单入库&#xff08;后台逻辑&#xff09; &#xff08;3&#xff09;支付订单&#xff08;商城…

人生小满胜万全

大家好,这里是大话硬件。 最近大家都在讨论房贷利率的问题,昨天晚上看到很多群里在发要降息的小道消息,但是今天早上看到央行发了通告不降息。 下午又在群里看到这个买房对比的截图。对于没买房的人来说,肯定在想,还好当时没有买啊。对于买了房的人来说,可能有些人也在想…

「漏洞复现」灵当CRM marketing/index.php SQL注入漏洞

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

Isaac Sim 跑Slam学习过程2024.9.20

# 本文随着时间逐渐增加内容&#xff0c;是学习笔记 # 诶怎么今天Isaac Sim 4.2.0 突然出现了&#xff0c;这哪来的时间再去试试新的.... 没有大佬带...自己学吧 希望使用仿真环境跑定位Slam&#xff0c;现在IMU在Isaac Sim中有现成的传感器模块&#xff0c;GPS则没有&am…

电商ISV 电商SaaS 是什么

Independent Software Vendors的英文缩写&#xff0c;意为“独立软件开发商” 软件即服务(SaaS) 指一种基于云技术的软件交付模式 订阅收费 这些公司叫做ISV软件供应商&#xff0c;通过SaaS服务交付收费 为什么会有电商ISV 从商家角度划分&#xff1a;有独立品牌商家、大商…

MySQL篇(SQL优化)(持续更新迭代)

目录 一、插入数据&#xff1a;Insert 1. 优化方案一&#xff1a;批量插入数据 2. 优化方案二&#xff1a;手动控制事务 3. 优化方案三&#xff1a;主键顺序插入&#xff0c;性能要高于乱序插入 4. 大批量插入数据 5. 案例 5.1. 创建表结构 5.2. 设置参数 5.3. load加载…

计算机毕业设计 基于Python的校园个人闲置物品换购平台 闲置物品交易平台 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Wireshark学习使用记录

wireshark 是一个非常好用的抓包工具&#xff0c;使用 wireshark 工具抓包分析&#xff0c;是学习网络编程必不可少的一项技能。 原理 Wireshark使用的环境大致分为两种:一种是电脑直连互联网的单机环境&#xff0c;另外一种就是应用比较多的互联网环境&#xff0c;也就是连接…

macOS 中搭建 Flutter 开发环境

如果你的 Mac 是 Apple silicon 处理器&#xff0c;那么有些 Flutter 组件就需要通过 Rosetta 2 来转换适配&#xff08;详情&#xff09;。要在 Apple silicon 处理器上运行所有 Flutter 组件&#xff0c;请运行以下指令来安装 Rosetta 2。 sudo softwareupdate --install-ro…

低代码可视化工具-uniapp页面跳转传参-代码生成器

uniapp页面跳转传参 在uni-app中&#xff0c;页面间的跳转和传参是一个常见的需求。uni-app提供了多种页面跳转方式&#xff0c;如uni.navigateTo、uni.redirectTo、uni.reLaunch、uni.switchTab、uni.navigateBack等&#xff0c;每种方式适用于不同的场景。以 页面跳转并传参…

【笔记】第三节 组织与性能

3.1 基本成分 3.2 微观组织特征 0.6-0.8C%碳素钢的组织为珠光体和少量的铁素体。 如何把组织和性能联系起来&#xff1f;德国克虏伯公司的研究——珠光体片间距与渗碳体片层厚度成比例&#xff1a; t s 0 ( ρ 15 ( C % ) − 1 ) ts_0(\frac{\rho}{15(C\%)}-1) ts0​(15(C%)…

【EtherCAT】CiA402简介

目录 1、CiA402是CANopen协议的子协议 2、CiA402是 用于驱动和运动控制的CANopen设备配置文件 3、 CiA402主要由三部分组成 4、CiA介绍 4.1、操作模式 4.2、对象字典 5、一般对象字定义 6、详细对象字定义 7、Profile position mode 8、Homing mode 9、 Position co…

【Unity踩坑】UI Image的fillAmount不起作用

在游戏场景中&#xff0c;我们经常在界面上展示进度条&#xff0c;当然有各种形状的&#xff0c;线性的&#xff0c;长方形的&#xff0c;圆形&#xff0c;环形等等。 Unity中实现这种效果的话&#xff0c;最基本的方法说是改变Image的fillAmout属性。 如果你是初次使用UI Ima…

如何安装1Panel面板并架设一个静态网站

我们通常要架设网站在vps上&#xff0c;就要用到面板&#xff0c;一般是宝塔&#xff0c;但这个面板收费项目较多&#xff0c;用着不太方便。相比宝塔面板&#xff0c;1panel面板是国内功能强大、操作简单、免费易学的Linux服务器管理面板。我们还可以使用一键代码来安装这个面…

新手教学系列——基于统一页面的管理后台设计(二)集成篇

在现代企业级应用中,后台管理系统不仅是业务运营的核心,还承担着数据管理、用户权限控制等重要功能。随着业务规模的不断扩大,系统架构逐渐向微服务转变,多个后端服务模块协同工作,如何高效地集成这些模块,确保系统的稳定性和可维护性,成为开发者亟需解决的问题。在《新…

网络丢包定位记录(一)

数据在Internet上是以数据包为单位传输的&#xff0c;单位为字节&#xff0c;数据在网络上传输&#xff0c;受网络设备&#xff0c;网络质量等原因的影响&#xff0c;使得接收到的数据少于发送出去的数据&#xff0c;造成丢包。 数据包接收、发送原理 发送数据包&#xff1a; …

刷题训练之字符串

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握字符串算法。 > 毒鸡汤&#xff1a;学习&#xff0c;学习&#xff0c;再学习 ! 学&#xff0c;然后知不足。 > 专栏选自&#xff1a;刷题…

2024年9月第3周AI资讯

阅读时间&#xff1a;3-4min 更新时间&#xff1a;2024.9.16-2024.9.20 目录 OpenAI 推出 o1&#xff1a;一种新的“推理”人工智能模型 微软为 Excel 和 Word 添加了更快的 Copilot World Labs 利用 AI 创建 3D 世界 AI 利用文本创建开放世界视频游戏 OpenAI 推出 o1&#x…

ESP32 JTAG 调试

前言 个人邮箱&#xff1a;zhangyixu02gmail.com本人使用的是 Ubuntu 环境&#xff0c;采用 GDB 方式进行调试。对于新手&#xff0c;我个人还是建议参考ESP32S3学习笔记&#xff08;0&#xff09;—— Vscode IDF环境搭建及OpenOCD调试介绍进行图形化的方式调试。如果是希望在…

Java反序列化利用链篇 | URLDNS链

文章目录 URLDNS链调用链分析Payload编写 系列篇其他文章&#xff0c;推荐顺序观看~ Java反序列化利用链篇 | JdbcRowSetImpl利用链分析Java反序列化利用链篇 | CC1链_全网最菜的分析思路Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链Java反序列化利用链篇 | URLD…