UE5 C++ LevelSequence

news2024/11/19 17:23:56

前言

       最近在用UE C++做一些功能,用到了Level Sequence功能,但是看了下UE官方论坛包括一些文章基本没有关于C++ 处理Level Sequence 这块内容,有的也是一些修改或者源码原理的一些内容分析,接下来我就把我新建Sequence包括一些库的调用写下来,基本上把源码翻了一遍了。

过程

       因为我这是基本走了一遍UE官方的新建的流程,所以我这里UE的插件模式Editor Toolbar Button模式。

       创建完这个模式的插件以后,需要我们在Edit -> Edit Preferences -> Miscellaneous中将Display UI extension Poins勾选,因为我们是一个编辑器按钮的插件,所以我们要知道我们的插件按钮放在哪个UI层级下面,开启这个勾选以后,它就会显示对应的层级关系。

       创建完插件同步代码以后,在我们的插件Source文件中就会默认.h / Commands.h  / Style.h三个文件默认就是我们用来处理常规逻辑的,Commadns是我们同步编辑器一些配置用的,Style就是我们这个插件的一些样式内容了,我们可以先打开Commans.cpp文件编辑按钮名称以及鼠标提示词

       然后打开我们的默认CPP文件,因为我这里是不需要插件按钮在其他地方显示出来的,所以我就把PlayToolBar这边的显示注解掉了,如果大家有需要去开启就好了。设置完成以后,点击编译,运行我们的项目这时你就会发现在我们创建UE LevelSequence的地方就有了一个我们自己的插件

       现在我们这个Level Sequence插件就基本创建完成了,在我们的编辑器中有一个自己的按钮了,接下来我们来实现逻辑,第一步如UE一样,我们也打开一个Save Asset 的窗口对我们的Level Sequence 进行命名和路径选择。创建一个函数,命名为CreateLevelSequenceAsset,这步的操作我是在Movice下面的LevelSequenceEditor里面找到的,他主要就是打开一个UE窗口创建一个Level Sequence资产

       我这里创建完Level Sequence以后是创建了一个CameraCut然后又创建了一个摄像机,将这个摄像机绑定到了CameraCut上面作为了一个默认设置。我是先在场景中创建了相机,这个逻辑处理过程是如果这个场景中没有这个摄像机我就进行创建,有的话就不创建了,这样我所有的LevelSequence都用的一个摄像机,如果大家不需要这么做就修改一下逻辑就好了,创建相机这块很简单,创建了一个相机类,代码如下:

ACameraActor* DoseCineCameraExist()
{
	UWorld* World = GWorld;
	bool bCineCameraExists = false;
	for (TActorIterator<ACameraActor> It(World); It; ++It)
	{
		ACameraActor* ExistingCineCameraActor = *It;
		if (ExistingCineCameraActor && ExistingCineCameraActor->GetActorLabel() == "MainCamera")
		{
			bCineCameraExists = true;
			// 如果存在指定名称的 CineCameraActor,则直接返回该 Actor
			return ExistingCineCameraActor;
			break;
		}
	}
	if (!bCineCameraExists)
	{
		FActorSpawnParameters SpawnParams;
		ACameraActor* NewCineCameraActor = GWorld->SpawnActor<ACameraActor>(ACameraActor::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);

		// 设置新创建的 CineCameraActor 的位置和旋转
		if (NewCineCameraActor)
		{
			NewCineCameraActor->SetActorLabel("MainCamera");
			// 设置位置和旋转
			NewCineCameraActor->SetActorLocation(FVector(0, 0, 50));
			NewCineCameraActor->SetActorRotation(FRotator(0, 0, 0));
		}
		return NewCineCameraActor;
	}
	return nullptr;
}

       现在,我们进行主功能,就是创建一个CameraCut然后将我们的摄像机绑定上去,接下来的主要逻辑顺序基本分层为创建一个对应类型的Track然后设置其属性或者Section。代码如下:

	if (NewAsset && NewAsset->IsA<ULevelSequence>())
	{
		//将CameraCut添加到Seq中
		ULevelSequence* levelsequence = static_cast<ULevelSequence*>(NewAsset);

		UMovieSceneCameraCutTrack* CameraCutTrack = Cast<UMovieSceneCameraCutTrack>(levelsequence->MovieScene->GetCameraCutTrack());
		CameraCutTrack = Cast<UMovieSceneCameraCutTrack>(levelsequence->MovieScene->AddCameraCutTrack(UMovieSceneCameraCutTrack::StaticClass()));

        //定义相机以及Transform数据
		AActor* cameraActor = DoseCineCameraExist();
		FVector DefaultLocation = FVector::ZeroVector;
		FVector DefaultRotation = FVector::ZeroVector;
		FVector DefaultScale = FVector::OneVector;


		DefaultLocation = cameraActor->GetActorLocation();
		DefaultRotation = cameraActor->GetActorRotation().Euler();
		DefaultScale = cameraActor->GetActorScale();

		if (cameraActor)
		{
			FGuid Guid = levelsequence->FindBindingFromObject(cameraActor, cameraActor->GetWorld());
			Guid = Cast<UMovieSceneSequence>(levelsequence)->CreatePossessable(cameraActor);

			int32 StartFrame = 0;
			int32 EndFrame = 50;

			int FrameTickValue = levelsequence->MovieScene->GetTickResolution().AsDecimal();
			UMovieSceneCameraCutSection* Section = CameraCutTrack->AddNewCameraCut(UE::MovieScene::FRelativeObjectBindingID(Guid), FFrameNumber(StartFrame * FrameTickValue));
			Section->SetEndFrame(FFrameNumber(EndFrame * FrameTickValue));
			Section->SetIsLocked(true);

			levelsequence->PostEditChange();

			
			UMovieScene3DTransformTrack* TransformTrack = levelsequence->GetMovieScene()->AddTrack<UMovieScene3DTransformTrack>(Guid);

			UMovieScene3DTransformSection* TransformSection = Cast<UMovieScene3DTransformSection>(TransformTrack->CreateNewSection());
			TransformTrack->AddSection(*TransformSection);
			TransformSection->SetRange(TRange<FFrameNumber>(FFrameNumber(0), FFrameNumber(150)));

			TArrayView<FMovieSceneDoubleChannel*> DoubleChannels = TransformSection->GetChannelProxy().GetChannels<FMovieSceneDoubleChannel>();

			DoubleChannels[0]->AddCubicKey(0, DefaultLocation.X);
			DoubleChannels[1]->AddCubicKey(0, DefaultLocation.Y);
			DoubleChannels[2]->AddCubicKey(0, DefaultLocation.Z);
			DoubleChannels[3]->AddCubicKey(0, DefaultRotation.X);
			DoubleChannels[4]->AddCubicKey(0, DefaultRotation.Y);
			DoubleChannels[5]->AddCubicKey(0, DefaultRotation.Z);
			DoubleChannels[6]->AddCubicKey(0, DefaultScale.X);
			DoubleChannels[7]->AddCubicKey(0, DefaultScale.Y);
			DoubleChannels[8]->AddCubicKey(0, DefaultScale.Z);
			levelsequence->PostEditChange();

		}
	}

       具体的实现代码看下顺序其实就就能看出来的过程比较顺利,这样我们就已经在我们的工程中创建了一个LevelSequence了,但是UE中创建的LevelSequence后会自动打开这个LevelSequecne编辑器进行动画编辑我们也把这块加上。

	// Spawn an actor at the origin, and either move infront of the camera or focus camera on it (depending on the viewport) and open for edit

	UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass(ALevelSequenceActor::StaticClass());
	if (!ensure(ActorFactory))
	{
		return;
	}

	AActor* Actor = GEditor->UseActorFactory(ActorFactory, FAssetData(NewAsset), &FTransform::Identity);
	if (Actor == nullptr)
	{
		return;
	}
	ALevelSequenceActor* NewActor = CastChecked<ALevelSequenceActor>(Actor);
	if (GCurrentLevelEditingViewportClient != nullptr && GCurrentLevelEditingViewportClient->IsPerspective())
	{
		GEditor->MoveActorInFrontOfCamera(*NewActor, GCurrentLevelEditingViewportClient->GetViewLocation(), GCurrentLevelEditingViewportClient->GetViewRotation().Vector());
	}
	else
	{
		GEditor->MoveViewportCamerasToActor(*NewActor, false);
	}

	GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(NewAsset);

       现在我们已经完成了打开-> 创建-> 保存 ->打开编辑器工作,接下来我把需要的头文件引用和环境应用配置进行一下,这个UE C++ levelsequence工作就完成了,第一步打开我们的uplugin文件我

们将LevelSequenceEditor配置一下,在modules中添加AdditionalDependencies然后保存

{
	"FileVersion": 3,
	"Version": 1,
	"VersionName": "1.0",
	"FriendlyName": "ViewSequence",
	"Description": "",
	"Category": "MainSequence",
	"CreatedBy": "筱星辰",
	"CreatedByURL": "",
	"DocsURL": "",
	"MarketplaceURL": "",
	"SupportURL": "",
	"CanContainContent": false,
	"Installed": true,
	"Modules": [
		{
			"Name": "ViewSequence",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"LevelSequenceEditor"
			]
		}
	]
}

       然后打开Buil.cs配置我们的环境在PublicDependencyModuleNames中进行添加和配置

		PublicDependencyModuleNames.AddRange(
			new string[]
			{
				"Core",
                "LevelSequence",
                "CoreUObject",
                "UnrealEd",
                "Engine",
                "MovieScene",
                "MovieSceneTracks",
				"LevelSequenceEditor",
                "DesktopPlatform",
                "MovieSceneTracks",
                "Sequencer"
				// ... add other public dependencies that you statically link with here ...
			}
			);
			
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"Projects",
				"InputCore",
				"EditorFramework",
				"UnrealEd",
				"ToolMenus",
				"CoreUObject",
				"Engine",
				"Slate",
				"SlateCore"
				// ... add private dependencies that you statically link with here ...	
			}
			);

       最后打开我们默认的主要CPP文件添加相关使用的头文件即可,我直接把所有代码放进来,这样大家在用的时候前面有不清楚的地方就可以回来看这个文件了。

// Copyright Epic Games, Inc. All Rights Reserved.


#include "ViewSequence.h"

#include "Editor.h"
#include "FileHelpers.h"
#include "Misc/MessageDialog.h"
#include "ToolMenus.h"
#include "ViewSequenceStyle.h"
#include "ViewSequenceCommands.h"

#include "MovieScene.h"
#include "LevelSequence.h"
#include <LevelSequencePlayer.h>
#include "LevelSequenceActor.h"
#include "MovieScene/Public/Channels/MovieSceneChannelProxy.h"
#include "Sequencer/Public/ISequencerModule.h"
#include "LevelEditorViewport.h"



#include <Tracks/MovieScene3DTransformTrack.h>
#include "Tracks/MovieSceneCameraCutTrack.h"
#include "Tracks/MovieSceneTransformTrack.h"


#include "Sections/MovieSceneCameraCutSection.h"
#include "Sections/MovieScene3DTransformSection.h"

#include "Camera/CameraActor.h"
#include "Camera/CameraComponent.h"

#include "AssetData.h"
#include "AssetRegistryModule.h"
#include "AssetToolsModule.h"
#include "AssetRegistryModule.h"  
#include "AssetRegistry/Public/AssetRegistryModule.h"
#include "AssetRegistry/Public/IAssetRegistry.h"  

#include "Modules/ModuleManager.h"
#include "Framework/Application/SlateApplication.h"  

#include "Serialization/BulkData.h"  
#include "Editor/EditorEngine.h"  
#include "UnrealEd/Public/UnrealEd.h"



static const FName ViewSequenceTabName("ViewSequence");

// 定义全局FString数组  
TArray<FString> GlobalFStringArray;
FString FstringCon;

#define LOCTEXT_NAMESPACE "FViewSequenceModule"

void FViewSequenceModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module

	FViewSequenceStyle::Initialize();
	FViewSequenceStyle::ReloadTextures();

	FViewSequenceCommands::Register();

	PluginCommands = MakeShareable(new FUICommandList);

	PluginCommands->MapAction(
		FViewSequenceCommands::Get().PluginAction,
		FExecuteAction::CreateRaw(this, &FViewSequenceModule::PluginButtonClicked),
		FCanExecuteAction());
	UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FViewSequenceModule::RegisterMenus));
}

void FViewSequenceModule::ShutdownModule()
{
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
	// we call this function before unloading the module.

	UToolMenus::UnRegisterStartupCallback(this);

	UToolMenus::UnregisterOwner(this);

	FViewSequenceStyle::Shutdown();
	FViewSequenceCommands::Unregister();
}

ACameraActor* DoseCineCameraExist()
{
	UWorld* World = GWorld;
	bool bCineCameraExists = false;
	for (TActorIterator<ACameraActor> It(World); It; ++It)
	{
		ACameraActor* ExistingCineCameraActor = *It;
		if (ExistingCineCameraActor && ExistingCineCameraActor->GetActorLabel() == "MainCamera")
		{
			bCineCameraExists = true;
			// 如果存在指定名称的 CineCameraActor,则直接返回该 Actor
			return ExistingCineCameraActor;
			break;
		}
	}
	if (!bCineCameraExists)
	{
		FActorSpawnParameters SpawnParams;
		ACameraActor* NewCineCameraActor = GWorld->SpawnActor<ACameraActor>(ACameraActor::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);

		// 设置新创建的 CineCameraActor 的位置和旋转
		if (NewCineCameraActor)
		{
			NewCineCameraActor->SetActorLabel("MainCamera");
			// 设置位置和旋转
			NewCineCameraActor->SetActorLocation(FVector(0, 0, 50));
			NewCineCameraActor->SetActorRotation(FRotator(0, 0, 0));
		}
		return NewCineCameraActor;
	}
	return nullptr;
}

void CreateLevelSequenceAsset()
{
	//创建资产模版
	IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();

	UObject* NewAsset = nullptr;
	for (TObjectIterator<UClass> It;It; ++It)
	{
		UClass* CurrentClass = *It;
		if (CurrentClass->IsChildOf(UFactory::StaticClass()) && !(CurrentClass->HasAnyClassFlags(CLASS_Abstract)))
		{
			UFactory* Factory = Cast<UFactory>(CurrentClass->GetDefaultObject());
			if (Factory->CanCreateNew() && Factory->ImportPriority >= 0 && Factory->SupportedClass == ULevelSequence::StaticClass())
			{
				//打开UE窗口进行创建
				NewAsset = AssetTools.CreateAssetWithDialog(ULevelSequence::StaticClass(), Factory);
				break;
			}
		}
	}

	if (!NewAsset)
	{
		return;
	}

	if (NewAsset && NewAsset->IsA<ULevelSequence>())
	{
		//将CameraCut添加到Seq中
		ULevelSequence* levelsequence = static_cast<ULevelSequence*>(NewAsset);

		UMovieSceneCameraCutTrack* CameraCutTrack = Cast<UMovieSceneCameraCutTrack>(levelsequence->MovieScene->GetCameraCutTrack());
		CameraCutTrack = Cast<UMovieSceneCameraCutTrack>(levelsequence->MovieScene->AddCameraCutTrack(UMovieSceneCameraCutTrack::StaticClass()));


		AActor* cameraActor = DoseCineCameraExist();
		FVector DefaultLocation = FVector::ZeroVector;
		FVector DefaultRotation = FVector::ZeroVector;
		FVector DefaultScale = FVector::OneVector;


		DefaultLocation = cameraActor->GetActorLocation();
		DefaultRotation = cameraActor->GetActorRotation().Euler();
		DefaultScale = cameraActor->GetActorScale();

		if (cameraActor)
		{
			FGuid Guid = levelsequence->FindBindingFromObject(cameraActor, cameraActor->GetWorld());
			Guid = Cast<UMovieSceneSequence>(levelsequence)->CreatePossessable(cameraActor);

			int32 StartFrame = 0;
			int32 EndFrame = 50;

			int FrameTickValue = levelsequence->MovieScene->GetTickResolution().AsDecimal();
			UMovieSceneCameraCutSection* Section = CameraCutTrack->AddNewCameraCut(UE::MovieScene::FRelativeObjectBindingID(Guid), FFrameNumber(StartFrame * FrameTickValue));
			Section->SetEndFrame(FFrameNumber(EndFrame * FrameTickValue));
			Section->SetIsLocked(true);

			levelsequence->PostEditChange();
			
			UMovieScene3DTransformTrack* TransformTrack = levelsequence->GetMovieScene()->AddTrack<UMovieScene3DTransformTrack>(Guid);

			UMovieScene3DTransformSection* TransformSection = Cast<UMovieScene3DTransformSection>(TransformTrack->CreateNewSection());
			TransformTrack->AddSection(*TransformSection);
			TransformSection->SetRange(TRange<FFrameNumber>(FFrameNumber(0), FFrameNumber(150)));

			TArrayView<FMovieSceneDoubleChannel*> DoubleChannels = TransformSection->GetChannelProxy().GetChannels<FMovieSceneDoubleChannel>();

			DoubleChannels[0]->AddCubicKey(0, DefaultLocation.X);
			DoubleChannels[1]->AddCubicKey(0, DefaultLocation.Y);
			DoubleChannels[2]->AddCubicKey(0, DefaultLocation.Z);
			DoubleChannels[3]->AddCubicKey(0, DefaultRotation.X);
			DoubleChannels[4]->AddCubicKey(0, DefaultRotation.Y);
			DoubleChannels[5]->AddCubicKey(0, DefaultRotation.Z);
			DoubleChannels[6]->AddCubicKey(0, DefaultScale.X);
			DoubleChannels[7]->AddCubicKey(0, DefaultScale.Y);
			DoubleChannels[8]->AddCubicKey(0, DefaultScale.Z);
			levelsequence->PostEditChange();

		}
	}


	// Spawn an actor at the origin, and either move infront of the camera or focus camera on it (depending on the viewport) and open for edit

	UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass(ALevelSequenceActor::StaticClass());
	if (!ensure(ActorFactory))
	{
		return;
	}

	AActor* Actor = GEditor->UseActorFactory(ActorFactory, FAssetData(NewAsset), &FTransform::Identity);
	if (Actor == nullptr)
	{
		return;
	}
	ALevelSequenceActor* NewActor = CastChecked<ALevelSequenceActor>(Actor);
	if (GCurrentLevelEditingViewportClient != nullptr && GCurrentLevelEditingViewportClient->IsPerspective())
	{
		GEditor->MoveActorInFrontOfCamera(*NewActor, GCurrentLevelEditingViewportClient->GetViewLocation(), GCurrentLevelEditingViewportClient->GetViewRotation().Vector());
	}
	else
	{
		GEditor->MoveViewportCamerasToActor(*NewActor, false);
	}

	GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(NewAsset);


	//ULevelSequenceEditorBlueprintLibrary::SetLockCameraCutToViewport(true);

}


void FViewSequenceModule::PluginButtonClicked()
{
	CreateLevelSequenceAsset();
}


void FViewSequenceModule::RegisterMenus()
{

	//UI对照信息可以在项目偏好设置中找到Miscellaneous中的Disply UI Extension Points开启勾选
	// Owner will be used for cleanup in call to UToolMenus::UnregisterOwner
	FToolMenuOwnerScoped OwnerScoped(this);
	{
		UToolMenu* Menu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.Cinematics");//获取到对应的分类
		{
			FToolMenuSection& Section = Menu->FindOrAddSection("LevelEditorNewCinematics");//添加到指定地址
			Section.AddMenuEntryWithCommandList(FViewSequenceCommands::Get().PluginAction, PluginCommands);
			

		}
	}


	//{
	//	UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.PlayToolBar");
	//	{
	//		FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("PluginTools");
	//		{
	//			FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FViewSequenceCommands::Get().PluginAction));
	//			Entry.SetCommandList(PluginCommands);
	//		}
	//	}
	//}


}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FViewSequenceModule, ViewSequence)

结尾

       这个功能到这里就结束了,希望对大家有帮助,关于LevelSequence这块功能使用可以到油管看下,有个大佬写了很多绑定和添加的过程,功能也很使用,应该会帮助你详细了解Level Sequecen C++的,源码的话在Movice下面的LevelSequenceEditor中涵盖了所有内容,有兴趣的话可以翻一下。

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

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

相关文章

CleanMyMac X中文---一键优化Mac,释放存储空间新利器

CleanMyMac X是一款专业的苹果笔记本系统管理工具&#xff0c;旨在全面优化和清理Mac内存&#xff0c;释放更多有效空间&#xff0c;使Mac始终保持最佳状态。它具备智能扫描功能&#xff0c;能够准确识别并清理系统垃圾、冗余文件以及大型和废旧文件&#xff0c;有效释放磁盘空…

深入了解美颜技术开发:利用深度学习打造直播美颜SDK

直播美颜不仅让主播在镜头前更加自信&#xff0c;也让观众享受到更美好的视觉体验。而在美颜技术的背后&#xff0c;深度学习技术正扮演着至关重要的角色。 一、美颜技术的发展历程 这些算法往往无法达到自然的效果&#xff0c;容易出现过度处理或者失真的情况。随着深度学习…

CSS3新增的语法(四)

CSS3新增的语法&#xff08;四&#xff09;【布局】 14. 多列布局15.伸缩盒模型1. 伸缩盒模型简介2. 伸缩容器、伸缩项目3. 主轴与侧轴4. 主轴方向5. 主轴换行方式6. flex-flow7. 主轴对齐方式8. 侧轴对齐方式8.1 一行的情况8.2 多行的情况 9.flex 实现水平垂直居中10. 伸缩性1…

【opencv】教程代码 —Histograms_Matching(1)反向投影:在给定图像中寻找特定的颜色或颜色分布...

1. calcBackProject_Demo1.cpp 反向投影函数的使用 /*** file BackProject_Demo1.cpp* brief 示例代码&#xff0c;演示反向投影函数的使用* author OpenCV团队*/#include "opencv2/imgproc.hpp" // 包括图像处理相关功能的头文件 #include "opencv2/imgcodecs…

VMware创建Ubuntu虚拟机详细教程

下载ISO映像文件 进入官网下载&#xff1a;Download Ubuntu Desktop | Download | Ubuntu 下面是一些其他的下载路径&#xff1a; 中国官网 https://cn.ubuntu.com/ 中科大源 Index of /ubuntu-releases/ (ustc.edu.cn) 阿里云开源镜像站 ubuntu-releases安装包下载_开源镜像…

使用 BeeWare 构建 Python GUI 应用程序

点击下方卡片&#xff0c;关注“小白玩转Python”公众号 本文探讨使用 BeeWare 套件通过 Python 构建应用程序的基础知识&#xff0c;详细介绍其功能、优点以及与其他流行框架的比较。 由于 Python 语言的简单性和多功能性&#xff0c;用它构建应用程序变得越来越流行。在 Pyth…

Centos7安装单机版Kafka

下载 链接&#xff1a;https://pan.baidu.com/s/1W8lVEF6Y-xlg6zr3l9QAbg?pwdhbkt 提取码&#xff1a;hbkt 上传到服务器/opt目录 安装 # kafka安装目录为 /opt/kafka cd /opt; mkdir kafka; mv kafka_2.13-2.7.0.tgz ./kafka;cd kafka; #解压 tar -zxvf kafka_2.13-2.7.0…

边缘计算盒子与云计算:谁更适合您的业务需求?

边缘计算盒子和云计算&#xff0c;这两个概念听起来可能有点复杂&#xff0c;但其实它们就是两种不同的数据处理方式。那谁更适合您的业务需求呢&#xff1f;咱们来详细说说。 边缘计算盒子&#xff0c;就像是个小型的数据处理中心&#xff0c;放在离你业务现场比较近的地方。它…

STM32 TIM DMA burst 输出变频 PWM 波形

1. 问题背景 客户需要 MCU 输出一组变频的 PWM 波形来控制外围器件&#xff0c;并且不同频率脉冲的个数也不同。STM32U5 芯片拥有 TIM1/TIM8 高级定时器&#xff0c;还有通用定时器TIM2/TIM3/TIM4/TIM5 以及 TIM15/TIM16/TIM17。TIM 模块中&#xff0c;可通过修改 ARR 寄存器的…

OWASP API 安全风险,有哪些安全措施

随着互联网的快速发展&#xff0c;Web应用已成为人们日常生活和工作中不可或缺的一部分。然而&#xff0c;Web应用的安全问题也日益凸显&#xff0c;给企业和个人带来了极大的风险。 对于一些安全行业的用户来说&#xff0c;不少都听过关于OWASP这个词&#xff0c;很多用户想要…

redis---位图Bitmap和位域 Bitfield

位图是字符串类型的拓展&#xff0c;可以使用一个string类型来模拟一个Bit数组。数组的下标就是偏移量&#xff0c;值只有0和1&#xff0c;也支持一些位运算&#xff0c;比如与或非&#xff0c;异或等等&#xff0c;它们的应用场景非常广泛比如可以用来记录用户的签到情况&…

【Java核心能力】饿了么一面:Redis 面试连环炮

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

flink1.18源码本地调试环境

01 源码本地调试环境搭建 1. 从github拉取源码创建本地项⽬ https://github.com/apache/flink.git 可以拉取github上官⽅代码 https://github.com/apache/flink.git GitHub - apache/flink: Apache Flink 2. 配置编译环境 ctrlaltshifts &#xff08;或菜单&#xff09;打…

zabbix 7.0 新增功能亮点(一)——T参数

概要&#xff1a; T参数是zabbix7.0新增的一项功能&#xff0c;它支持对配置文件进行可用性验证&#xff0c;即zabbix程序(server/proxy/agent等)修改配置文件后&#xff0c;支持-T或–test-config参数验证配置参数可用性。 T参数主要包含以下三个方面的应用场景&#xff1a; …

SQL语句生成器,支持MSSQL/MYSQL/SQLITE/ACCESS/EXCEL

经过7个月的艰苦开发&#xff0c;SQL语句生成器终于和各位见面了&#xff0c;因为工程量浩大&#xff0c;一度做到崩溃&#xff0c;差点烂尾&#xff0c;好在经过N次激烈思想斗争后还是坚持了下来累累累累累累累 本软件能够自动生成SQL语句及对应的易语言代码&#xff0c;还有相…

如何在Java中,使用jackson实现json缩进美化

导入的maven依赖 <!--json--> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.0</version> </dependency>示例代码 json要是String类型 public…

HarmonyOS NEXT应用开发之MVVM模式

应用通过状态去渲染更新UI是程序设计中相对复杂&#xff0c;但又十分重要的&#xff0c;往往决定了应用程序的性能。程序的状态数据通常包含了数组、对象&#xff0c;或者是嵌套对象组合而成。在这些情况下&#xff0c;ArkUI采取MVVM Model View ViewModel模式&#xff0c;其…

Linux TUN设备实现Tunnel性能分析

一、TUN/TAP设备原理&#xff1a; Linux的TUN/TAP设备是一种可以使得应用层与TCP/IP协议栈交互的驱动模块&#xff0c;通常用于组建虚拟局域网中的点对点隧道&#xff08;Tunnel&#xff09;&#xff0c;可以工作于2层&#xff08;TAP设备&#xff09;和3层&#xff08;TUN设备…

下载与安装Latex(windows简洁板)

总共要安装两个软件&#xff1a;TeX Live与TeX Studio 下载与安装TeX Live 下载 下载地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/Images/ 点击&#xff1a; texlive2024.iso 文件很大&#xff0c;可能会慢点 2. 安装 下载好了iso文件&…

redis事务(redis features)

redis支持事务&#xff0c;也就是可以在一次请求中执行多个命令。redis中的事务主要是通过MULTI和EXEC这两个命令来实现的。 MULTI命令用来开启一个事务&#xff0c;事务开启之后&#xff0c;所有的命令就都会被放入到一个队列中&#xff0c;最后通过一个EXEC命令来执行事务中…