UE4 Unlua的快速使用

news2024/10/6 2:23:30

目录

  • Unlua的使用
    • 前言
    • 下载Unlua插件
    • 插件安装
    • 快速入门
    • 语法汇总
      • 模块导入
      • 多行字符串
      • 官方静态方法调用
      • 蓝图方法调用
      • 重载蓝图中的方法
      • 主动调用被重载的蓝图方法
      • 输入绑定
      • 动态绑定Lua脚本
      • 委托
      • 容器使用
    • 延迟与协程的使用
      • C++ 调用Lua
    • 静态导出自定义类型到Lua使用
      • 网络
      • UMG资源释放
      • 自定义加载器
      • 动画通知

Unlua的使用

前言

整理一下Unlua的整个学习流程

下载Unlua插件

我们此处使用的是腾讯的Unlua插件,打开官方的Github链接,下载对应的版本
官方链接GitHub
Wiki文档

插件安装

把下载好的插件放在自己新建项目的Plugins文件夹下,编译启动

快速入门

萌新看的图文教学
老手看的文档

点击Create的时候,会根据填写的模块名字生成路径
在这里插入图片描述
在这里插入图片描述

语法汇总

模块导入

与路径对应即可

local Common = require "Core.Common"

在这里插入图片描述

多行字符串

在这里插入图片描述

官方静态方法调用

UE.类名.静态方法名字

nil代表无效值空值未定义的值
在这里插入图片描述

蓝图方法调用

self:XXXFunction() 

在这里插入图片描述
在这里插入图片描述
输出结果:这是我的蓝图测试

重载蓝图中的方法

function M:XXXFunction())
end

在这里插入图片描述

输出结果:M:TestFunction

主动调用被重载的蓝图方法

self.Overridden.XXXFunction()

在这里插入图片描述

输出结果:
这是我的蓝图测试
M:TestFunction

输入绑定

function M:LeftMouseButton_Pressed()
end

实例:绑定按键并打印它的名字

local M = UnLua.Class()

local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

function M:ReceiveBeginPlay()
    local msg =
        [[
    来试试以下输入吧:
    字母、数字、小键盘、方向键、鼠标
    ]]
    Print(msg)
end

local function SetupKeyBindings()
    local key_names = 
    {
        -- 字母
        "A", "B", --[["C",]] "D", "E","F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", --[["V", ]] "W", "X", "Y", "Z",
        -- 数字
        "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
        -- 小键盘
        "NumPadOne", "NumPadTwo", "NumPadThree", "NumPadFour", "NumPadFive", "NumPadSix", "NumPadSeven", "NumPadEight", "NumPadNine",
        -- 方向键
        "Up", "Down", "Left", "Right",
        -- ProjectSettings -> Engine - Input -> Action Mappings
        "Fire", "Aim",
    }
    
    for _, key_name in ipairs(key_names) do
        M[key_name .. "_Pressed"] = function(self, key)
            Print(string.format("按下了%s", key.KeyName))
        end
    end
end

local function SetupAxisBindings()
    local axis_names = {
        "MoveForward", "MoveRight", "Turn", "LookUp", "LookUpRate", "TurnRate"
    }
    for _, axis_name in ipairs(axis_names) do
        M[axis_name] = function(self, value)
            if value ~= 0 then
                Print(string.format("%s(%f)", axis_name, value))
            end
        end
    end
end

SetupKeyBindings() -- 在require的时候会执行
SetupAxisBindings()

local BindKey = UnLua.Input.BindKey

BindKey(M, "C", "Pressed", function(self, Key)
    Print("按下了C")
end)

BindKey(M, "C", "Pressed", function(self, Key)
    Print("复制")
end, { Ctrl = true })

BindKey(M, "V", "Pressed", function(self, Key)
    Print("按下了V")
end)

BindKey(M, "V", "Pressed", function(self, Key)
    Print("粘贴")
end, { Ctrl = true })

return M

动态绑定Lua脚本

Actor:

    local World = self:GetWorld()
    local SpawnClass = self.SpawnClass
    local Transform = self.SpawnPointActor:GetTransform()
    local AlwaysSpawn = UE.ESpawnActorCollisionHandlingMethod.AlwaysSpawn
    World:SpawnActor(SpawnClass, Transform, AlwaysSpawn, self, self, "XXX.XXX")

Object:

local WidgetClass = self.WidgetClass
local img = NewObject(WidgetClass, self, nil, "XXX.XXX")
img:AddToViewport()
img:RandomPosition()

委托

local FLinearColor = UE.FLinearColor

local M = UnLua.Class()

function M:Construct()
	-- Bind
    self.ClickMeButton.OnClicked:Add(self, self.OnButtonClicked)
    self.ClickMeCheckBox.OnCheckStateChanged:Add(self, self.OnCheckBoxToggled)
    -- SetTimerByEvent
    self.TimerHandle = UE.UKismetSystemLibrary.K2_SetTimerDelegate({ self, self.OnTimer }, 1, true)
end

function M:OnButtonClicked()
    local r = math.random()
    local g = math.random()
    local b = math.random()

    self.ClickMeButton:SetBackgroundColor(FLinearColor(r, g, b, 1))
end

function M:OnCheckBoxToggled(on)
    if on then
        self.CheckBoxText:SetText("已选中")
    else
        self.CheckBoxText:SetText("未选中")
    end
end

function M:OnTimer())
end

function M:Destruct()
    -- Unbind
    self.ClickMeButton.OnClicked:Remove(self, self.OnButtonClicked)
    self.ClickMeCheckBox.OnCheckStateChanged:Remove(self, self.OnCheckBoxToggled)
    -- ClearTimer
    UE.UKismetSystemLibrary.K2_ClearAndInvalidateTimerHandle(self, self.TimerHandle)
end

return M

容器使用

创建原生容器时通常需要指定参数类型,来确定容器内存放的数据类型

参数类型示例实际类型
booleantrueBoolean
number0Interge
string“”String
tableFVectorVector
userdataFVector(1,1,1)Vector

例:

local array = TArray({ElementType})
local set = TSet({ElementType})
local map = TMap({KeyType}, {ValueType})
local array = UE.TArray(0)
local set = UE.TSet(0)
local map = UE.TMap(0, true)

延迟与协程的使用

local M = UnLua.Class()

local Latent = UE.UKismetSystemLibrary.XXXLatentFunction 

-- 定义一个协程函数
function M:StartCoroutine()
    local co = coroutine.create(function()
        print("开始等待...")
        Latent.Wait(2.0) 
        print("等待结束")
    end)
    coroutine.resume(co)
end

function M:ReceiveBeginPlay()
    self:StartCoroutine()
end

return M
local M = UnLua.Class()

local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

local function run(self, name)
   Print(string.format("协程%s:启动", name))
    for i = 1, 5 do
        UE.UKismetSystemLibrary.Delay(self, 1)
       Print(string.format("协程%s:%d", name, i))
    end
   Print(string.format("协程%s:结束", name))
end

function M:ReceiveBeginPlay()
    local msg = [[
    —— ReceiveBeginPlay"
    ]]
    Print(msg)

    coroutine.resume(coroutine.create(run), self, "A")
    coroutine.resume(coroutine.create(run), self, "B")
end

return M

C++ 调用Lua

C++部分

void UTutorialBlueprintFunctionLibrary::CallLuaByFLuaTable()
{
    PrintScreen(TEXT("[C++]CallLuaByFLuaTable 开始"));
    UnLua::FLuaEnv Env;

    const auto Require = UnLua::FLuaFunction(&Env, "_G", "require");
    const auto RetValues1 = Require.Call("Tutorials.08_CppCallLua");
    check(RetValues1.Num() == 2);

    const auto RetValue = RetValues1[0];
    const auto LuaTable = UnLua::FLuaTable(&Env, RetValue);
    const auto RetValues2 = LuaTable.Call("CallMe", 3.3f, 4.4f);
    check(RetValues2.Num() == 1);

    const auto Msg = FString::Printf(TEXT("[C++]收到来自Lua的返回,结果=%f"), RetValues2[0].Value<float>());
    PrintScreen(Msg);
    PrintScreen(TEXT("[C++]CallLuaByFLuaTable 结束"));
}

void UTutorialBlueprintFunctionLibrary::CallLuaByGlobalTable()
{
    PrintScreen(TEXT("[C++]CallLuaByGlobalTable 开始"));

    UnLua::FLuaEnv Env;
    const auto bSuccess = Env.DoString("G_08_CppCallLua = require 'Tutorials.08_CppCallLua'");
    check(bSuccess);

    const auto RetValues = UnLua::CallTableFunc(Env.GetMainState(), "G_08_CppCallLua", "CallMe", 1.1f, 2.2f);
    check(RetValues.Num() == 1);

    const auto Msg = FString::Printf(TEXT("[C++]收到来自Lua的返回,结果=%f"), RetValues[0].Value<float>());
    PrintScreen(Msg);
    PrintScreen(TEXT("[C++]CallLuaByGlobalTable 结束"));
}

static void PrintScreen(const FString& Msg)
{
    UKismetSystemLibrary::PrintString(nullptr, Msg, true, false, FLinearColor(0, 0.66, 1), 100);
}

lua 部分

local M = UnLua.Class()

local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

function M:ReceiveBeginPlay()
    local msg =
        [[
    —— ReceiveBeginPlay
    ]]
    Print(msg)
    UE.UTutorialBlueprintFunctionLibrary.CallLuaByGlobalTable()
    Print("=================")
    UE.UTutorialBlueprintFunctionLibrary.CallLuaByFLuaTable()
end

function M.CallMe(a, b)
    local ret = a + b
    local msg = string.format("[Lua]收到来自C++的调用,a=%f b=%f,返回%f", a, b, ret)
    Print(msg)
    return ret
end

return M

静态导出自定义类型到Lua使用

C++.h

#pragma once

#include "CoreMinimal.h"

struct FTutorialObject
{
protected:
	FString Name;

public:
	FTutorialObject();

	explicit FTutorialObject(const FString& Name)
		:Name(Name)
	{
	}

	FString GetTitle() const
	{
		return FString::Printf(TEXT("《%s》"), *Name);
	}

	FString ToString() const
	{
		return GetTitle();
	}
};

c++ cpp

#include "TutorialObject.h"

#include "LuaCore.h"
#include "UnLua.h"
#include "UnLuaEx.h"

FTutorialObject::FTutorialObject()
{
}

static int32 FTutorialObject_New(lua_State* L)
{
	const auto NumParams = lua_gettop(L);
    if (NumParams != 2)
    {
        UNLUA_LOGERROR(L, LogUnLua, Log, TEXT("%s: Invalid parameters!"), ANSI_TO_TCHAR(__FUNCTION__));
        return 0;
    }

    const char* NameChars = lua_tostring(L, 2);
    if (!NameChars)
    {
        UE_LOG(LogUnLua, Log, TEXT("%s: Invalid tutorial name!"), ANSI_TO_TCHAR(__FUNCTION__));
        return 0;
    }

    const auto UserData = NewUserdataWithPadding(L, sizeof(FTutorialObject), "FTutorialObject");
	new(UserData) FTutorialObject(UTF8_TO_TCHAR(NameChars));
    return 1;
}

static const luaL_Reg FTutorialObjectLib[] =
{
    { "__call", FTutorialObject_New },
    { nullptr, nullptr }
};

BEGIN_EXPORT_CLASS(FTutorialObject)
ADD_FUNCTION(GetTitle)
ADD_LIB(FTutorialObjectLib)
END_EXPORT_CLASS()
IMPLEMENT_EXPORTED_CLASS(FTutorialObject)

lua部分

local M = UnLua.Class()
local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

function M:ReceiveBeginPlay()
    local msg =
        [[
    -- ReceiveBeginPlay
    ]]
    Print(msg)
    
    local tutorial = UE.FTutorialObject("教程")
    msg = string.format("tutorial -> %s\n\ntutorial:GetTitle() -> %s", tostring(tutorial), tutorial:GetTitle())
   Print(msg)
end

网络

使用 {函数名}RPC 可以覆盖蓝图中RPC函数的实现
使用 OnRep
{变量名} 可以覆盖蓝图中变量同步消息的处理

蓝图里面添加多人联机复制广播之类的
在这里插入图片描述
lua里写真正调用的方法
在这里插入图片描述

UMG资源释放

这部分直接附着官方内容
UMG:

---@type ReleaseUMG_Root_C
local M = UnLua.Class()

function M:Construct()
    print("Root Construct")
    self.Button_AddNew.OnClicked:Add(self, self.OnAddNew)
    self.Button_ReleaseAll.OnClicked:Add(self, self.OnReleaseAll)
end

function M:OnAddNew()
    print("Root Add New")
    local widget_class = UE.UClass.Load("/Game/Tutorials/11_ReleaseUMG/ReleaseUMG_ItemParent.ReleaseUMG_ItemParent_C")
    local widget = NewObject(widget_class, self)
    self.VerticalBox_Panel:AddChildToVerticalBox(widget)
end

function M:OnReleaseAll()
    self:RemoveFromViewport()
end

function M:Destruct()
    print("Root Destruct")
    self:Release()
end

return M

测试部分:

--[[
    说明:

    UMG对象的释放流程:
    1、调用self:Release(),解除LuaTable在C++侧的引用
    2、确保LuaTable在Lua侧没有其他引用,触发LuaGC
    3、C++侧收到UObject_Delete回调,解除UMG在C++侧的引用
    4、确保UMG在C++侧没有其他引用,触发UEGC

    小提示:

    使用控制台命令查看对象和类的引用情况:
    
    查看指定类的引用列表:Obj List Class=ReleaseUMG_Root_C
    查看指定对象的引用链:Obj Refs Name=ReleaseUMG_Root_C_0
]] --

local Screen = require "Tutorials.Screen"

local M = UnLua.Class()

local function print_intro()
    local msg =
        [[
使用以下按键进行一次强制垃圾回收:

C:强制 C++ GC
L:强制 Lua GC

—— 本示例来自 "Content/Script/Tutorials.11_ReleaseUMG.lua"
]]
    Screen.Print(msg)
end

function M:ReceiveBeginPlay()
    local widget_class = UE.UClass.Load("/Game/Tutorials/11_ReleaseUMG/ReleaseUMG_Root.ReleaseUMG_Root_C")
    local widget_root = NewObject(widget_class, self)
    widget_root:AddToViewport()

    print_intro()
end

function M:L_Pressed()
    collectgarbage("collect")
    Screen.Print('collectgarbage("collect")')
end

function M:C_Pressed()
    UE.UKismetSystemLibrary.CollectGarbage()
    Screen.Print("UKismetSystemLibrary.CollectGarbage()")
end

return M

自定义加载器

说明:通过绑定 FUnLuaDelegates::CustomLoadLuaFile 可以实现自定义Lua加载器
方式1:查找路径固定,性能更好
方式2:通过package.path查找,更加灵活

lua部分:

UE.UTutorialBlueprintFunctionLibrary.SetupCustomLoader(1)
Screen.Print(string.format("FromCustomLoader1:%s", require("Tutorials")))

package.loaded["Tutorials"] = nil

package.path = package.path .. ";./?/Index.lua"
UE.UTutorialBlueprintFunctionLibrary.SetupCustomLoader(2)
Screen.Print(string.format("FromCustomLoader2:%s", require("Tutorials")))

UE.UTutorialBlueprintFunctionLibrary.SetupCustomLoader(0)

C++部分

bool CustomLoader1(UnLua::FLuaEnv& Env, const FString& RelativePath, TArray<uint8>& Data, FString& FullPath)
{
    const auto SlashedRelativePath = RelativePath.Replace(TEXT("."), TEXT("/"));
    FullPath = FString::Printf(TEXT("%s%s.lua"), *GLuaSrcFullPath, *SlashedRelativePath);

    if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
        return true;

    FullPath.ReplaceInline(TEXT(".lua"), TEXT("/Index.lua"));
    if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
        return true;

    return false;
}
bool CustomLoader2(UnLua::FLuaEnv& Env, const FString& RelativePath, TArray<uint8>& Data, FString& FullPath)
{
    const auto SlashedRelativePath = RelativePath.Replace(TEXT("."), TEXT("/"));
    const auto L = Env.GetMainState();
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path");
    const char* Path = lua_tostring(L, -1);
    lua_pop(L, 2);
    if (!Path)
        return false;

    TArray<FString> Parts;
    FString(Path).ParseIntoArray(Parts, TEXT(";"), false);
    for (auto& Part : Parts)
    {
        Part.ReplaceInline(TEXT("?"), *SlashedRelativePath);
        FPaths::CollapseRelativeDirectories(Part);
        
        if (FPaths::IsRelative(Part))
            FullPath = FPaths::ConvertRelativePathToFull(GLuaSrcFullPath, Part);
        else
            FullPath = Part;

        if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
            return true;
    }

    return false;
}

动画通知

local M = UnLua.Class()

function M:Received_Notify(MeshComp, Animation)
    return true
end

return M

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

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

相关文章

秋招季的策略与行动指南:提前布局,高效备战,精准出击

6月即将进入尾声&#xff0c;一年一度的秋季招聘季正在热火进行中。对于即将毕业的学生和寻求职业发展的职场人士来说&#xff0c;秋招是一个不容错过的黄金时期。 秋招的序幕通常在6月至9月间拉开&#xff0c;名企们纷纷开启网申的大门。在此期间&#xff0c;求职备战是一个系…

SaaS客户裂变:如何构建合作伙伴的双向沟通桥梁

在SaaS行业中&#xff0c;客户裂变不仅是增长的关键&#xff0c;更要求与合作伙伴之间建立稳固的沟通桥梁。如何构建合作伙伴双向沟通的桥梁&#xff0c;真正做到理解对方的价值需求&#xff0c;实现长期合作共赢呢&#xff1f; 一、明确价值共享 首先&#xff0c;确保双方明…

git 初基本使用-----------笔记(结合idea)

Git命令 下载git 打开Git官网&#xff08;git-scm.com&#xff09;&#xff0c;根据自己电脑的操作系统选择相应的Git版本&#xff0c;点击“Download”。 基本的git命令使用 可以在项目文件下右击“Git Bash Here” &#xff0c;也可以命令终端下cd到指定目录执行初始化命令…

Windows环境本地部署开源在线演示文稿应用PPTist并实现远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Shopee本土店选品有什么技巧?EasyBoss ERP为你整理了6个高效选品的方法!

电商圈有句话叫&#xff1a;七分靠选品&#xff0c;三分靠运营&#xff0c;选品对了&#xff0c;事半功倍&#xff0c;选品错了&#xff0c;功亏一篑&#xff01; 很多卖家都会为选品发愁&#xff0c;特别对于Shopee本土店卖家来说&#xff0c;要囤货到海外仓&#xff0c;如果…

六西格玛黑带培训:技能进阶与薪资增长的助推器

在快速变化的职场环境中&#xff0c;不断寻求自我提升与突破成为了每一位职场人士的重要课题。六西格玛黑带培训作为质量管理领域的精英认证&#xff0c;它不仅代表着个人技能的提升&#xff0c;更意味着职业发展道路上的新机遇和薪资水平的飞跃。 六西格玛黑带培训&#xff…

KubeSphere容器平台本地部署并实现无公网IP远程监控集群

文章目录 前言1. 部署KubeSphere2. 本地测试访问3. Linux 安装Cpolar4. 配置KubeSphere公网访问地址5. 公网远程访问KubeSphere6. 固定KubeSphere公网地址 前言 本文主要介绍如何在Linux CentOS搭建KubeSphere并结合Cpolar内网穿透工具&#xff0c;实现远程访问&#xff0c;根…

Spring框架FactoryBean接口的作用和应用

一、FactoryBean源码解读 FactoryBean<T> 是 Spring 框架 beans.factory包中的一个接口&#xff0c;从字面意思可以理解为工厂bean&#xff0c;它是干什么的&#xff0c;类名上的泛型又是指什么&#xff0c;有什么作用&#xff1f; 注释看不懂没关系&#xff0c;先看一…

敏源-数字高精度温度探头可替代传统PT100/1000

传统模拟温度探头成本高、功耗高、数据采集不方便&#xff0c;而由工采网代理的敏源0.1℃数字温度探头&#xff0c;可替代传统的PT100/1000或升级热敏电阻探头&#xff1b;可应用于冷链、仓储、医疗、工业等低温/室温/高温高精度温度采集场景。 PT100温度传感器需要复杂的采集电…

BMS绝缘检测方案

目前已有绝缘检测方案大都类似&#xff0c;我想分享一下&#xff0c;同时也想提出一个问题&#xff1a;在总压1500V的时候&#xff0c;检测100K以下的阻值有什么很好的方案吗&#xff1f;希望有懂行的人能给予帮助&#xff0c;万分感谢&#xff01;&#xff01;&#xff01; 我…

电路与数字逻辑期末复习重点整理!!

1.带无关项的卡诺图 2.置数法设计N进制电路 计数器&#xff1a;具有记忆输入脉冲个数功能的电路称为计数器。 按照各个触发器状态更新情况的不同可分为&#xff1a; 同步计数器&#xff1a;各触发器受同一时钟脉冲─输入计数脉冲控制&#xff0c;同步更新状态。异步计数器&a…

AI大模型安全挑战和安全要求解读

引言 随着人工智能技术的飞速发展&#xff0c;大模型技术以其卓越的性能和广泛的应用前景&#xff0c;正在重塑人工智能领域的新格局。然而&#xff0c;任何技术都有两面性&#xff0c;大模型在带来前所未有便利的同时&#xff0c;也引发了深刻的安全和伦理挑战。 大模型&…

PointMamba: A Simple State Space Model for Point Cloud Analysis

1. 论文基本信息 2. 创新点 介绍了第一个状态空间模型 PointMamba&#xff0c;将其应用与点云分析。PointMamba 表现出令人印象深刻的能力&#xff0c;包括结构简单性&#xff08;例如&#xff0c;vanilla Mamba&#xff09;、低计算成本和知识可迁移性&#xff08;例如&#…

通过验证邮箱进行注册信息确认

应用在进行注册时&#xff0c;避免恶意攻击和垃圾注册&#xff0c;可以通过验证注册者身份后才能够提交。一般可以使用验证手机短信或者验证邮箱&#xff0c;验证短信会有专门的第三方服务&#xff0c;可以进行付费购买。验证邮箱的正确与否&#xff0c;可以通过以下2种方式进行…

关于组织赴俄罗斯(莫斯科)第 28 届国际汽车零部件、汽车维修设备和商品展览会商务考察的通知

关于组织赴俄罗斯&#xff08;莫斯科&#xff09; 第 28 届国际汽车零部件、汽车维修设备和商品展览会商务考察的通知 展会名称&#xff1a;俄罗斯&#xff08;莫斯科&#xff09;第 28 届国际汽车零部件、汽车零部件、汽车维修设备和商品展览会 时间&#xff1a;2024 年 8 月…

【异常总结】SeaTunnel集群脑裂配置优化方法

集群配置 项目描述数量3台规格阿里云ECS 16C64GSlot模式静态50个ST内存配置-Xms32g -Xmx32g -XX:MaxMetaspaceSize8g 异常问题 4月份以来&#xff0c;出现了3次集群脑裂现象&#xff0c;均为某节点脑裂/自动关闭。 核心日志如下&#xff1a; Master节点 出现Hazelcast监控…

学会python——在excel中写入数据(python实例十三)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3 .想Excel中写入数据 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

[JS]DOM元素

介绍 DOM(Document Object Model---文档对象模型) 是浏览器提供的一套专门用来操作网页内容的API DOM树 把HTML文档以树状结构直观的表现出来, 称为文档数或者DOM树, DOM树直观的展示了标签与标签的关系 DOM对象 浏览器根据html标签生成的JS对象称为DOM对象 document对象 …

Java 树形结构数据如何高效返回给前端进行展示?

在开发过程中我们总是遇到一些具有层次结构的数据&#xff0c;这些数据在前端也总是需要以树形结构进行显示&#xff0c;那么后端接口如何高效的去将这些数据封装成树形结构呢&#xff1f;下面来进行解析讲解。 最终实现的一个结果图 设计返回的实体VO import com.fasterxm…

PTA—C语言期末复习(选择题)

1. 按照标识符的要求&#xff0c;&#xff08;A&#xff09;不能组成标识符。 A.连接符 B.下划线 C.大小写字母 D.数字字符 在大多数编程语言中&#xff0c;标识符通常由字母&#xff08;包括大写和小写&#xff09;、数字和下划线组成&#xff0c;但不能以数字开头&#xff0c…