泰拉瑞亚EasyBuildMod便捷建造模组开发详细过程

2023-11-01 01:40

本文主要是介绍泰拉瑞亚EasyBuildMod便捷建造模组开发详细过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

github地址:
GitHub - lxmghct/Terraria-EasyBuildMod
如果觉得有帮助,记得在github上点个star哦~
创意工坊搜索EasyBuildMod即可找到模组

目录

  • 简介
  • 模组物品制作
    • 物品拾取磁铁
    • 物块放置与摧毁助手基类
      • Item实现
      • 菜单实现
      • 物块选择框实现
    • 物块放置助手
    • 物块摧毁助手
  • 多人模式下的相关修改
  • 开发过程中的其他问题

1.简介

EasyBuildMod是一个便捷建造模组,它包含了三个物品:物块放置助手可以快速将物块或墙壁放置在一个矩形区域、物块摧毁助手可以快速摧毁矩形区域内的物块或墙壁、物品拾取磁铁则可用于快速拾取摧毁后掉落的物品。
制作这个模组主要是因为自己在游戏中想挖空或建造地形进行建造战斗场地时,直接手动挖空或放置非常耗时,而自己尝试过某些模组但都不太能满足自己需要,比如Fargo的“城市克星”,摧毁范围大但是墙壁无法破坏,还有“更好的体验”模组,放置和摧毁物块的效率并不算太高。暂时也没找到其他模组(如果有欢迎提出)。所以就自己动手写了一个。

2.模组物品制作

本模组包含三个物品,物品拾取磁铁、物块放置助手和物块摧毁助手。定义了一个全局的EasyBuildModPlayer类继承自ModPlayer,来控制使用某些物品或拥有某些效果时玩家的行为改变。

2.1物品拾取磁铁

ItemGrabMagnet,该物品借鉴了懒人模组中的战利品磁铁和ItemMagnetPlus模组。希望达到的效果是使用后玩家拥有“物品拾取”的Buff,可以扩大拾取范围,再次使用则可以关闭。
首先是ItemGrabMagnet的代码。这部分的代码比较简单,就是在玩家使用物品时判断是否已经拥有Buff,如果没有则添加Buff,如果有则移除Buff。
有几个细节的地方:由于想要的是使用磁铁后buff时间无限长,在Buff中设置剩余时间不可见,在给Buff时设置足够长的时间即可。
还有一个要注意的地方就是CombatText.NewText会默认对所有玩家触发,也就是玩家A在使用时,玩家B也能看到CombatText.NewText的讯息,所以CombatText.NewText的第一个参数不能用Main.LocalPlayer,否则其他人使用时也会显示在自己这里。

    public class ItemGrabBuff : ModBuff{public override void SetStaticDefaults(){Main.buffNoTimeDisplay[Type] = true;Main.debuff[Type] = false;}public override void Update(Player player, ref int buffIndex){player.GetModPlayer<EasyBuildModPlayer>().ItemGrabBuff = true;}}
    public class ItemGrabMagnet : ModItem{internal static string GetText(string str, params object[] args){return Language.GetTextValue($"Mods.EasyBuildMod.Content.Items.ItemGrabMagnet.{str}", args);}public override string Texture => "EasyBuildMod/Content/Items/ItemGrabMagnet";public bool IsMagnetOn;public override void SetStaticDefaults(){CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;}public override void SetDefaults(){Item.width = 30;Item.height = 30;Item.maxStack = 1;Item.value = Item.sellPrice(gold: 1);Item.rare = ItemRarityID.Blue;Item.useAnimation = 15;Item.useTime = 20;Item.useStyle = ItemUseStyleID.HoldUp;Item.consumable = false;IsMagnetOn = false;}public override void AddRecipes(){// 20个铁锭/铅锭CreateRecipe().AddRecipeGroup("IronBar", 20).AddTile(TileID.Anvils).Register();}public override bool? UseItem(Player player){IsMagnetOn = !player.HasBuff(ModContent.BuffType<Buffs.ItemGrabBuff>());if (IsMagnetOn){CombatText.NewText(player.Hitbox, Color.Green, GetText("OnTooltip"));player.AddBuff(ModContent.BuffType<Buffs.ItemGrabBuff>(), 2592000);SoundEngine.PlaySound(SoundID.MenuTick);}else{CombatText.NewText(player.Hitbox, Color.Red, GetText("OffTooltip"));player.ClearBuff(ModContent.BuffType<Buffs.ItemGrabBuff>());SoundEngine.PlaySound(SoundID.MenuClose);}return true;}public override void ModifyTooltips(List<TooltipLine> tooltips){string color = IsMagnetOn ? "00FF00" : "FF0000";string tooltop = IsMagnetOn ? GetText("OnTooltip") : GetText("OffTooltip");var line = new TooltipLine(Mod, GetText("StatusName"), $"[c/{color}:{tooltop}]");tooltips.Add(line);}}

然后是物品拾取范围扩大的实现。新定义EasyBuildModGlobalItem继承自GlobalItem,重写其中的GrabRange方法。注意格子数与游戏实际距离的换算是乘除16。

    public class EasyBuildModGlobalItem : GlobalItem{public override void GrabRange(Item item, Player player, ref int grabRange){if (player.GetModPlayer<EasyBuildModPlayer>().ItemGrabBuff){grabRange = ModContent.GetInstance<EasyBuildModConfig>().MagnetRange * 16;}}}

至此便基本实现了ItemGrabMagnet的功能。效果如下:
 

2.2物块放置与摧毁助手基类

ItemPlaceHelper与ItemDestroyHelper二者都有共同的特点,一个是可以通过右键调出菜单进行选择,一个是左键可以框选区域进行放置或破坏。自己最开始是先写了ItemPlaceHelper,而后写另一个的时候才意识到有大量重复的逻辑。为了避免过多重复代码,这里就二者的共同特点提取出一个抽象基类。
这里分成了三部分,物品自身、菜单和区域选择。

2.2.1Item实现

主要就是定义了物品的基本行为,如右键调出菜单,左键进行框选。调出菜单在重写CanUseItem中进行实现,选择区域则是在UseItem,这样处理更为方便。这种情况下,ItemPlaceHelperItemDestroyHelper只需重写StartAction方法即可。
这部分核心代码如下:

    public abstract class AreaSelectItem : ModItem{// 选择区域的起点和终点protected Point _beginPoint;protected Point _endPoint;// 是否开始选择区域protected bool _startSelecting;// 菜单UI的静态实例protected MenuUI _menuUI;public override bool AltFunctionUse(Player player) => true;protected virtual bool useItemCondition(Player player) => true;public override bool CanUseItem(Player player){UISystem.CurrentMenuUI = _menuUI;if (player.noBuilding){return false;}if (player.altFunctionUse == 2){if (_menuUI.Visible){SoundEngine.PlaySound(SoundID.MenuClose);_menuUI.Close();}else{SoundEngine.PlaySound(SoundID.MenuTick);_menuUI.Open(this);}return false;}if (!useItemCondition(player)){return false;}if (!_startSelecting){_beginPoint = Main.MouseWorld.ToTileCoordinates();_startSelecting = true;}return true;}public override bool? UseItem(Player player){_endPoint = Main.MouseWorld.ToTileCoordinates();if (!Main.mouseLeft){HandleMouseUp();return true;}if (Main.mouseRight && _startSelecting){StopUse();}else{DrawingSystem.StartDraw(GetRectangle(_beginPoint, _endPoint));}return base.UseItem(player);}public virtual void StopUse(){DrawingSystem.StopDraw();_startSelecting = false;}public void HandleMouseUp(){if (_startSelecting){StartAction(Main.LocalPlayer);SoundEngine.PlaySound(SoundID.Dig);StopUse();}}protected virtual void StartAction(Player player){}}
2.2.2菜单实现

由于任意一个ItemPlaceHelper所调出的菜单都相同,所以就没必要给每一个ItemPlaceHelper配一个菜单,所有ItemPlaceHelper共用一个菜单即可。菜单继承自Terraria.UI.UIState,菜单的正确显示也花了不少时间,经过查看源码以及参考了"更好的体验"模组最后终于将UI显示出来。
显示菜单的基本层次结构是ModSystem -> UserInterface -> UIState -> UIElement。具体就是UI中由若干像按钮之类的UIElement构成,UI的显示需要通过用户接口去更新UI状态,UIStateUserInterface的静态变量都存储在一个ModSystem中,让其可以在模组加载时就被加载好,并通过重写ModSystem的UpdateUIModifyInterfaceLayers去实现UI的更新与绘制。
UISystem的核心代码如下:

    public class UISystem : ModSystem{public static ItemPlaceHelperUI ItemPlaceHelperUI { get; set; }private static UserInterface _itemPlaceHelperInterface;public static ItemDestroyHelperUI ItemDestroyHelperUI { get; set; }private static UserInterface _itemDestroyHelperInterface;public override void Load(){ItemPlaceHelperUI = new ItemPlaceHelperUI();_itemPlaceHelperInterface = new UserInterface();_itemPlaceHelperInterface.SetState(ItemPlaceHelperUI);ItemDestroyHelperUI = new ItemDestroyHelperUI();_itemDestroyHelperInterface = new UserInterface();_itemDestroyHelperInterface.SetState(ItemDestroyHelperUI);}public override void Unload(){ItemPlaceHelperUI = null;_itemPlaceHelperInterface = null;ItemDestroyHelperUI = null;_itemDestroyHelperInterface = null;}public override void UpdateUI(GameTime gameTime){if (ItemPlaceHelperUI.Visible){_itemPlaceHelperInterface.Update(gameTime);}if (ItemDestroyHelperUI.Visible){_itemDestroyHelperInterface.Update(gameTime);}}public override void ModifyInterfaceLayers(List<GameInterfaceLayer> layers){int mouseTextIndex = layers.FindIndex(layer => layer.Name.Equals("Vanilla: Mouse Text")); // 表示在鼠标文本之上if (mouseTextIndex != -1){layers.Insert(mouseTextIndex, new LegacyGameInterfaceLayer("EasyBuildMod: MyMenuUI",delegate{if (ItemPlaceHelperUI.Visible){_itemPlaceHelperInterface.Draw(Main.spriteBatch, new GameTime());}if (ItemDestroyHelperUI.Visible){_itemDestroyHelperInterface.Draw(Main.spriteBatch, new GameTime());}return true;},InterfaceScaleType.UI));}}}

可以看到存在这样的调用顺序ModSystem.UpdateUI -> UseInterface.Update用于实时更新, ModSystem.ModifyInterfaceLayers -> UseInterface.Draw用于绘制。而这里给UI添加了个变量Visible用于控制何时显示。只有当Visible为true时上述两个方法才对其进行更新。

接下来是UI,UI中的代码比较简单,由于所有物品共用一个UI,所以这里需要存储调出UI的物品是哪一个(AreaSelectItem)。在其派生类中只需定义包含的元素以及相应的点击事件等即可。
这里有一个需要注意的点就是UI的位置需要考虑用户的UI缩放。


这部分核心代码如下:

    public abstract class MenuUI : UIState{internal AreaSelectItem AreaSelectItem;protected UIElement MainContainer;public bool Visible;public override void OnInitialize(){base.OnInitialize();Append(MainContainer = new ());MainContainer.Width.Set(200, 0);MainContainer.Height.Set(200, 0);}public virtual void Open(AreaSelectItem item){this.AreaSelectItem = item;Visible = true;// 注意要除以UIScale,否则如果缩放比例不是100%就会错位MainContainer.Left.Set(Main.mouseX / Main.UIScale - MainContainer.Width.Pixels / 2, 0);MainContainer.Top.Set(Main.mouseY / Main.UIScale - MainContainer.Height.Pixels / 2, 0);}}

当玩家手中物品切换时,也需要关闭UI,这里需要在ModPlayer中重写PostUpdate方法,当玩家手中物品不是AreaSelectItem时关闭UI。

    public override void PostUpdate(){if (UISystem.CurrentMenuUI is null || UISystem.CurrentMenuUI.AreaSelectItem is null){return;}AreaSelectItem currentItem = UISystem.CurrentMenuUI.AreaSelectItem;Player player = Main.player[Main.myPlayer];Item item = player.inventory[player.selectedItem];if (item.type != currentItem.Type){if (!Main.playerInventory){UISystem.Hide();}}else{DrawingSystem.Init();if (!Main.mouseLeft){UISystem.CurrentMenuUI.AreaSelectItem.}}}
2.2.3物块选择框实现

这里也一样需要通过在ModSystemModifyInterfaceLayers调用对应UserInterfaceDraw进行绘制。新定义一个DrawingSystem继承自ModSystem,这部分代码就不多赘述了。
物品框选时希望显示的有(1)在鼠标末尾画物块预览 (2)矩形区域预览 (3) 矩形大小显示,其中(2)和(3)只有在使用物品时才进行绘制。这部分核心代码如下:

    public class SelectedAreaDrawing{public bool IsDrawing;/// <summary>/// 绘制物块预览/// </summary>private void drawItemPreview(){Vector2 position = Main.MouseScreen + new Vector2(32, 32);Texture2D texture = TextureAssets.Item[itemId].Value;Main.spriteBatch.Draw(texture, position, null, Color.White, 0f, texture.Size() / 2, 1f, SpriteEffects.None, 0f);}/// <summary>/// 绘制矩形区域预览/// </summary>private void drawRectanglePreview(){Vector2 leftTop = _rectangle.TopLeft() * 16 - Main.screenPosition;Vector2 size = _rectangle.Size() * 16;Color color = Color.White * 0.7f;_areaTexture.SetData(new Color[] { color });Main.spriteBatch.Draw(_areaTexture, leftTop, null, color, 0f, Vector2.Zero, size, SpriteEffects.None, 0f);}/// <summary>/// 标明矩形大小/// </summary>private void drawRectangleSize(){string sizeText = $"{_rectangle.Width} x {_rectangle.Height}";Vector2 size = FontAssets.MouseText.Value.MeasureString(sizeText);Vector2 position = Main.MouseScreen + new Vector2(16, -size.Y - 6);ChatManager.DrawColorCodedStringWithShadow(Main.spriteBatch, FontAssets.MouseText.Value, sizeText, position, Color.White, 0f, Vector2.Zero, Vector2.One);}public void Draw(){drawItemPreview();if (IsDrawing){drawRectanglePreview();drawRectangleSize();}}}

2.3物块放置助手

ItemPlaceHelper,想要实现的效果是右键打开物品选择菜单,选择物品后,左键可以选择矩形区域放置。
选择菜单中只有一个用于放置选择物块的按钮,通过获取Main.mouseItem物品,根据其createTile和createWall判断是否为物块或墙壁,这部分代码如下:

    itemSelectButton.OnClick += (evt, element) =>{if (Main.mouseItem.type != 0){// 如果物块可以放置,则添加进来if ((Main.mouseItem.createTile != -1 && Main.tileSolid[Main.mouseItem.createTile]) || Main.mouseItem.createWall != -1){AreaSelectItem.ContentItemType = Main.mouseItem.type;itemSelectButton.SetContent(TextureAssets.Item[Main.mouseItem.type]);}}else{itemSelectButton.SetContent(null);AreaSelectItem.ContentItemType = 0;}};

其中itemSelectButton是自己定义的一个圆形按钮。

该物品的关键在于放置物品,即重写基类AreaSelectItemStartAction方法。

    protected override void StartAction(Player player){var rect = GetRectangle(_beginPoint, _endPoint);int consumeCount = 0;int total = GetItemCountOfInventory(player.inventory, ContentItemType);Item item = new Item();item.SetDefaults(ContentItemType);bool isWall = item.createWall > 0;bool hasHammer = getMaxHammerPower(player) > 0;// 从下到上,从左到右// 这种顺序可以保证某些具有自由落体性质的方块(如沙块)能够被正确的放置// 不过也会导致替换方块时, 像沙块这样的方块无法被从下往上替换for (int y = rect.Y + rect.Height - 1; y >= rect.Y; y--){for (int x = rect.X; x < rect.X + rect.Width; x++){if (consumeCount >= total){break;}Tile tile = Main.tile[x, y];if (isWall){if (tile.WallType > 0){if (!player.TileReplacementEnabled){continue;}if (hasHammer){WorldGen.KillWall(x, y, false);WorldGen.PlaceWall(x, y, (ushort)item.createWall, true);consumeCount++;}}else{WorldGen.PlaceWall(x, y, (ushort)item.createWall, true);consumeCount++;}}else{if (tile.HasTile){if (!player.TileReplacementEnabled || !player.HasEnoughPickPowerToHurtTile(x, y)){continue;}// 判断是否是同一种方块,是则跳过WorldGen.KillTile_GetItemDrops(x, y, tile, out int tileType, out _, out _, out _);if (tileType == item.type){continue;}if (WorldGen.ReplaceTile(x, y, (ushort)item.createTile, item.placeStyle)){consumeCount++;}}else{if (WorldGen.PlaceTile(x, y, (ushort)item.createTile, true, true, player.whoAmI, item.placeStyle)){consumeCount++;}}}}}if (consumeCount > 0){for (int i = 0; i < player.inventory.Length; i++){if (player.inventory[i].type == ContentItemType){if (player.inventory[i].stack > consumeCount){player.inventory[i].stack -= consumeCount;break;}else{consumeCount -= player.inventory[i].stack;player.inventory[i].SetDefaults();}}}}}

以上有几个需要注意的问题,

  1. 如果使用player.PickTile进行破坏物块,则第三个参数镐力值需要尽可能的填大一些,如果镐力刚好大于物块所需的最大镐力,则完全有可能不能直接摧毁物块而仅仅是对其造成一定程度损坏
  2. 替换物块可以用WorldGen.ReplaceTile但替换墙壁则没找到对应的ReplaceWall,需要先使用KillWall再进行放置。
  3. 获取位于x,y处的物块或墙壁的类型的问题放在了文章末尾 点这里跳转

2.4物块摧毁助手

ItemDestroyHelper,设计思路与ItemPlaceHelper几乎完全相同,只是将StartAction中的放置改为了摧毁,实际上摧毁的逻辑在替换物块时已经实现,这里就不多赘述。

3.多人模式下的相关修改

这部分主要集中在物块墙壁放置和摧毁时与游戏内其他玩家的同步问题上,于是我就在摧毁和放置的末尾加上:

    if (Main.netMode == NetmodeID.MultiplayerClient){NetMessage.SendData(MessageID.TileSquare, Main.myPlayer, -1, null, rect.X, rect.Y, rect.Width, rect.Height);}

这样一次性同步范围内的所有方块。但这时也遇到了个问题,虽然方块同步了,但却没有掉落物。摧毁物块和墙壁调用的是WorldGen.KillTileWorldGen.KillWall,仔细查看源码才发现当游戏处于多人模式时,这两个方法禁用了物块的正常掉落。


这时我注意到另一个函数player.PickTile(x, y, 10000)在进行破坏物块时可以在多人模式下掉落,于是我进入Player的PickTile方法中查看了一下,如下图所示:

仿照这个方法,我重新写了一下破坏物块和墙壁的代码,注意墙壁和物块的SendData第五个参数不同:

    public static class WallUtils{public static void KillWall(int x, int y, bool fail = false){WorldGen.KillWall(x, y, fail);if (!fail && Main.netMode == NetmodeID.MultiplayerClient){// Wall对应的SendData第5个参数值为2NetMessage.SendData(MessageID.TileManipulation, -1, -1, null, 2, (float)x, (float)y, 0f, 0, 0, 0);}}}public static class TileUtils{public static void KillTile(int x, int y, bool fail = false, bool effectOnly = false, bool noItem = false){WorldGen.KillTile(x, y, fail, effectOnly, noItem);if (!fail && Main.netMode == NetmodeID.MultiplayerClient){// Tile对应的SendData第5个参数值为0NetMessage.SendData(MessageID.TileManipulation, -1, -1, null, 0, (float)x, (float)y, 0f, 0, 0, 0);}}}

4.开发过程中的其他问题

1.使用语言文件时遇到的问题

将模组中需要用到的文字信息的不同语言版本放在XXX.hjson如en-US.hjson中,再通过Language.GetTextValue("Mods.XXX.XXX")来获取对应语言的文字。但在我使用时遇到一个小问题,在设置物品的DisplayName和Tooltip的名称时,以下代码并不能正常获取到对应语言的文字信息:

    DisplayName.SetDefault(Language.GetTextValue("Mods.XXX.XXX"));Tooltip.SetDefault(Language.GetTextValue("Mods.XXX.XXX"));

在游戏运行时有时能正常显示,有时则直接显示了“Mods.XXXXXX”这个字符串。推测是语言文件与物品静态信息加载顺序关。后面参考了官方的ExampleMod,解决方法是在语言文件hjson中直接写明物品或Buff的DisplayName和Tooltip,会自动读取到游戏中。

    Mods.XXXMod.ItemName: {物品类名: 物品名称}Mods.XXXMod.ItemTooltip: {物品类名: 物品Tooltip}Mods.XXXMod.BuffName: {Buff类名: Buff名称}Mods.XXXMod.BuffDescription: {Buff类名: Buff描述}

2.获取物块或墙壁对应的类型

判断位于x,y处的物块对应的item的类型,也就是itemId。这个方法我找了很久,最后也是成功从掉落物块的相关源码中找到了直接想要的内容:Terraria.WorldGen.KillTile_DropItems是用于破坏物块后进行掉落用的,不过它是私有方法,而它调用的KillTile_GetItemDrops刚好是public方法,所以在判断物块时就使用了这种方法。但是奇怪的是KillWall_GetItemDrops却是私有方法,所以这里直接将源码中的代码复制过来,如下图所示:


由于是反编译得到的源码,所以有大量的switch-caseif分支。唯一要注意的是图中*tileCache.wallTileinternal属性:

图中可以看到实际上wall对应的实际就是公有属性WallType,故将源码中的*tileCache.wall全改为tileCache.WallType即可。

3.按钮的点击问题

当鼠标上已经有物块时,点击按钮如果鼠标上的物块可以被正确放在按钮所在的原位置,则系统会优先将物块放置再触发按钮的点击事件。这个由于不是非常影响体验,将鼠标离玩家远一点即可,暂时没去研究解决方法。

这篇关于泰拉瑞亚EasyBuildMod便捷建造模组开发详细过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/319596

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。