Godot引擎集成Lua脚本开发:PluginScript插件实战指南

news2026/5/3 6:24:19
1. 项目概述当Lua遇见Godot如果你是一个Godot引擎的开发者同时又对Lua脚本语言情有独钟那么你很可能和我一样曾经在两者之间纠结过。Godot自带的GDScript固然强大易用但在某些场景下比如需要热更新逻辑、复用已有的庞大Lua代码库或者单纯就是偏爱Lua的简洁与灵活时我们总会想要是在Godot里也能直接写Lua就好了。今天要聊的这个项目——godot-lua-pluginscript——就是为解决这个痛点而生的。它是一个基于GDNative和PluginScript技术的插件让你能在Godot 3.x项目中无缝地将Lua作为一门正式的脚本语言来使用。简单来说这个插件为Godot引擎增加了一个新的脚本语言类型.lua文件。你可以像创建GDScript脚本一样在编辑器中右键创建Lua脚本将其附加到任意节点上并且这个Lua脚本节点可以和场景中的GDScript、C#甚至Visual Script节点毫无障碍地通信、互相调用方法和访问属性。它的核心价值在于“无侵入性”和“无缝集成”。你不需要为了用Lua而去重新编译Godot引擎源码只需要把插件文件拖进你的项目重启编辑器一切就准备就绪了。这对于希望快速引入Lua能力或者想在已有Godot项目中部分模块尝试Lua的团队来说是一个极其友好的方案。重要提示这个插件仅适用于Godot 3.x版本。因为它底层依赖GDNative技术而Godot 4已经用GDExtension全面取代了GDNative。如果你正在使用Godot 4作者提供了另一个项目lua-gdextension作为替代方案。本文所有讨论都将围绕Godot 3环境下的godot-lua-pluginscript展开。2. 核心设计思路与架构解析2.1 为什么选择PluginScript要理解这个项目首先得明白Godot的PluginScript是什么。它不是指一个编辑器插件而是Godot引擎提供的一种允许第三方实现新脚本语言的API接口。通过实现PluginScript接口开发者可以“教”Godot认识一门新语言如何加载它的源文件、如何解析它的类定义、如何调用它的方法、如何管理它的对象生命周期等等。godot-lua-pluginscript正是实现了这一套接口。当Godot引擎遇到一个后缀为.lua的文件并且检测到这个插件已加载时就会将文件的加载、解释、执行等任务委托给这个插件。这样一来Lua在Godot内部就获得了和GDScript平起平坐的“一等公民”地位而不仅仅是一个通过某种桥接技术被动调用的外部库。2.2 GDNative的角色性能与安全的桥梁那么用C实现PluginScript接口不就行了吗为什么还要引入GDNative这里就涉及到一个关键权衡引擎模块与插件。如果直接用C编写一个引擎模块Module确实功能最强、性能最优但它需要用户重新编译整个Godot引擎这对于绝大多数独立开发者和中小团队来说门槛太高且不利于插件的分发和共享。而GDNative是Godot 3推出的原生插件系统它允许开发者用C、C等语言编译成动态链接库.dll、.so、.dylib在运行时被Godot加载。这带来了几个巨大优势免编译引擎用户只需将编译好的二进制文件放入项目即可使用。跨平台兼容插件作者为Windows、Linux、macOS等平台分别编译好库文件用户下载对应版本即可。相对安全GDNative插件运行在独立的地址空间即使插件崩溃也有较大概率不会直接拖垮整个Godot编辑器或游戏进程。因此godot-lua-pluginscript选择以GDNative库的形式实现PluginScript接口最大化地降低了使用门槛这也是它能在Godot Asset Library资源库上架、被普通用户一键安装的基础。2.3 LuaJIT FFI高效绑定的秘诀项目目前主要支持LuaJIT这又是一个关键的技术选型。LuaJIT不仅运行速度远超标准Lua其内置的FFIForeign Function Interface库更是本项目的基石。FFI允许Lua代码直接调用C函数和使用C数据结构而无需编写传统的Lua C绑定模块即编写lua_State操作的那套代码。通过FFI插件可以非常高效地将Godot的C类、方法、属性“映射”到Lua环境中。当你在Lua脚本中写OS:get_name()时底层是通过FFI直接调用了Godot引擎C层的OS::get_singleton()-get_name()方法。这种方式的性能损耗极低几乎接近于原生C调用同时极大地简化了绑定代码的复杂度。绑定代码不再需要处理繁琐的Lua栈操作而是声明好C函数原型剩下的交给FFI和LuaJIT。3. 环境配置与安装详解3.1 三种安装方式对比根据你的需求和开发习惯可以选择以下任意一种方式安装插件方式一通过Godot资源库安装推荐给绝大多数用户这是最傻瓜式的方法。在Godot编辑器内点击右侧的“AssetLib”标签页在搜索框中输入“Lua PluginScript”找到后点击下载并安装。Godot会自动将插件文件放置到res://addons/godot-lua-pluginscript/目录下。重启编辑器后你就可以在“创建资源”的菜单里看到“Lua Script”了。这种方式能确保你获取到的是经过测试的稳定发布版本。方式二手动放置预编译的二进制文件适合无法访问AssetLib或需要特定版本的情况。你需要从项目的GitHub Releases页面下载对应你操作系统和Godot版本的压缩包例如godot-lua-pluginscript-windows-64.zip。解压后确保整个addons/godot-lua-pluginscript文件夹被完整地复制到你的Godot项目的res://根目录下。关键是要保证lua_pluginscript.gdnlib这个库定义文件存在于上述路径中。之后同样需要重启Godot编辑器。方式三从源码编译适合开发者、需要修改插件或为目标平台如Android、iOS、Web定制编译的情况。你需要将整个Git仓库克隆到项目的res://addons/godot-lua-pluginscript目录。然后根据项目文档的构建指南使用SCons或你熟悉的C构建系统为目标平台编译GDNative库文件.dll/.so等。这种方式最灵活但要求你具备基本的C编译环境配置能力。3.2 安装后的验证与常见问题安装并重启编辑器后如何验证插件是否成功加载检查插件是否激活打开“项目” - “项目设置” - “插件”标签页。你应该能看到“Lua PluginScript”插件并且其状态是“已启用”。尝试创建Lua脚本在文件系统面板中右键选择“新建资源”在列表里应该能找到“Lua Script”。创建一个试试。检查输出日志如果插件加载失败Godot编辑器底部的“输出”面板通常会显示错误信息。常见问题包括架构不匹配下载的二进制文件是64位的但你运行的Godot是32位的或者反之。依赖缺失在Windows上可能会缺少msvcp140.dll等VC运行时库。安装最新的 Visual C Redistributable 通常可以解决。路径错误确保gdnlib和.dll/.so文件在正确的addons子目录下而不是直接扔在根目录。实操心得我个人的习惯是对于任何GDNative/GDExtension插件在首次安装后先创建一个最简单的测试场景一个节点挂一个Lua脚本脚本里只写一句print(“Hello from Lua!”)。运行场景如果在输出台看到这行字就证明插件从安装到运行的全链路都通了。这个简单的测试能避免很多后续的迷惑。4. Lua脚本编写入门与语法精讲4.1 脚本基本结构从GDScript到Lua的思维转换一个有效的Godot Lua脚本本质上是一个会返回一个Lua表的Lua模块。这个表就代表了你在Godot中定义的类。让我们对照GDScript来理解GDScript:extends Node class_name MyLuaNode signal my_signal export var my_number: int 10 func _ready(): print(“Hello from GDScript”)等价的Lua Script:local MyClass {} -- 设置继承对应 extends MyClass.extends Node -- 设置类名对应 class_name MyClass.class_name ‘MyLuaNode’ -- 声明信号 MyClass.my_signal signal() -- 定义属性对应 export var MyClass.my_number 10 -- 这是一个简单的属性但不会显示在编辑器面板 -- 使用 export 函数使其在编辑器可见 MyClass.my_exported_number export { 10, type int, hint PropertyHint.RANGE, hint_string “0, 100” } function MyClass:_ready() print(“Hello from Lua!”) end -- 最后必须返回这个类表 return MyClass关键点解析extends通过设置表的extends字段为字符串如“Node”来指定父类。默认为“Reference”。class_name通过class_name字段注册全局类名之后可以在GDScript中用MyLuaNode来引用它。signal()这是一个由插件注入的全局函数用于定义信号。带参数的信号写作signal(“arg1_type”, “arg2_type”)。export与property这是Lua脚本中功能最丰富的部分之一。export是property的语法糖专门用于创建在编辑器中可见和可编辑的属性。4.2 深入属性系统property函数的完全指南property函数接收一个表作为参数用于配置属性的所有元数据。理解这个配置表是编写高质量Lua脚本的关键。MyClass.complex_prop property { -- 位置1或键“default_value”: 默认值 100, -- 位置2或键“type”: Godot变量类型如 int, float, String, Vector2, Array, Dictionary 等 type int, -- 键“get”: 获取器可以是函数或方法名字符串 get function(self) return self._internal_value * 2 end, -- 键“set”: 设置器可以是函数或方法名字符串 set ‘set_complex_prop’, -- 键“usage”: 属性用途标志决定其行为 usage PropertyUsage.DEFAULT, -- 常见值DEFAULT, NOEDITOR, SCRIPT_VARIABLE -- 键“hint”: 属性提示影响编辑器中的UI控件 hint PropertyHint.RANGE, -- 键“hint_string”: 提示字符串格式依hint而定 hint_string “0, 1000, 10, or_greater”, -- 最小值最大值步长后缀标志 -- 键“rset_mode”: 网络RPC模式 rset_mode RPCMode.AUTHORITY, }常见hint与hint_string搭配示例Godot属性提示 (PropertyHint)对应hint_string格式示例编辑器中的效果RANGE“0, 100, 1”一个从0到100步长为1的滑块。ENUM“Slow,Medium,Fast”一个下拉选择框选项为Slow, Medium, Fast。FILE“*.png,*.jpg”一个文件选择对话框默认过滤png和jpg文件。DIR“”一个目录选择对话框。MULTILINE_TEXT“”一个多行文本编辑框。EXP_RANGE“0.01, 100, 0.01, or_greater, exp”一个指数滑动的数值滑块适合调节范围很大的值如音量。COLOR_NO_ALPHA“”一个不带透明度通道的颜色选择器。关于类型type的特别说明Lua本身只有number类型它同时代表整数和浮点数。但在Godot中int和float是严格区分的这会影响序列化、网络同步等。因此强烈建议在定义数值属性时总是明确指定type int或type float。或者在默认值处使用int(5)或float(3.14)这样的构造函数插件会从中推断出正确类型。4.3 方法、信号与节点操作方法定义和GDScript一样以_开头的方法是引擎回调如_ready,_process。其他方法都是自定义的公共方法。注意Lua的冒号语法function MyClass:method(...)它等价于function MyClass.method(self, ...)会自动传入self。信号连接与发射function MyClass:_ready() -- 连接信号 (参数目标对象 信号名 回调函数) self.some_child_node:connect(“button_pressed”, self, “_on_button_pressed”) end function MyClass:_on_button_pressed() -- 发射信号 self:emit_signal(“my_signal”, “some_data”) end访问节点Lua中没有GDScript的$NodePath语法糖。你必须使用get_node。function MyClass:_ready() -- 相当于GDScript中的 onready var sprite $Sprite self.sprite self:get_node(“Sprite”) -- 对于复杂的路径建议在_ready中一次性获取并缓存 self.anim_player self:get_node(“../../AnimationPlayer”) end使用单例Godot的所有引擎单例如OS,Input,Engine和自定义的单例节点都以全局变量的形式注入到了Lua环境中可以直接使用。local screen_size OS:get_window_size() local fps Engine:get_frames_per_second() if Input:is_action_just_pressed(“ui_accept”): print(“Enter key pressed!”)5. 高级特性与工程化实践5.1 模块系统与require路径插件修改了Lua标准的require搜索路径使其能够识别Godot的资源路径res://。这意味着你可以像组织普通Lua项目一样将代码模块化。假设你的项目结构如下res:// ├── main.lua (主场景脚本) └── lib/ ├── utils.lua └── enemy_ai.lua你可以在main.lua中这样引入模块-- 注意路径基于 res://不需要写后缀 .lua local utils require(“res://lib/utils”) local EnemyAI require(“res://lib/enemy_ai”) function Main:_ready() local helper_value utils.calculate_something() local enemy EnemyAI.new() end这对于构建大型游戏项目至关重要。你可以将通用函数、配置表、状态机、行为树等封装在独立的Lua模块中。注意事项require在Lua中是缓存加载的。同一个模块在第一次require后后续的require会直接返回已加载的模块表不会重复执行文件。这符合Godot资源加载的预期。但要小心循环依赖问题。5.2 协程与异步等待GD.yieldGodot中大量使用信号和异步回调。GDScript提供了yield关键字来优雅地等待。在Lua插件中这个功能由全局的GD.yield函数提供。场景等待一个计时器function MyClass:start_countdown(duration) local timer Timer.new() self:add_child(timer) timer:set_wait_time(1) -- 每秒触发一次 timer:start() for i duration, 1, -1 do print(“Countdown: “ .. i) -- 等待 “timeout” 信号。GD.yield返回两个值信号发射者信号名 local result_sender, result_signal GD.yield(timer, “timeout”) -- 通常我们只关心等待结束不关心返回值 end print(“Blast off!”) timer:queue_free() end场景等待一个HTTP请求function MyClass:fetch_data(url) local http_request HTTPRequest.new() self:add_child(http_request) http_request:connect(“request_completed”, self, “_on_request_completed”) http_request:request(url) -- 等待自定义信号 GD.yield(self, “http_data_received”) local data self._fetched_data -- ... 处理 data end function MyClass:_on_request_completed(result, response_code, headers, body) if result HTTPRequest.RESULT_SUCCESS then self._fetched_data body:get_string_from_utf8() self:emit_signal(“http_data_received”) end endGD.yield是编写清晰异步流程的关键它避免了“回调地狱”让代码保持线性思维。5.3 编辑器集成REPL与导出插件插件附带了一个强大的编辑器插件提供了两个核心功能1. Lua REPL交互式解释环境这是一个内置在Godot编辑器中的Lua命令行。你可以在编辑游戏时随时打开它默认快捷键可能需要在编辑器设置中查看或绑定执行Lua代码片段。这对于调试、快速测试函数、修改场景中对象的属性实时查看效果来说是无价之宝。例如你可以在REPL中输入-- 获取当前场景根节点 local root get_tree():get_root():get_child(0) -- 查找名为“Player”的节点并让其跳跃 local player root:find_node(“Player”, true, false) if player then player:jump() end2. 导出时脚本压缩Minify在发布游戏时你可能不希望源代码被轻易查看。这个导出插件可以集成到Godot的导出流程中在构建导出版本时自动压缩你的所有.lua脚本文件。它会移除注释、不必要的空格和换行符减小包体大小并增加一定的反编译难度。你可以在项目设置的“导出”选项中配置该插件。5.4 与LuaRocks集成高级对于需要复杂第三方Lua库的开发者插件文档提供了与LuaRocksLua的包管理器集成的指南。基本原理是使用LuaRocks将你需要的库安装到一个本地目录例如project/lua_modules。在Godot Lua脚本中通过修改package.path和package.cpath将这个目录添加到Lua的搜索路径中。然后就可以正常require这些库了。这为在Godot游戏中使用成熟的Lua网络库、JSON解析库、加密库等打开了大门。不过需要注意C语言编写的Lua模块.so/.dll需要针对你的目标平台尤其是移动端和Web进行交叉编译这可能带来额外的复杂性。6. 性能考量、局限性与最佳实践6.1 性能特点调用开销通过LuaJIT FFI调用Godot C方法开销非常小与GDScript的C绑定调用处于同一数量级在绝大多数游戏中可以忽略不计。内存管理Godot对象在Lua中是通过FFI的cdata进行引用的。Godot的引用计数机制依然有效。当Lua中不再引用某个Godot对象时其对应的cdata会被Lua垃圾回收但这不会减少Godot对象的引用计数。Godot对象的生命周期依然由Godot的引用计数和树形结构管理。这意味着你通常不需要在Lua中担心Godot对象的内存泄漏但也要遵循Godot的规则例如用add_child添加的节点需要用remove_child或queue_free来移除。LuaJIT的JIT编译热点代码频繁运行的循环、函数会被LuaJIT实时编译为机器码运行速度极快甚至可能接近C。这对于游戏中的战斗计算、AI逻辑等密集运算场景非常有利。6.2 已知局限性不支持多线程插件目前不支持Lua协程以外的多线程。你不能在Godot的子线程中安全地操作Lua状态。所有Lua代码都应在主线程执行。调试支持有限原生的Godot调试器可能无法直接调试Lua代码。你需要依赖打印日志print或使用第三方Lua调试器集成。插件文档提到了debugger.lua的集成可能性。编辑器代码提示缺失Godot编辑器对GDScript和C#有智能补全和错误检查但对Lua脚本目前只是一个文本编辑器。你需要依靠自己对Lua语法的熟悉或者使用外部Lua IDE如VSCode配合Lua插件进行辅助开发。仅限Godot 3这是由底层技术决定的必须再次强调。6.3 最佳实践与避坑指南明确类型如前所述始终为数值属性指定type int或type float。这是避免序列化和网络同步bug的最重要一步。缓存节点引用在_ready方法中获取并缓存需要频繁访问的节点引用避免每帧都调用get_node。get_node调用虽然不慢但在_process中频繁使用仍属浪费。善用局部变量Lua中访问局部变量比访问全局变量或表字段快得多。在性能关键的循环中将self.some_property或全局的Vector2等构造函数存入局部变量。function MyClass:_process(delta) local pos self.position -- 缓存到局部变量 local Vector2 Vector2 -- 缓存全局构造函数 for i 1, 1000 do -- 使用局部变量 pos 和 Vector2 pos pos Vector2(1, 0) end self.position pos -- 最后写回 end信号管理在对象销毁_exit_tree前记得断开disconnect所有由该对象连接的外部信号或者断开连接到该对象的所有信号以防止回调已销毁对象导致错误。错误处理Lua代码中的运行时错误比如访问nil值会触发Godot脚本错误。使用pcall保护调用来包裹可能出错的代码块可以提供更友好的错误恢复。function MyClass:risky_operation() local success, err pcall(function() -- 可能出错的代码 self.some_missing_method() end) if not success then print(“An error occurred:”, err) -- 执行错误恢复逻辑 end end代码组织即使是小项目也尽量将代码模块化。将工具函数、常量定义、管理器类分别放在不同的res://lib/模块中。这会让你的代码更清晰也更易于复用。7. 实战构建一个简单的Lua脚本组件让我们通过一个完整的、有实际意义的小例子将上述知识点串联起来。我们将创建一个HealthComponent生命值组件它可以被挂载到任何敌人或玩家节点上管理生命值、伤害、治疗以及死亡事件。1. 创建脚本在Godot编辑器中右键 - 新建资源 - Lua Script命名为health_component.lua。2. 编写组件代码local HealthComponent {} HealthComponent.extends “Node” HealthComponent.class_name “HealthComponent” -- 定义信号生命值改变、死亡 HealthComponent.health_changed signal(“new_health”, “old_health”) HealthComponent.died signal() -- 定义属性最大生命值、当前生命值 HealthComponent.max_health export { 100, type int, hint PropertyHint.RANGE, hint_string “1, 1000” } HealthComponent.current_health property { 100, type int, get function(self) return self._current_health or self.max_health end, set function(self, value) local old_health self.current_health -- 将生命值钳制在 0 ~ max_health 之间 self._current_health math.max(0, math.min(value, self.max_health)) -- 发出生命值改变信号 self:emit_signal(“health_changed”, self._current_health, old_health) -- 检查死亡 if self._current_health 0 and old_health 0 then self:emit_signal(“died”) end end } -- 初始化 function HealthComponent:_ready() -- 确保current_health被正确初始化触发setter self.current_health self.max_health end -- 公共方法造成伤害 function HealthComponent:take_damage(amount, damage_source) if amount 0 then return end print(string.format(“%s takes %d damage from %s”, self:get_parent():get_name(), amount, tostring(damage_source))) self.current_health self.current_health - amount end -- 公共方法进行治疗 function HealthComponent:heal(amount) if amount 0 then return end self.current_health self.current_health amount end -- 公共方法检查是否存活 function HealthComponent:is_alive() return self.current_health 0 end -- 公共方法重置生命值 function HealthComponent:reset() self.current_health self.max_health end return HealthComponent3. 在场景中使用创建一个KinematicBody2D节点作为敌人命名为Enemy。为Enemy添加一个Sprite和CollisionShape2D。将health_component.lua脚本附加到Enemy节点上。你会在检查器面板看到导出的max_health属性。再创建一个Area2D作为攻击区域挂上脚本检测玩家进入并调用敌人的HealthComponent。4. 在GDScript中与Lua组件交互# 在玩家的攻击脚本中 (GDScript) func _on_AttackArea_body_entered(body): if body.has_node(“HealthComponent”): var health_comp body.get_node(“HealthComponent”) # 直接调用Lua组件的方法 health_comp.take_damage(10, self) # 连接Lua组件发出的信号 if not health_comp.is_connected(“died”, self, “_on_enemy_died”): health_comp.connect(“died”, self, “_on_enemy_died”) func _on_enemy_died(): print(“Enemy died! GDScript received signal from Lua.”) # 增加分数等逻辑...这个例子展示了Lua脚本与Godot引擎、与其他GDScript脚本之间完美的互操作性。你可以用Lua快速实现游戏逻辑原型然后用GDScript或C#构建更复杂的系统它们可以无缝地协同工作。8. 总结与项目展望godot-lua-pluginscript项目为Godot 3生态带来了一个成熟、高效且易于集成的Lua脚本解决方案。它巧妙地利用了GDNative的便携性和PluginScript的无缝集成性通过LuaJIT FFI实现了高性能的绑定。对于热爱Lua、需要热更新、或希望复用现有Lua代码库的Godot开发者而言它是一个不可多得的利器。从我个人的使用经验来看在中小型项目或大型项目的特定子系统如UI逻辑、剧情对话、技能配置中使用Lua可以极大地提升开发效率和灵活性。Lua代码的修改无需重启整个Godot编辑器有时甚至无需重启游戏结合一些热重载技巧这非常适合快速迭代。当然它也有其边界比如缺乏官方的编辑器深度集成和调试支持。但在社区插件的辅助下这些障碍大多可以克服。项目的作者维护活跃文档也在逐步完善。如果你正在Godot 3.x上进行开发并且对Lua有兴趣我强烈建议你尝试一下这个插件它可能会为你打开一扇新的门。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…