当前位置: 首页 > news >正文

Godot 4 源码分析 - 碰撞

碰撞功能应该是一个核心功能,它能自动产生相应的数据,比如目标对象进入、离开本对象的检测区域。

基于属性设置,能碰撞的都具备这样的属性:Layer、Mask.

在Godot 4中,Collision属性中的Layer和Mask属性是用于定义碰撞过滤的重要参数。它们允许控制哪些物体可以与该节点进行碰撞检测。

  1. Layer(图层):

    • Layer是所有节点都具有的属性,用于将节点分组到不同的图层中。Layer是一组位掩码(bitmask),每个位代表一个特定的碰撞图层。每个物体都可以分配一个或多个碰撞图层。通过将物体分配到特定的碰撞图层,可定义其所属的逻辑组
    • 每个节点可以属于一个或多个图层。你可以在节点的属性面板中的Layer部分选择一个或多个图层。
    • Layer属性定义了节点所属的图层。默认情况下,节点属于基本图层(Base Layer)。
    • 使用不同图层将场景中的节点分组,可以使你能够仅与特定图层上的节点进行碰撞检测。
  2. Mask(掩码):

    • Mask也是所有节点都具有的属性,用于指定该节点对碰撞的兴趣。Mask也是一组位掩码,用于指示物体可以与哪些碰撞图层的物体发生碰撞检测。每个物体都可以指定一个碰撞掩码。通过设置碰撞掩码,可定义物体与哪些碰撞图层的物体发生碰撞
    • 每个节点都有一个掩码值。可以在节点的属性面板中的Collision属性下设置掩码。
    • Mask属性定义了该节点对哪些图层的节点感兴趣,该节点将与这些图层中的其他节点进行碰撞检测。
    • 每个节点的掩码值是一个32位的整数,每一位代表一个图层。0表示不兴趣该图层,1表示兴趣该图层。可以使用位操作(如按位与和按位或)来设置和检查掩码值。

通过使用Layer和Mask属性,你可以灵活地控制碰撞检测,使得只特定图层中的节点相互交互。例如,你可以设置一个节点仅与属于某个特定图层的节点进行碰撞,而忽略其他图层的节点。

需要注意的是,为了让两个节点进行碰撞检测,它们的Layer和Mask需要同时满足一定条件。具体而言,一个节点的Layer值必须包含在另一个节点的Mask值中,同时另一个节点的Layer值必须包含在该节点的Mask值中。

通过合理设置Layer和Mask属性,可在Godot 4中创建精细且灵活的碰撞过滤系统,以实现各种复杂的物理效果和游戏机制。

假设有两个碰撞图层,一个是"Player",另一个是"Enemy"。有一个玩家角色和一些敌人,想要确保玩家和敌人之间发生碰撞,但是敌人之间不发生碰撞。

  • 对于玩家对象:将其分配到"Player"碰撞图层,并将其Collision Mask设置为"Enemy"的位掩码。这将使玩家只与"Enemy"图层的物体发生碰撞。

  • 对于敌人对象:将它们分配到"Enemy"碰撞图层,并将其Collision Mask设置为"Player"的位掩码。这将使敌人只与"Player"图层的物体发生碰撞。

对于敌人对象之间,可将它们分配到相同的碰撞图层并设置相应的碰撞掩码,以确保它们不会互相碰撞。

通过这种方式,可在复杂的场景中更精细地控制碰撞的交互,使碰撞逻辑更加清晰和可管理。

从理解角度来说,逻辑说起来复杂,技术上实现很简单

Layer与Mask应该都是32位整数,对象A有Layer与Mask属性,对象B也有Layer与Mask属性

如果 A.Layer & B.Mask 非零,则 A要与B发生碰撞

如果 A.Mask & B.Layer非零,则B要与A发生碰撞

还是有点绕,再多想一下,以下是我自己的想法,不一定正确:

其实,Layer与Mask都是逻辑概念,虚拟的。在真实场景中,A、B都占据相应的空间位置(3D)或平面位置(2D),在运行过程中,A、B至少有一个能动,它们的相对位置可能会变化,在某个时刻会有交叠。这个时候,godot引擎知道,因为它能实时计算。那么,godot发现两个对象发生交叠了,怎么办呢?

那就检查A、B的Layer与Mask。

  • 如果 A.Layer & B.Mask 非零,则B能检测到A,触发B的body_entered信号,实参为A。
  • 如果 B.Layer & A.Mask 非零,则A能检测到B,触发A的body_entered信号,实参为B。

其实上面的说法不严谨,因为body_entered信号不应该连续发送,而是有个进出状态。整体连起来应该就是:

  • A、B分别维护自己的body_map,知道与自己交叠的对象列表。这个工作不能交给godot引擎做,它多忙的,还是各自管好自己的事
  • 从源码看出,检测进出的状态标志,还是A、B自己完成,也就是说,遍历所有的监控对象monitored_bodies,看与自己的??状态E->value,若为0,则啥事没有,不再监控该对象。如果>0,则为AREA_BODY_ADDED,表示进入。如果<0,则为AREA_BODY_REMOVED,表示离开。
void GodotArea2D::call_queries() {if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) {if (monitor_callback.is_valid()) {Variant res[5];Variant *resptr[5];for (int i = 0; i < 5; i++) {resptr[i] = &res[i];}for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_bodies.begin(); E;) {if (E->value.state == 0) { // Nothing happenedHashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_bodies.remove(E);E = next;continue;}res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;res[1] = E->key.rid;res[2] = E->key.instance_id;res[3] = E->key.body_shape;res[4] = E->key.area_shape;HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_bodies.remove(E);E = next;Callable::CallError ce;Variant ret;monitor_callback.callp((const Variant **)resptr, 5, ret, ce);if (ce.error != Callable::CallError::CALL_OK) {ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(monitor_callback, (const Variant **)resptr, 5, ce));}}} else {monitored_bodies.clear();monitor_callback = Callable();}}if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) {if (area_monitor_callback.is_valid()) {Variant res[5];Variant *resptr[5];for (int i = 0; i < 5; i++) {resptr[i] = &res[i];}for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_areas.begin(); E;) {if (E->value.state == 0) { // Nothing happenedHashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_areas.remove(E);E = next;continue;}res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;res[1] = E->key.rid;res[2] = E->key.instance_id;res[3] = E->key.body_shape;res[4] = E->key.area_shape;HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_areas.remove(E);E = next;Callable::CallError ce;Variant ret;area_monitor_callback.callp((const Variant **)resptr, 5, ret, ce);if (ce.error != Callable::CallError::CALL_OK) {ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(area_monitor_callback, (const Variant **)resptr, 5, ce));}}} else {monitored_areas.clear();area_monitor_callback = Callable();}}
}
  • 根据是否为AREA_BODY_ADDED确定body_in标志。若为body_in,则触发tree_entered、tree_exiting信号,如果本对象在工作场景中,则触发body_entered,参数为node。顺便还触发了body_shape_entered信号,看着用吧。
  • 若body_in为false,则触发tree_entered、tree_exiting。如果本对象在工作场景中,则触发body_exited、body_shape_exited
void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {bool body_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;ObjectID objid = p_instance;Object *obj = ObjectDB::get_instance(objid);Node *node = Object::cast_to<Node>(obj);HashMap<ObjectID, BodyState>::Iterator E = body_map.find(objid);if (!body_in && !E) {return; //does not exist because it was likely removed from the tree}lock_callback();locked = true;if (body_in) {if (!E) {E = body_map.insert(objid, BodyState());E->value.rid = p_body;E->value.rc = 0;E->value.in_tree = node && node->is_inside_tree();if (node) {node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree).bind(objid));node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree).bind(objid));if (E->value.in_tree) {emit_signal(SceneStringNames::get_singleton()->body_entered, node);}}}E->value.rc++;if (node) {E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));}if (!node || E->value.in_tree) {emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);}} else {E->value.rc--;if (node) {E->value.shapes.erase(ShapePair(p_body_shape, p_area_shape));}bool in_tree = E->value.in_tree;if (E->value.rc == 0) {body_map.remove(E);if (node) {node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree));node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree));if (in_tree) {emit_signal(SceneStringNames::get_singleton()->body_exited, obj);}}}if (!node || in_tree) {emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);}}locked = false;unlock_callback();
}

到此,就该关注monitored_bodies,它在add_body_to_query、remove_body_from_query中维护


void GodotArea2D::add_body_to_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {BodyKey bk(p_body, p_body_shape, p_area_shape);monitored_bodies[bk].inc();if (!monitor_query_list.in_list()) {_queue_monitor_update();}
}void GodotArea2D::remove_body_from_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {BodyKey bk(p_body, p_body_shape, p_area_shape);monitored_bodies[bk].dec();if (!monitor_query_list.in_list()) {_queue_monitor_update();}
}

但这没看到Layer与Mask属性的作用。那就倒查。最终发现在GodotCollisionObject2D类中:

_FORCE_INLINE_ bool collides_with(GodotCollisionObject2D *p_other) const {return p_other->collision_layer & collision_mask;
}

果然,与猜测的一致。具体调用collides_with是在一些setup函数中。

bool GodotAreaPair2D::setup(real_t p_step) {bool result = false;if (area->collides_with(body) && GodotCollisionSolver2D::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {result = true;}process_collision = false;has_space_override = false;if (result != colliding) {if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {has_space_override = true;} else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {has_space_override = true;} else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {has_space_override = true;}process_collision = has_space_override;if (area->has_monitor_callback()) {process_collision = true;}colliding = result;}return process_collision;
}bool GodotBodyPair2D::setup(real_t p_step) {check_ccd = false;if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {collided = false;return false;}collide_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) && A->collides_with(B);collide_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) && B->collides_with(A);report_contacts_only = false;if (!collide_A && !collide_B) {if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {report_contacts_only = true;} else {collided = false;return false;}}//use local A coordinates to avoid numerical issues on collision detectionoffset_B = B->get_transform().get_origin() - A->get_transform().get_origin();_validate_contacts();const Vector2 &offset_A = A->get_transform().get_origin();Transform2D xform_Au = A->get_transform().untranslated();Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A);Transform2D xform_Bu = B->get_transform();xform_Bu.columns[2] -= offset_A;Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B);GodotShape2D *shape_A_ptr = A->get_shape(shape_A);GodotShape2D *shape_B_ptr = B->get_shape(shape_B);Vector2 motion_A, motion_B;if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_SHAPE) {motion_A = A->get_motion();}if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_SHAPE) {motion_B = B->get_motion();}bool prev_collided = collided;collided = GodotCollisionSolver2D::solve(shape_A_ptr, xform_A, motion_A, shape_B_ptr, xform_B, motion_B, _add_contact, this, &sep_axis);if (!collided) {oneway_disabled = false;if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_A) {check_ccd = true;return true;}if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_B) {check_ccd = true;return true;}return false;}if (oneway_disabled) {return false;}if (!prev_collided) {if (shape_B_ptr->allows_one_way_collision() && A->is_shape_set_as_one_way_collision(shape_A)) {Vector2 direction = xform_A.columns[1].normalized();bool valid = false;for (int i = 0; i < contact_count; i++) {Contact &c = contacts[i];if (c.normal.dot(direction) > -CMP_EPSILON) { // Greater (normal inverted).continue;}valid = true;break;}if (!valid) {collided = false;oneway_disabled = true;return false;}}if (shape_A_ptr->allows_one_way_collision() && B->is_shape_set_as_one_way_collision(shape_B)) {Vector2 direction = xform_B.columns[1].normalized();bool valid = false;for (int i = 0; i < contact_count; i++) {Contact &c = contacts[i];if (c.normal.dot(direction) < CMP_EPSILON) { // Less (normal ok).continue;}valid = true;break;}if (!valid) {collided = false;oneway_disabled = true;return false;}}}return true;
}

这就没有必要再跟下去了。至于这些setup函数什么时候被调用,可以用一个实际项目调试来看看。

主要核心思想是理解碰撞的Layer与Mask配置问题。

相关文章:

Godot 4 源码分析 - 碰撞

碰撞功能应该是一个核心功能&#xff0c;它能自动产生相应的数据&#xff0c;比如目标对象进入、离开本对象的检测区域。 基于属性设置&#xff0c;能碰撞的都具备这样的属性&#xff1a;Layer、Mask. 在Godot 4中&#xff0c;Collision属性中的Layer和Mask属性是用于定义碰撞…...

前端面试经典算法题

前言 现在面试流行考核算法&#xff0c;做过面试官&#xff0c;也被面试。问算法对面试官来说&#xff0c;是一种解脱&#xff0c;找出了一个看似很高明且能偷懒的办法选择人&#xff0c;避免了不知道问啥的尴尬&#xff1b;被面试者&#xff0c;也找到了一种新的面试八股文&am…...

ospf减少LSA更新

实验及实验要求 一、思路 1.根据区域划分IP地址 2.使公网可通---写缺省 3.使R3成为MGRE中心站点&#xff0c;R5、R6、R7为分支站点 4.一个个去配置ospf区域和RIP区域&#xff0c;确保每个区域配置无误 5.区域0要更改OSPF在接口的工作类型为broadcast &#xff0c;并使R3为…...

万字长文解析深度学习中的术语

引言 新手在学习深度学习或者在看深度学习论文的过程中&#xff0c;有不少专业词汇&#xff0c;软件翻译不出来&#xff0c;就算是翻译出来也看不懂&#xff0c;因为不少术语是借用其他学科的概念&#xff0c;这里整理了一些在深度学习中常见的术语&#xff0c;并对一些概念进…...

冠达管理投资前瞻:三星加码机器人领域 大信创建设提速

上星期五&#xff0c;沪指高开高走&#xff0c;盘中一度涨超1%打破3300点&#xff0c;但随后涨幅收窄&#xff1b;深成指、创业板指亦强势震动。截至收盘&#xff0c;沪指涨0.23%报3288.08点&#xff0c;深成指涨0.67%报11238.06点&#xff0c;创业板指涨0.95%报2263.37点&…...

24届近5年上海交通大学自动化考研院校分析

今天给大家带来的是上海交通大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、上海交通大学 学校简介 上海交通大学是我国历史最悠久、享誉海内外的高等学府之一&#xff0c;是教育部直属并与上海市共建的全国重点大学。经过120多年的不懈努力&#xff0c;上海交…...

【PDF密码】PDF文件不能打印,为什么?

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…...

LeetCode-Java(03)

9. 回文数 class Solution {public boolean isPalindrome(int x) {if (x < 0 || (x % 10 0 && x ! 0)) {return false;}int revertedNumber 0;while (x > revertedNumber) {revertedNumber revertedNumber * 10 x % 10;x / 10;}// 当长度为奇数时通过reverte…...

【Linux命令行与Shell脚本编程】第十六章 Shell函数

Linux命令行与Shell脚本编程 第一章 文章目录 Linux命令行与Shell脚本编程六.函数6.1.脚本函数基础6.1.1.创建函数6.1.2.使用函数 6.2.函数返回值6.2.1.默认的退出状态码6.2.2.使用return命令6.2.3.使用函数输出 6.3.函数中使用变量6.3.1.向函数传递参数6.3.2.在函数中处理变量…...

SpringCloud-Hystrix服务熔断与降级工作原理源码 | 京东物流技术团队

先附上Hystrix源码图 在微服务架构中&#xff0c;根据业务来拆分成一个个的服务&#xff0c;服务与服务之间可以相互调用&#xff08;RPC&#xff09;&#xff0c;在Spring Cloud可以用RestTemplateRibbon和Feign来调用。为了保证其高可用&#xff0c;单个服务通常会集群部署。…...

(一)react脚手架

1. react脚手架 react提供了一个用于创建react项目的脚手架库&#xff1a;create-react-app 项目的整体技术架构为&#xff1a;react webpack es6 eslint 使用脚手架开发的项目的特点&#xff1a;模块化、组件化、工程化 2. 创建项目并启动 # 第一步&#xff1a; 全局安…...

Typescript中的元组与数组的区别

Typescript中的元组与数组的区别 元组可以应用在经纬度这样明确固定长度和类型的场景下 //元组和数组类似&#xff0c;但是类型注解时会不一样//元组赋值的类型、位置、个数需要和定义的类型、位置、个数完全一致&#xff0c;不然会报错。 // 数组 某个位置的值可以是注解中的…...

SpringBoot的index首页的访问、自定义Favicon图标

目录 1. index首页1.1 index首页访问规则的源码1.2 index首页的访问 2. 自定义Favicon图标 1. index首页 1.1 index首页访问规则的源码 package org.springframework.boot.autoconfigure.web.servlet; ......省略部分......// SpringBoot给容器中放WebMvcConfigurationSuppor…...

【C++】C++文件操作-文本文件/二进制文件

0.前言 一、文本文件 1.写文件 代码 #include <iostream> using namespace std; #include <fstream> //头文件包含//************************************** //文本文件 写文件 void test01() {//1.包含文件 fstream//2.创建流对象ofstream ofs;//3.指导打开方式…...

java通过http网络url下载文件

Testpublic void test3() throws ParseException {String fileUrl "http://*****/123.pdf";String savePath "C:\\Users\\HHH\\Desktop\\文件\\123.pdf";try {URL url new URL(fileUrl);InputStream inputStream url.openStream();Path outputPath Pa…...

网络安全【黑客】自学

1.什么是网络安全&#xff1f; 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有…...

PCA和自动编码器:每个人都能理解的算法

一、说明 本文的主要重点是提供主成分分析 &#xff08;PCA&#xff09; 和自动编码器数据转换技术的直观信息。我不打算深入研究支撑这些模型的数学理论&#xff0c;因为已经有大量的资源可用。 二、pca降维和自编码 2.1 pca和自编码的共同点 自动编码器通过组合数据最重要的特…...

C++——STL容器【priority_queue】模拟实现

本章代码&#xff1a;优先级队列模拟实现、priority_queue文档 文章目录 &#x1f408;1. priority_queue介绍&#x1f984;2. priority_queue模拟实现&#x1f427;2.1 构造函数&#x1f427;2.2 建堆向下调整向上调整 &#x1f427;2.3 仿函数&#x1f427;2.4 push & po…...

SpringBoot实现文件记录日志,日志文件自动归档和压缩

&#x1f60a; 作者&#xff1a; Eric &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_47316183?typeblog &#x1f389; 主题&#xff1a;SpringBoot实现文件记录日志&#xff0c;日志文件自动归档和压缩 ⏱️ 创作时间&#xff1a; 2023年08月06日 文章目…...

MySQL 窗口函数

聚合函数作为窗口函数 设聚合函数为op语法结构&#xff1a; op(字段名A) over(partition by 字段名B order by 字段名C rows between D1 and D2) 其中&#xff1a; partition by&#xff1a;按照某一字段将数据进行分组 order by&#xff1a;按照某一字段将数据进行排序&…...

0140 数据链路层2

目录 3.数据链路层 3.6局域网 3.7广域网 3.8数据链路层设备 部分习题 3.数据链路层 3.6局域网 3.7广域网 3.8数据链路层设备 部分习题 1.如果使用5类UTP来设计一个覆盖范围为200m的10BASE-T以太网&#xff0c;需要采用的设备是&#xff08;&#xff09; A.放大器 …...

Python字典的应用场景

Python字典是一种无序、可变的数据类型&#xff0c;它由键值对组成。字典在Python中被广泛应用&#xff0c;以下是一些常见的应用场景&#xff1a; 数据存储和检索&#xff1a;字典可以用来存储和检索大量的数据&#xff0c;通过使用键来快速访问对应的值。例如&#xff0c;可以…...

关于外贸跟进客户过程中需要注意的地方

如果你感觉业务进展困难&#xff0c;多去看一些书&#xff0c;多去链接一些人&#xff0c;特别是优秀的人&#xff0c;多交流会让你思维更加开阔&#xff0c;笔记做好实践起来&#xff0c;就会有收获&#xff01; 我记得汪老师说过&#xff1a;跟进客户&#xff0c;当你准备好…...

AI绘画:两组赛博咒语和ComfyUI使用方法

虽迟但到啊&#xff0c;上次说过要发&#xff0c;必然是要发滴&#xff01; 本来我是可以直接发的&#xff0c;但是我又想着发关键词的同时&#xff0c;最好是讲解一下用法&#xff0c;这样更友好。所以就拖了一天&#xff01; 下面先展示一下两套咒语的效果&#xff1a; 这套…...

Nacos源码 (2) 核心模块

返回目录 整体架构 服务管理&#xff1a;实现服务CRUD&#xff0c;域名CRUD&#xff0c;服务健康状态检查&#xff0c;服务权重管理等功能配置管理&#xff1a;实现配置管CRUD&#xff0c;版本管理&#xff0c;灰度管理&#xff0c;监听管理&#xff0c;推送轨迹&#xff0c;聚…...

MySQL之深入InnoDB存储引擎——Buffer Pool

文章目录 一、空闲链表的管理二、缓冲页的哈希处理三、Flush链表的管理四、LRU链表的管理五、脏页刷新六、多Buffer Pool实例 InnoDB存储引擎是基于磁盘存储的&#xff0c;并将其中的记录按照页的方式进行管理。在数据库系统中&#xff0c;由于CPU速度与磁盘速度之间的鸿沟&…...

网络安全(秋招)如何拿到offer?(含面试题)

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;本套面试题&#xff0c;已整理成pdf文档&#xff0c;但内容还在持续更新中&#xff0c;因为无论如何都不可能覆盖所有的面试问题&#xf…...

笙默考试管理系统-MyExamTest----classranking(2)

笙默考试管理系统-MyExamTest----classranking&#xff08;2&#xff09; 目录 笙默考试管理系统-MyExamTest----classranking&#xff08;2&#xff09; 一、 笙默考试管理系统-MyExamTest----classranking 二、 笙默考试管理系统-MyExamTest----classranking 三、 笙…...

基于python的一个元素多种定位方式

基于 Python 的 Page Factory 设计模式测试库, 类似于Java的Page Factory模式&#xff0c;旨在减少代码冗余&#xff0c;简单易用&#xff0c;具有高度的可扩展能力。 支持以annotation的方式定义元素 支持同一个元素多种定位方式 支持动态的定位方式 安装 pip install pyth…...

Fastdfs集群搭建

一、简单介绍&#xff1a; FastDFS是一个开源的高性能分布式文件系统&#xff08;DFS&#xff09;。 它的主要功能包括&#xff1a;文件存储&#xff0c;文件同步和文件访问&#xff0c;以及高容量和负载平衡。主要解决了海量数据存储问题&#xff0c;特别适合以中小文件&…...