diff --git a/Content/Blueprint/Level/GameMode/BP_BusyLevelGameMode.uasset b/Content/Blueprint/Level/GameMode/BP_BusyLevelGameMode.uasset index ee2dc77..8459331 100644 Binary files a/Content/Blueprint/Level/GameMode/BP_BusyLevelGameMode.uasset and b/Content/Blueprint/Level/GameMode/BP_BusyLevelGameMode.uasset differ diff --git a/Source/BusyRabbit/Private/BusyGamePlayLibrary.cpp b/Source/BusyRabbit/Private/BusyGamePlayLibrary.cpp index 1bfeb1c..f252196 100644 --- a/Source/BusyRabbit/Private/BusyGamePlayLibrary.cpp +++ b/Source/BusyRabbit/Private/BusyGamePlayLibrary.cpp @@ -47,8 +47,8 @@ UClass* UBusyGamePlayLibrary::GetGameUIClass(const FString& ClassName){ return Class ? Class->Get() : nullptr; } -UWorld* UBusyGamePlayLibrary::K2_GetWorld(UObject* obj){ - return Cast(obj->GetOuter()); +UWorld* UBusyGamePlayLibrary::K2_GetWorld(const UObject* obj){ + return obj->GetWorld(); } bool UBusyGamePlayLibrary::GetLevelBaseConfig(const FName& RowName, FBusyLevelBaseConfig& RowData){ @@ -84,7 +84,6 @@ bool UBusyGamePlayLibrary::GetCookMaterialStateConfig(const FName& RowName, FBus } FLuaBPVar UBusyGamePlayLibrary::CreateTextureBuffer(UObject* WorldContextObject){ - // 创建纹理 auto DataTexture = UTexture2D::CreateTransient(512, 1, PF_R32_FLOAT); DataTexture->Filter = TF_Trilinear; DataTexture->AddressX = TA_Clamp; @@ -94,15 +93,12 @@ FLuaBPVar UBusyGamePlayLibrary::CreateTextureBuffer(UObject* WorldContextObject) } void UBusyGamePlayLibrary::UpdateTextureBuffer(UTexture2D *DataTexture, TArray FloatData){ - // 锁定纹理以便写入 DataTexture->GetPlatformData()->Mips[0]; FTexture2DMipMap& Mip = DataTexture->GetPlatformData()->Mips[0]; void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE); - // 将浮点数据复制到纹理 FMemory::Memcpy(Data, FloatData.GetData(), FloatData.Num() * sizeof(float)); - // 解锁并更新纹理 Mip.BulkData.Unlock(); DataTexture->UpdateResource(); } diff --git a/Source/BusyRabbit/Private/Gas/BusyAbilitySystemComponent.cpp b/Source/BusyRabbit/Private/Gas/BusyAbilitySystemComponent.cpp deleted file mode 100644 index d3ce2bb..0000000 --- a/Source/BusyRabbit/Private/Gas/BusyAbilitySystemComponent.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Gas/BusyAbilitySystemComponent.h" - diff --git a/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp b/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp index f614b8d..0298b1d 100644 --- a/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp +++ b/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp @@ -7,21 +7,30 @@ ABusyPawnBase::ABusyPawnBase() { + RootScene = CreateDefaultSubobject(TEXT("RootScene")); SpineRoot = CreateDefaultSubobject(TEXT("SpineRoot")); SphereComponent = CreateDefaultSubobject(TEXT("SphereComponent")); SpineRenderComponent = CreateDefaultSubobject(TEXT("SpineRenderComponent")); SpineAnimationComponent = CreateDefaultSubobject(TEXT("SpineAnimationComponent")); + AbilitySystemComponent = CreateDefaultSubobject(TEXT("AbilitySystemComponent")); + MovementComponent = CreateDefaultSubobject(TEXT("MovementComponent")); + RootComponent = RootScene; SpineRoot->SetupAttachment(RootScene); SphereComponent->SetupAttachment(SpineRoot); SpineRenderComponent->SetupAttachment(SpineRoot); - SpineRoot->SetRelativeRotation(FRotator(0, 0, -90)); + + bReplicates = true; + SetReplicatingMovement(true); + NetUpdateFrequency = 60.0f; + MovementComponent->SetIsReplicated(true); + AbilitySystemComponent->SetIsReplicated(true); } void ABusyPawnBase::BeginPlay() @@ -40,3 +49,4 @@ float ABusyPawnBase::GetSpeed_Implementation()const { return 280; } + diff --git a/Source/BusyRabbit/Private/Level/Actor/Components/BusyAbilitySystemComponent.cpp b/Source/BusyRabbit/Private/Level/Actor/Components/BusyAbilitySystemComponent.cpp new file mode 100644 index 0000000..557f1be --- /dev/null +++ b/Source/BusyRabbit/Private/Level/Actor/Components/BusyAbilitySystemComponent.cpp @@ -0,0 +1,6 @@ +锘#include "Level/Actor/Components/BusyAbilitySystemComponent.h" + +FString UBusyAbilitySystemComponent::GetLuaFilePath_Implementation() const +{ + return LuaFilePath; +} diff --git a/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp b/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp index a8a90b3..6a935e1 100644 --- a/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp +++ b/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp @@ -30,10 +30,14 @@ FVector2D UBusyPawnMovement::GetMoveDirection()const return FVector2D(); } +#pragma optimize("",off) void UBusyPawnMovement::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (!GetOwner()->HasAuthority()) return; + AActor* Owner = GetOwner(); const IBusyMovable* Movable = Cast(Owner); if (!Owner || !Movable) return; @@ -61,8 +65,12 @@ void UBusyPawnMovement::TickComponent(float DeltaTime, ELevelTick TickType, } if (!NewLocation.Equals(CurrentLocation)) { - Owner->SetActorLocation(NewLocation, true); + Owner->SetActorLocation(NewLocation, true); + Owner->ForceNetUpdate(); } - Movable->Execute_UpdateMoveDirection(Owner, GetMoveDirection()); -} + + + // Movable->Execute_UpdateMoveDirection(Owner, GetMoveDirection()); +} +#pragma optimize("",on) diff --git a/Source/BusyRabbit/Private/Level/BusyLevelItem.cpp b/Source/BusyRabbit/Private/Level/BusyLevelItem.cpp index 3968292..350c38e 100644 --- a/Source/BusyRabbit/Private/Level/BusyLevelItem.cpp +++ b/Source/BusyRabbit/Private/Level/BusyLevelItem.cpp @@ -4,7 +4,6 @@ #include "Level/BusyLevelItem.h" #include "Components/CapsuleComponent.h" #include "Components/WidgetComponent.h" -#include "Gas/BusyAbilitySystemComponent.h" #include "BusyGamePlayLibrary.h" ABusyLevelItem::ABusyLevelItem(): CurrentItemID("100001") { @@ -16,7 +15,6 @@ ABusyLevelItem::ABusyLevelItem(): CurrentItemID("100001") { PickBar = CreateDefaultSubobject(TEXT("PickBar")); LevelItemAttribute = CreateDefaultSubobject("LevelItemAttribute"); - AbilityComponent = CreateDefaultSubobject("RoleAbility"); InitSprite(); InitCapsule(); diff --git a/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp b/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp index 5eb92c3..1ea8c05 100644 --- a/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp +++ b/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp @@ -1,6 +1,10 @@ 锘#include "Level/LevelPlayerController.h" #include "Level/Actor/BusyPlayerRole.h" #include "EnhancedInput/Public/EnhancedInputSubsystems.h" +#include "Level/LevelPlayerState.h" +#include "EnhancedInput/Public/EnhancedInputSubsystems.h" +#include "EnhancedInput/Public/EnhancedInputComponent.h" + ALevelPlayerController::ALevelPlayerController() { @@ -16,11 +20,27 @@ void ALevelPlayerController::BeginPlay() SetInputMode(InputMode); // 娉ㄥ唽杈撳叆 - const auto Subsystem = ULocalPlayer::GetSubsystem(GetLocalPlayer()); - if (InputMapping && Subsystem) + if (!HasAuthority()) { - Subsystem->AddMappingContext(InputMapping, 0); + const auto Subsystem = ULocalPlayer::GetSubsystem(GetLocalPlayer()); + if (InputMapping && Subsystem) + { + Subsystem->AddMappingContext(InputMapping, 0); + } + + + if (UEnhancedInputComponent* EnhancedInput = CastChecked(InputComponent)) { + EnhancedInput->BindAction(TouchAction, ETriggerEvent::Triggered, this, FName("OnTouch")); + } } + +} + +void ALevelPlayerController::SetRoleMoveTo_Implementation(const FVector2D& Location) +{ + ABusyPlayerRole* ControlledRole = GetControlledRole(); + if (!ControlledRole) return; + ControlledRole->MovementComponent->MoveTo(Location); } bool ALevelPlayerController::GetCursorPosition(FVector2D& Position) const @@ -42,11 +62,25 @@ void ALevelPlayerController::GetCursorHitResult(TArray& Results) const { } -void ALevelPlayerController::GetControlledRole() const +ABusyPlayerRole* ALevelPlayerController::GetControlledRole() const { + if (const ALevelPlayerState* PS = GetPlayerState()) + { + return PS->GetControlledRole(); + } + return nullptr; } void ALevelPlayerController::SwitchControlledRole(ABusyPlayerRole* Target) { this->SetViewTarget(Target); } + +void ALevelPlayerController::OnTouch(const FInputActionValue& Value) +{ + FVector2D Position; + if (GetCursorPosition(Position)) + { + SetRoleMoveTo(Position); + } +} diff --git a/Source/BusyRabbit/Private/Level/LevelPlayerState.cpp b/Source/BusyRabbit/Private/Level/LevelPlayerState.cpp index 75117b3..009c3e1 100644 --- a/Source/BusyRabbit/Private/Level/LevelPlayerState.cpp +++ b/Source/BusyRabbit/Private/Level/LevelPlayerState.cpp @@ -1,6 +1,5 @@ 锘#include "Level/LevelPlayerState.h" - -#include "Level/LevelPlayerController.h" +#include "Net/UnrealNetwork.h" #include "Level/Actor/BusyPlayerRole.h" @@ -10,38 +9,62 @@ DEFINE_LOG_CATEGORY(LogLevelPlayerState); void ALevelPlayerState::BeginPlay() { Super::BeginPlay(); - UWorld* World = GetWorld(); - const auto PC = Cast(GetPlayerController()); - if (!World || !PC) - { - UE_LOG(LogLevelPlayerState, Error, TEXT("ALevelPlayerController::BeginPlay() failed!")); - return; - } - - FVector2D SpawnLocation = GetSpawnLocation(); - for (auto PawnClass : RoleClasses) - { - FTransform SpawnTransform; - FActorSpawnParameters Params; - SpawnTransform.SetLocation(FVector(SpawnLocation, 50)); - if (auto *NewRole = Cast(World->SpawnActor(PawnClass, nullptr, Params))) - { - Roles.Add(NewRole); - } - } - - if (Roles.IsValidIndex(0)) - { - PC->SwitchControlledRole(Roles[0]); - } } +void ALevelPlayerState::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(ALevelPlayerState, RoleRoster); + DOREPLIFETIME(ALevelPlayerState, ControlledRoleIndex); +} + +AActor* ALevelPlayerState::CreateRoleRoster(class APlayerController* PlayerController) +{ + if (!HasAuthority()) + { + return nullptr; + } + + UWorld* World = PlayerController->GetWorld(); + if (!World) + { + return nullptr; + } + + const FVector Location = FVector(GetSpawnLocation(), 10); + FActorSpawnParameters SpawnParameters; + + for (const auto RoleClass : RoleClasses) + { + SpawnParameters.Owner = PlayerController; + ABusyPlayerRole* NewRole = World->SpawnActor( + RoleClass, Location, + FRotator(), SpawnParameters + ); + RoleRoster.Add(NewRole); + } + + if (RoleRoster.IsValidIndex(0)) + { + ControlledRoleIndex = 0; + return RoleRoster[0]; + } + else + { + ControlledRoleIndex = -1; + return nullptr; + } + +} + + ABusyPlayerRole* ALevelPlayerState::GetControlledRole() const { - if (Roles.IsValidIndex(ControlledRoleIndex)) + if (RoleRoster.IsValidIndex(ControlledRoleIndex)) { - return Roles[ControlledRoleIndex]; + return RoleRoster[ControlledRoleIndex]; } else { @@ -53,3 +76,11 @@ FVector2D ALevelPlayerState::GetSpawnLocation()const { return FVector2D::ZeroVector; } + +void ALevelPlayerState::SetRoleRoster(const TArray& Roster) +{ + if (HasAuthority()) + { + RoleRoster = Roster; + } +} \ No newline at end of file diff --git a/Source/BusyRabbit/Private/Level/PaperTerrainMapActor.cpp b/Source/BusyRabbit/Private/Level/PaperTerrainMapActor.cpp deleted file mode 100644 index f938381..0000000 --- a/Source/BusyRabbit/Private/Level/PaperTerrainMapActor.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "Level/PaperTerrainMapActor.h" - -#include "Level/TerrainGenerator.h" -#include "Level/TerrainGeneratorBlueprintLibrary.h" -#include "Paper2D/Classes/PaperTileMapComponent.h" -#include "Paper2D/Classes/PaperTileMap.h" -#include "Paper2D/Classes/PaperTileLayer.h" -#include "Engine/Engine.h" -#include "UObject/ConstructorHelpers.h" - -/* 鐩搁偦鍥涙牸鍦板舰淇℃伅鏄犲皠鍒癟ileSet鐨勭储寮 - * 浠ュ乏涓娿佸彸涓娿佸乏涓嬨佸彸涓嬪湴褰㈠潡瀛樺湪涓1锛屼笉瀛樺湪涓0, 浠庡乏鍒板彸鏋勫缓涓涓4浣嶄簩杩涘埗鏁存暟 - * 鍋囪鍘熷TileSet涓紝0鍙风储寮曞乏涓娿佸彸涓娿佸彸涓嬩负绌, 瀵瑰簲浜岃繘鍒舵暣鏁颁负0x0010 - * 閭d箞TileSet鐨勮繖涓储寮曚笌鐩搁偦鏁版嵁瀵瑰簲鍏崇郴灏辨槸[0] -> 2 - * 涔熷氨鏄疍efaultNeighborDataToIdxMappings[2] = 0 - */ -const static int DefaultNeighborDataToIdxMappings[16] = { - 12, 13, 0, 3, 8, 1, 14, 5, 15, 4, 11, 2, 9, 10, 7, 6 -}; - -APaperTerrainMapActor::APaperTerrainMapActor() -{ - PrimaryActorTick.bCanEverTick = false; - - // 鍒涘缓鏍圭粍浠 - RootComponent = CreateDefaultSubobject(TEXT("RootComponent")); - - // 鍒涘缓TileMap缁勪欢 - TileMapComponent = CreateDefaultSubobject(TEXT("TileMapComponent")); - TileMapComponent->SetupAttachment(RootComponent); -} - -void APaperTerrainMapActor::BeginPlay() -{ - Super::BeginPlay(); - - if (bAutoGenerateOnBeginPlay) - { - GenerateTerrainMap(); - } -} - -void APaperTerrainMapActor::OnConstruction(const FTransform& Transform) -{ - Super::OnConstruction(Transform); - // 鍒濆鍖栧湴褰㈢敓鎴愬櫒 - InitializeGenerator(); - // 鍒濆鍖朤ileMap - InitializeTileMap(); - - if (bAutoGenerateOnConstruction) - { - GenerateTerrainMap(); - } -} - -void APaperTerrainMapActor::GenerateTerrainMap() -{ - if (!TerrainGenerator) - { - UE_LOG(LogTemp, Error, TEXT("TerrainGenerator is null!")); - return; - } - if (!TerrainTileSetConfigs) - { - UE_LOG(LogTemp, Error, TEXT("TerrainTileSetConfigs is null!")); - return; - } - - // 鐢熸垚鍦板舰鏁版嵁 - GeneratedTerrainData = TerrainGenerator->GenerateMap(MapWidth, MapHeight); - - // 搴旂敤鍒癟ileMap - ApplyTerrainToTileMap(GeneratedTerrainData); - - UE_LOG(LogTemp, Log, TEXT("Terrain map generated successfully! Size: %dx%d"), MapWidth, MapHeight); -} - -void APaperTerrainMapActor::ClearMap() -{ - if (!TileMapComponent || !TileMapComponent->TileMap) - { - return; - } - - // 娓呴櫎鎵鏈塗ile - 閫氳繃閲嶆柊鍒涘缓绌虹殑TileMap鏉ュ疄?? - if (TileMapComponent->TileMap) - { - UPaperTileMap* NewTileMap = NewObject(this); - NewTileMap->MapWidth = MapWidth; - NewTileMap->MapHeight = MapHeight; - NewTileMap->TileWidth = TileSize; - NewTileMap->TileHeight = TileSize; - - // 娣诲姞涓涓┖鍥惧眰 - UPaperTileLayer* NewLayer = NewObject(NewTileMap); - NewLayer->LayerName = FText::FromString("TerrainLayer"); - NewTileMap->TileLayers.Add(NewLayer); - - TileMapComponent->SetTileMap(NewTileMap); - } - - GeneratedTerrainData.Empty(); - UE_LOG(LogTemp, Log, TEXT("Map cleared!")); -} - -#if WITH_EDITOR -void APaperTerrainMapActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) -{ - Super::PostEditChangeProperty(PropertyChangedEvent); - - FName PropertyName = (PropertyChangedEvent.Property != nullptr) - ? PropertyChangedEvent.Property->GetFName() - : NAME_None; - - // 褰撳湴鍥惧昂瀵告垨Tile澶у皬鏀瑰彉鏃讹紝閲嶆柊鍒濆鍖朤ileMap - if (PropertyName == GET_MEMBER_NAME_CHECKED(APaperTerrainMapActor, MapWidth) || - PropertyName == GET_MEMBER_NAME_CHECKED(APaperTerrainMapActor, MapHeight) || - PropertyName == GET_MEMBER_NAME_CHECKED(APaperTerrainMapActor, TileSize) || - PropertyName == GET_MEMBER_NAME_CHECKED(APaperTerrainMapActor, TileSetDataAsset)) - - { - InitializeTileMap(); - GenerateTerrainMap(); - } -} -#endif - -void APaperTerrainMapActor::InitializeTileMap() -{ - if (!TileMapComponent) return; - - if (TileSetDataAsset) - { - TerrainTileSetConfigs = &TileSetDataAsset.Get()->TerrainTileSetConfigs; - } - else - { - TerrainTileSetConfigs = nullptr; - } - - // 鍒涘缓TileMap - UPaperTileMap *TileMap = NewObject(this); - - // 璁剧疆TileMap鍙傛暟 - TileMap->MapWidth = MapWidth; - TileMap->MapHeight = MapHeight; - TileMap->TileWidth = TileSize; - TileMap->TileHeight = TileSize; - - // 鍒涘缓鍥涘眰layer - for (int i = 0; i < 4; ++i) - { - UPaperTileLayer* NewLayer = NewObject(TileMap); - NewLayer->LayerName = FText::FromString( - FString::Format(TEXT("TerrainLayer{0}"), {FString::FromInt(i)}) - ); - NewLayer->ResizeMap(MapWidth, MapHeight); - TileMap->TileLayers.Add(NewLayer); - } - - TileMapComponent->SetTileMap(TileMap); - UE_LOG(LogTemp, Log, TEXT("TileMap initialized: %dx%d, TileSize: %d"), MapWidth, MapHeight, TileSize); -} - -void APaperTerrainMapActor::InitializeGenerator() -{ - // 鍒涘缓鍦板舰鐢熸垚鍣 - if (GeneratorClass.Get()) - { - TerrainGenerator = NewObject(this, GeneratorClass.Get()); - UTerrainGeneratorBlueprintLibrary::SetupExampleTerrainConfig(TerrainGenerator); - } - else - { - UE_LOG(LogTemp, Warning, TEXT("APaperTerrainMapActor::APaperTerrainMapActor, GeneratorClass is nullptr")); - } -} - -void APaperTerrainMapActor::ApplyTerrainToTileMap(const TArray& TerrainData) const -{ - if (!TileMapComponent || !TileMapComponent->TileMap || TerrainData.Num() != MapWidth * MapHeight) - { - UE_LOG(LogTemp, Error, TEXT("Cannot apply terrain data to TileMap!")); - return; - } - if (TileMapComponent->TileMap->TileLayers.Num() == 0) - { - UE_LOG(LogTemp, Error, TEXT("No tile layers in TileMap!")); - return; - } - - FGameplayTag TerrainTags[4]; - const int32 LimitedWidth = MapWidth - 1; - const int32 LimitedHeight = MapHeight - 1; - - for (int32 Y = 0; Y < LimitedHeight; Y++) - { - for (int32 X = 0; X < LimitedWidth; X++) - { - TerrainTags[0] = TerrainData[Y * MapWidth + X]; - TerrainTags[1] = TerrainData[Y * MapWidth + X + 1]; - TerrainTags[2] = TerrainData[(Y + 1) * MapWidth + X]; - TerrainTags[3] = TerrainData[(Y + 1) * MapWidth + X + 1]; - DrawTile(X, Y, TerrainTags); - } - } - UE_LOG(LogTemp, Log, TEXT("Terrain data applied to TileMap!")); -} - -static inline int32 GetNeighborInfo(const FGameplayTag& TargetTag, FGameplayTag TerrainTags[4]) -{ - int32 NeighborInfo = 0; - NeighborInfo += (TargetTag == TerrainTags[0] ? 1 : 0) << 3; - NeighborInfo += (TargetTag == TerrainTags[1] ? 1 : 0) << 2; - NeighborInfo += (TargetTag == TerrainTags[2] ? 1 : 0) << 1; - NeighborInfo += (TargetTag == TerrainTags[3] ? 1 : 0); - return NeighborInfo; -} - -static inline void GetSortedLayerDrawingInfo(FGameplayTag **LayerTerrainTags, int32 *LayerNeighborInfo, FGameplayTag TerrainTags[4]) -{ - // 杩斿洖0-3灞傛瘡灞傚簲璇ョ敾鍝鍦板舰鏍煎瓙锛屼互鍙婅繖涓牸瀛愮殑鍝褰㈢姸锛屽彲鑳介渶瑕佹帓搴 - LayerTerrainTags[0] = &TerrainTags[0]; - LayerTerrainTags[1] = &TerrainTags[1]; - LayerTerrainTags[2] = &TerrainTags[2]; - LayerTerrainTags[3] = &TerrainTags[3]; - LayerNeighborInfo[0] = GetNeighborInfo(TerrainTags[0], TerrainTags); - LayerNeighborInfo[1] = GetNeighborInfo(TerrainTags[1], TerrainTags); - LayerNeighborInfo[2] = GetNeighborInfo(TerrainTags[2], TerrainTags); - LayerNeighborInfo[3] = GetNeighborInfo(TerrainTags[3], TerrainTags); -} - -void APaperTerrainMapActor::DrawTile(const int32 X, const int32 Y, FGameplayTag TerrainTags[4])const -{ - int32 LayerNeighborInfo[4]; - FGameplayTag *LayerTerrainTags[4]; - UPaperTileMap* TileMap = TileMapComponent->TileMap; - GetSortedLayerDrawingInfo(LayerTerrainTags, LayerNeighborInfo, TerrainTags); - - for (int32 Index = 0; Index < 4; ++Index) - { - int32 TileIndex = 0; - FPaperTileInfo TileInfo; - - const FTerrainTileSetConfig *TileSetConfig = TerrainTileSetConfigs->Find(*LayerTerrainTags[Index]); - if (!TileSetConfig) - { - UE_LOG(LogTemp, Warning, TEXT("APaperTerrainMapActor::DrawTile TileSetConfig not found: %s"), *LayerTerrainTags[Index]->GetTagName().ToString()); - continue; - } - const int32 NeighborInfo = LayerNeighborInfo[Index]; - if (TileSetConfig->bNeedOverrideMappings) - { - if (NeighborInfo < TileSetConfig->NeighborDataToIdxMappings.Num()) - { - TileIndex = TileSetConfig->NeighborDataToIdxMappings[NeighborInfo]; - } - else - { - UE_LOG(LogTemp, Warning, TEXT("APaperTerrainMapActor::DrawTile Neighbor Data not find: %s, %d"), - *LayerTerrainTags[Index]->GetTagName().ToString(), NeighborInfo - ) - } - } - else - { - TileIndex = DefaultNeighborDataToIdxMappings[NeighborInfo]; - } - UPaperTileLayer* TerrainLayer = TileMap->TileLayers[Index]; - TileInfo.TileSet = TileSetConfig->TileSet; - TileInfo.PackedTileIndex = TileIndex; - TerrainLayer->SetCell(X, Y, TileInfo); - } -} diff --git a/Source/BusyRabbit/Private/Role/BusyRole.cpp b/Source/BusyRabbit/Private/Role/BusyRole.cpp index 8dee33b..d5348fc 100644 --- a/Source/BusyRabbit/Private/Role/BusyRole.cpp +++ b/Source/BusyRabbit/Private/Role/BusyRole.cpp @@ -10,7 +10,6 @@ #include "Role/BusyRoleMovement.h" #include "Role/RoleAnimation.h" #include "BusyGamePlayLibrary.h" -#include "Gas/BusyAbilitySystemComponent.h" #include "Components/InventoryComponent.h" #include "Core/PW_AbilitySystemComponent.h" #include "EnhancedInputComponent.h" @@ -71,7 +70,7 @@ void ABusyRole::SetRole(const FName& Name){ RoleName = Name; RoleConfig = *Row; - // 设置基本属性 + // 锟斤拷锟矫伙拷锟斤拷锟斤拷锟斤拷 if (RoleAttribute) { RoleAttribute->InitHealth(Row->Health); RoleAttribute->InitHunger(Row->Hunger); @@ -79,7 +78,7 @@ void ABusyRole::SetRole(const FName& Name){ RoleAttribute->RegisterCustomAttribute(); } - // 设置技能 + // 锟斤拷锟矫硷拷锟斤拷 for (UClass* AbilityClass : Row->DefaultAbilities) { if (AbilityClass) { RoleAbility->GiveAbility(FGameplayAbilitySpec(AbilityClass)); diff --git a/Source/BusyRabbit/Public/BusyGamePlayLibrary.h b/Source/BusyRabbit/Public/BusyGamePlayLibrary.h index ccab6e8..b003a29 100644 --- a/Source/BusyRabbit/Public/BusyGamePlayLibrary.h +++ b/Source/BusyRabbit/Public/BusyGamePlayLibrary.h @@ -33,7 +33,7 @@ public: static UClass* GetGameUIClass(const FString& ClassName); UFUNCTION(BlueprintPure) - static UWorld* K2_GetWorld(UObject* obj); + static UWorld* K2_GetWorld(const UObject* obj); UFUNCTION(BlueprintPure) static bool GetLevelBaseConfig(const FName& RowName, FBusyLevelBaseConfig& RowData); diff --git a/Source/BusyRabbit/Public/Gas/BusyAbilitySystemComponent.h b/Source/BusyRabbit/Public/Gas/BusyAbilitySystemComponent.h deleted file mode 100644 index 3eed078..0000000 --- a/Source/BusyRabbit/Public/Gas/BusyAbilitySystemComponent.h +++ /dev/null @@ -1,17 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "AbilitySystemComponent.h" -#include "BusyAbilitySystemComponent.generated.h" - -/** - * - */ -UCLASS() -class BUSYRABBIT_API UBusyAbilitySystemComponent : public UAbilitySystemComponent -{ - GENERATED_BODY() - -}; diff --git a/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h b/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h index d04d6fc..836f6be 100644 --- a/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h +++ b/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h @@ -1,6 +1,7 @@ 锘#pragma once #include "LuaPawn.h" #include "Level/Actor/Components/BusyPawnMovement.h" +#include "Level/Actor/Components/BusyAbilitySystemComponent.h" #include "BusyPawnBase.generated.h" @@ -8,6 +9,7 @@ class USphereComponent; class USpineBoneFollowerComponent; class USpineSkeletonRendererComponent; class USpineSkeletonAnimationComponent; +class UBusyPawnMovementComponent; UCLASS() @@ -22,7 +24,7 @@ public: virtual void UpdateMoveDirection_Implementation(const FVector2D& InDirection) override; virtual float GetSpeed_Implementation()const override; - + protected: UPROPERTY(EditDefaultsOnly) TObjectPtr RootScene; //鍦烘櫙鏍圭粍浠 @@ -44,7 +46,13 @@ protected: TObjectPtr SpineAnimationComponent; /*-------------------------------------------------------------------*/ - + /*-----------------------------GAS鐩稿叧--------------------------------*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly) + TObjectPtr AbilitySystemComponent; + + /*-------------------------------------------------------------------*/ + +public: /*-------------------------------绉诲姩缁勪欢------------------------------*/ UPROPERTY(EditAnywhere, BlueprintReadOnly) TObjectPtr MovementComponent; diff --git a/Source/BusyRabbit/Public/Level/Actor/Components/BusyAbilitySystemComponent.h b/Source/BusyRabbit/Public/Level/Actor/Components/BusyAbilitySystemComponent.h new file mode 100644 index 0000000..6d0cb43 --- /dev/null +++ b/Source/BusyRabbit/Public/Level/Actor/Components/BusyAbilitySystemComponent.h @@ -0,0 +1,17 @@ +锘#pragma once +#include "slua.h" +#include "AbilitySystemComponent.h" +#include "BusyAbilitySystemComponent.generated.h" + + +UCLASS() +class UBusyAbilitySystemComponent : public UAbilitySystemComponent, public ILuaOverriderInterface +{ + GENERATED_BODY() +public: + virtual FString GetLuaFilePath_Implementation() const override; + + +protected: + FString LuaFilePath; +}; diff --git a/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h b/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h index cfa8f1d..fb79272 100644 --- a/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h +++ b/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h @@ -37,9 +37,6 @@ public: FVector2D GetMoveDirection()const; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)override; -public: - UPROPERTY(EditAnywhere, BlueprintReadOnly) - float MoveSpeed = 400; protected: UPROPERTY(EditAnywhere, BlueprintReadOnly) diff --git a/Source/BusyRabbit/Public/Level/LevelPlayerController.h b/Source/BusyRabbit/Public/Level/LevelPlayerController.h index b1f4f75..2d59187 100644 --- a/Source/BusyRabbit/Public/Level/LevelPlayerController.h +++ b/Source/BusyRabbit/Public/Level/LevelPlayerController.h @@ -16,6 +16,12 @@ public: virtual void BeginPlay() override; +public: // RPC鐩稿叧 + UFUNCTION(Server, Reliable) + void SetRoleMoveTo(const FVector2D& Location); + void SetRoleMoveTo_Implementation(const FVector2D& Location); + + public: UFUNCTION(BlueprintCallable, Category = "Controller") bool GetCursorPosition(FVector2D& Position) const; @@ -24,7 +30,7 @@ public: void GetCursorHitResult(TArray& Results) const; UFUNCTION(BlueprintCallable, Category = "Controller") - void GetControlledRole() const; + ABusyPlayerRole* GetControlledRole() const; UFUNCTION(BlueprintCallable, Category = "Controller") void SwitchControlledRole(ABusyPlayerRole* Target); @@ -38,4 +44,7 @@ public: // 杈撳叆鐩稿叧 UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr TouchAction; + + UFUNCTION() + void OnTouch(const FInputActionValue& Value); }; diff --git a/Source/BusyRabbit/Public/Level/LevelPlayerState.h b/Source/BusyRabbit/Public/Level/LevelPlayerState.h index 835edb6..b6362b3 100644 --- a/Source/BusyRabbit/Public/Level/LevelPlayerState.h +++ b/Source/BusyRabbit/Public/Level/LevelPlayerState.h @@ -14,27 +14,47 @@ class ALevelPlayerState : public ALuaPlayerState GENERATED_BODY() public: virtual void BeginPlay() override; + + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; +public: // 缁欒摑鍥惧垵濮嬪寲鐨勬帴鍙 + UFUNCTION(BlueprintCallable) + AActor* CreateRoleRoster(class APlayerController* PlayerController); + - -public: +public: // 缁欒摑鍥剧殑Get鎺ュ彛 UFUNCTION(BlueprintCallable) ABusyPlayerRole* GetControlledRole() const; +public: // 缁欒摑鍥剧殑Set鎺ュ彛 + UFUNCTION(BlueprintCallable) + void SetRoleRoster(const TArray& Roster); + + +public: + + +public: + + + protected: virtual FVector2D GetSpawnLocation()const; public: - UPROPERTY(EditAnywhere) + UPROPERTY(EditAnywhere, BlueprintReadOnly) TArray> RoleClasses; protected: - UPROPERTY() + UPROPERTY(Replicated, BlueprintReadOnly) int ControlledRoleIndex = -1; - UPROPERTY() - TArray Roles; + UPROPERTY(Replicated, BlueprintReadOnly) + TArray RoleRoster; }; + + + diff --git a/Source/BusyRabbit/Public/Level/PaperTerrainMapActor.h b/Source/BusyRabbit/Public/Level/PaperTerrainMapActor.h deleted file mode 100644 index b855c79..0000000 --- a/Source/BusyRabbit/Public/Level/PaperTerrainMapActor.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "GameFramework/Actor.h" -#include "GameplayTagContainer.h" -#include "Generator/TerrainGeneratorBase.h" -#include "Map/TerrainLayerComponent.h" -#include "PaperTerrainMapActor.generated.h" - - - - - -UCLASS(Blueprintable, BlueprintType) -class BUSYRABBIT_API APaperTerrainMapActor : public AActor -{ - GENERATED_BODY() - -public: - APaperTerrainMapActor(); - -protected: - virtual void BeginPlay() override; - virtual void OnConstruction(const FTransform& Transform) override; - -public: - // 鐢熸垚鍦板浘(鍙湪钃濆浘涓皟鐢) - UFUNCTION(BlueprintCallable, Category = "Terrain Map") - void GenerateTerrainMap(); - - // 娓呴櫎褰撳墠鍦板浘 - UFUNCTION(BlueprintCallable, Category = "Terrain Map") - void ClearMap(); - -#if WITH_EDITOR - virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; -#endif - - -protected: // 鐢熸垚鍣ㄧ浉鍏 - // 鍦板舰鐢熸垚鍣ㄧ被 - - UPROPERTY(EditAnywhere, Category = "Terrain Map") - TSubclassOf GeneratorClass; - - // 鍦板舰鐢熸垚鍣ㄥ疄渚 - UPROPERTY() - TObjectPtr TerrainGenerator; - - // 鐢熸垚鐨勫湴褰㈡暟鎹 - TArray GeneratedTerrainData; - - -protected: // 鍦板浘閰嶇疆鐩稿叧 - // 鍦板浘瀹藉害 - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "1", ClampMax = "1024")) - int32 MapWidth = 16; - - // 鍦板浘楂樺害 - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "1", ClampMax = "1024")) - int32 MapHeight = 16; - - // 鐡︾墖澶у皬锛堝儚绱狅級 - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "1")) - int32 TileSize = 16; - -protected: // 鐡︾墖鐩稿叧 - TMap *TerrainTileSetConfigs; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", DisplayName="鐡︾墖璁剧疆") - TObjectPtr TileSetDataAsset; - - -protected: - // Paper2D鐡︾墖鍦板浘缁勪欢 - UPROPERTY(EditAnywhere, BlueprintReadWrite) - TObjectPtr TileMapComponent; - - // 鏄惁鍦ㄦ瀯閫犳椂鑷姩鐢熸垚鍦板浘 - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings") - bool bAutoGenerateOnConstruction = true; - - // 鏄惁鍦ㄥ紑濮嬫椂鑷姩鐢熸垚鍦板浘 - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings") - bool bAutoGenerateOnBeginPlay = true; -private: - // 鍒濆鍖朤ileMap缁勪欢 - void InitializeTileMap(); - - void InitializeGenerator(); - - // 搴旂敤鍦板舰鏁版嵁鍒癟ileMap - void ApplyTerrainToTileMap(const TArray& TerrainData)const; - - void DrawTile(const int32 X, const int32 Y, FGameplayTag TerrainTags[4])const; - -}; diff --git a/Tools/README.md b/Tools/README.md new file mode 100644 index 0000000..cfd8df0 --- /dev/null +++ b/Tools/README.md @@ -0,0 +1,125 @@ +# UE澶存枃浠惰В鏋愬伐鍏 + +杩欐槸涓涓敤浜庢壂鎻廢E澶存枃浠跺苟鐢熸垚slua鎻掍欢鐨別mmy-lua娉ㄨВ鐨凱ython宸ュ叿銆 + +## 鍔熻兘鐗规 + +- 鑷姩鎵弿鎸囧畾鐩綍涓嬬殑鎵鏈塙E澶存枃浠(.h) +- 瑙f瀽UCLASS銆乁STRUCT銆乁ENUM銆乁FUNCTION銆乁PROPERTY绛夊畯 +- 鐢熸垚绗﹀悎emmy-lua鏍囧噯鐨勭被鍨嬫敞瑙f枃浠(.d.lua) +- 鏀寔C++绫诲瀷鍒癓ua绫诲瀷鐨勮嚜鍔ㄨ浆鎹 +- 鏀寔閫掑綊鎵弿瀛愮洰褰 + +## 鏀寔鐨刄E瀹 + +- **UCLASS**: 瑙f瀽绫诲畾涔夛紝鍖呮嫭缁ф壙鍏崇郴 +- **USTRUCT**: 瑙f瀽缁撴瀯浣撳畾涔夊拰灞炴 +- **UENUM**: 瑙f瀽鏋氫妇瀹氫箟鍜屽 +- **UFUNCTION**: 瑙f瀽鍑芥暟澹版槑锛屽寘鎷弬鏁板拰杩斿洖鍊 +- **UPROPERTY**: 瑙f瀽灞炴у0鏄 +- **DECLARE_DYNAMIC_DELEGATE**: 瑙f瀽濮旀墭澹版槑 + +## 瀹夎鍜屼娇鐢 + +### 鍓嶇疆瑕佹眰 + +- Python 3.6+ +- 鏃犻渶棰濆渚濊禆 + +### 鍩烘湰鐢ㄦ硶 + +```bash +# 鎵弿Source鐩綍骞剁敓鎴愭敞瑙f枃浠跺埌Content/Lua/@types鐩綍 +python ue_header_parser.py Source/BusyRabbit -o Content/Lua/@types + +# 鎵弿褰撳墠鐩綍骞剁敓鎴愭敞瑙f枃浠跺埌鍚岀洰褰 +python ue_header_parser.py . + +# 閫掑綊鎵弿鏁翠釜椤圭洰 +python ue_header_parser.py Source --recursive -o Content/Lua/@types +``` + +### 鍛戒护琛屽弬鏁 + +- `directory`: 瑕佹壂鎻忕殑鐩綍璺緞锛堝繀闇锛 +- `-o, --output`: 杈撳嚭鐩綍璺緞锛堝彲閫夛紝榛樿涓烘簮鏂囦欢鍚岀洰褰曪級 +- `--recursive`: 閫掑綊鎵弿瀛愮洰褰曪紙鍙夛級 + +## 鐢熸垚鐨勬敞瑙f牸寮 + +宸ュ叿浼氭牴鎹甎E澶存枃浠剁敓鎴愬搴旂殑emmy-lua娉ㄨВ锛 + +### 绫绘敞瑙gず渚 +```lua +---@class UInventoryComponent : ULuaActorComponent +---@field Capacity integer +---@field InventoryList table + +---@param ItemID integer +---@param Count integer +---@return boolean +function UInventoryComponent:IsCanContain(ItemID, Count) end +``` + +### 缁撴瀯浣撴敞瑙gず渚 +```lua +---@class FInventoryGrid +---@field ItemID integer +---@field CurrentCount integer +---@field MaxCount integer +---@field Priority integer +local FInventoryGrid = {} +``` + +### 鏋氫妇娉ㄨВ绀轰緥 +```lua +---@enum EBusyRoleState +local EBusyRoleState = { + BonfireIdle = 0, + Searching = 1, + Picking = 2, + PickFinished = 3, + BackBonfire = 4 +} +``` + +### 濮旀墭娉ㄨВ绀轰緥 +```lua +---@class FOnInventoryChanged +---@field Call fun(ItemID: integer) +local FOnInventoryChanged = {} +``` + +## 绫诲瀷鏄犲皠 + +宸ュ叿浼氳嚜鍔ㄥ皢C++绫诲瀷鏄犲皠鍒癓ua绫诲瀷锛 + +| C++绫诲瀷 | Lua绫诲瀷 | +|---------|---------| +| int32, int64 | integer | +| float, double | number | +| bool | boolean | +| FString, FText, FName | string | +| void | nil | +| TArray, TMap, TSet | table | +| 鍏朵粬绫诲瀷 | any | + +## 娉ㄦ剰浜嬮」 + +1. 宸ュ叿浼氳烦杩囨病鏈塙E瀹忕殑鏅氬ご鏂囦欢 +2. 鐢熸垚鐨勬敞瑙f枃浠朵細淇濆瓨鍦╜.d.lua`鏂囦欢涓 +3. 濡傛灉杈撳嚭鐩綍涓嶅瓨鍦紝宸ュ叿浼氳嚜鍔ㄥ垱寤 +4. 宸ュ叿浼氬鐞嗙紪鐮侀棶棰橈紝浣嗗缓璁‘淇濆ご鏂囦欢浣跨敤UTF-8缂栫爜 +5. 瀵逛簬澶嶆潅鐨勬ā鏉跨被鍨嬶紝宸ュ叿浼氬皾璇曡В鏋愬唴閮ㄧ被鍨 + +## 鏁呴殰鎺掗櫎 + +濡傛灉閬囧埌瑙f瀽閿欒锛岃妫鏌ワ細 +- 澶存枃浠惰娉曟槸鍚︽纭 +- UE瀹忔牸寮忔槸鍚︾鍚堟爣鍑 +- 鏂囦欢缂栫爜鏄惁涓篣TF-8 +- 鏄惁鏈夎娉曢敊璇垨缂哄け鐨勫垎鍙 + +## 璐$尞 + +娆㈣繋鎻愪氦闂鍜屾敼杩涘缓璁紒 diff --git a/Tools/ue_header_parser.py b/Tools/ue_header_parser.py new file mode 100644 index 0000000..d51c74d --- /dev/null +++ b/Tools/ue_header_parser.py @@ -0,0 +1,402 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +UE澶存枃浠惰В鏋愬伐鍏 +鐢ㄤ簬鎵弿UE澶存枃浠跺苟鐢熸垚slua鎻掍欢鐨別mmy-lua娉ㄨВ +""" + +import os +import re +import argparse +from pathlib import Path +from typing import List, Dict, Set, Optional + +class UEHeaderParser: + def __init__(self): + self.classes = [] + self.structs = [] + self.enums = [] + self.delegates = [] + + def parse_header_file(self, file_path: str) -> Dict: + """瑙f瀽鍗曚釜澶存枃浠""" + with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: + content = f.read() + + result = { + 'classes': [], + 'structs': [], + 'enums': [], + 'delegates': [], + 'file_path': file_path + } + + # 瑙f瀽UCLASS + class_pattern = r'UCLASS\s*\([^)]*\)\s*\n\s*class\s+[A-Z_]+\s+(\w+)\s*:\s*public\s+(\w+)' + classes = re.findall(class_pattern, content) + for class_name, parent_class in classes: + result['classes'].append({ + 'name': class_name, + 'parent': parent_class, + 'functions': self._parse_functions(content, class_name), + 'properties': self._parse_properties(content, class_name) + }) + + # 瑙f瀽USTRUCT + struct_pattern = r'USTRUCT\s*\([^)]*\)\s*\n\s*struct\s+[A-Z_]+\s+(\w+)' + structs = re.findall(struct_pattern, content) + for struct_name in structs: + result['structs'].append({ + 'name': struct_name, + 'properties': self._parse_struct_properties(content, struct_name) + }) + + # 瑙f瀽USTRUCT (BlueprintType鍙樹綋) + struct_pattern2 = r'USTRUCT\s*\([^)]*\)\s*\n\s*struct\s+F(\w+)' + structs2 = re.findall(struct_pattern2, content) + for struct_name in structs2: + result['structs'].append({ + 'name': f'F{struct_name}', + 'properties': self._parse_struct_properties(content, f'F{struct_name}') + }) + + # 瑙f瀽UENUM + enum_pattern = r'UENUM\s*\([^)]*\)\s*\n\s*enum\s+class\s+(\w+)' + enums = re.findall(enum_pattern, content) + for enum_name in enums: + result['enums'].append({ + 'name': enum_name, + 'values': self._parse_enum_values(content, enum_name) + }) + + # 瑙f瀽濮旀墭 + delegate_pattern = r'DECLARE_DYNAMIC_(MULTICAST_)?DELEGATE(?:_\w+)?\s*\(\s*(\w+)\s*' + delegates = re.findall(delegate_pattern, content) + for is_multicast, delegate_name in delegates: + result['delegates'].append({ + 'name': delegate_name, + 'is_multicast': bool(is_multicast), + 'params': self._parse_delegate_params(content, delegate_name) + }) + + return result + + def _parse_functions(self, content: str, class_name: str) -> List[Dict]: + """瑙f瀽UFUNCTION""" + functions = [] + + # 鍖归厤UFUNCTION澹版槑 + func_pattern = r'UFUNCTION\s*\([^)]*\)\s*\n\s*(\w+)\s+(\w+)\s*\(([^)]*)\)' + matches = re.findall(func_pattern, content) + + for return_type, func_name, params in matches: + # 瑙f瀽鍙傛暟 + param_list = [] + if params.strip(): + for param in params.split(','): + param = param.strip() + if param: + # 绠鍗曠殑鍙傛暟瑙f瀽 + parts = param.split() + if len(parts) >= 2: + param_type = parts[-2] if len(parts) > 2 else parts[0] + param_name = parts[-1] + param_list.append({ + 'type': param_type, + 'name': param_name + }) + + functions.append({ + 'name': func_name, + 'return_type': return_type, + 'params': param_list + }) + + return functions + + def _parse_properties(self, content: str, class_name: str) -> List[Dict]: + """瑙f瀽UPROPERTY""" + properties = [] + + # 鍖归厤UPROPERTY澹版槑 + prop_pattern = r'UPROPERTY\s*\([^)]*\)\s*\n\s*(\w+(?:<[^>]*>)?)\s+(\w+);' + matches = re.findall(prop_pattern, content) + + for prop_type, prop_name in matches: + properties.append({ + 'name': prop_name, + 'type': prop_type + }) + + return properties + + def _parse_struct_properties(self, content: str, struct_name: str) -> List[Dict]: + """瑙f瀽缁撴瀯浣撳睘鎬""" + properties = [] + + # 鍦ㄧ粨鏋勪綋瀹氫箟鑼冨洿鍐呮煡鎵惧睘鎬 + struct_start = content.find(f'struct {struct_name}') + if struct_start == -1: + return properties + + # 鎵惧埌缁撴瀯浣撶粨鏉熶綅缃 + brace_count = 0 + struct_content = "" + for i in range(struct_start, len(content)): + char = content[i] + if char == '{': + brace_count += 1 + elif char == '}': + brace_count -= 1 + if brace_count == 0: + struct_content = content[struct_start:i+1] + break + + if not struct_content: + return properties + + # 鍦ㄧ粨鏋勪綋鍐呭涓煡鎵綰PROPERTY + prop_pattern = r'UPROPERTY\s*\([^)]*\)\s*\n\s*(\w+(?:<[^>]*>)?)\s+(\w+);' + matches = re.findall(prop_pattern, struct_content) + + for prop_type, prop_name in matches: + properties.append({ + 'name': prop_name, + 'type': prop_type + }) + + return properties + + def _parse_enum_values(self, content: str, enum_name: str) -> List[Dict]: + """瑙f瀽鏋氫妇鍊""" + values = [] + + # 鎵惧埌鏋氫妇瀹氫箟 + enum_start = content.find(f'enum class {enum_name}') + if enum_start == -1: + return values + + # 鎵惧埌鏋氫妇鍐呭 + brace_start = content.find('{', enum_start) + if brace_start == -1: + return values + + brace_end = content.find('}', brace_start) + if brace_end == -1: + return values + + enum_content = content[brace_start+1:brace_end] + + # 瑙f瀽鏋氫妇鍊 + value_pattern = r'(\w+)\s*(?:=\s*(\d+))?' + matches = re.findall(value_pattern, enum_content) + + current_value = 0 + for name, explicit_value in matches: + if explicit_value: + current_value = int(explicit_value) + + values.append({ + 'name': name, + 'value': current_value + }) + + current_value += 1 + + return values + + def _parse_delegate_params(self, content: str, delegate_name: str) -> List[Dict]: + """瑙f瀽濮旀墭鍙傛暟""" + params = [] + + # 鎵惧埌濮旀墭澹版槑 + delegate_pattern = f'DECLARE_DYNAMIC_(MULTICAST_)?DELEGATE(?:_\\w+)?\\s*\\(\\s*{delegate_name}' + match = re.search(delegate_pattern, content) + if not match: + return params + + # 鏌ユ壘鍙傛暟鍒楄〃 + param_start = content.find('(', match.end()) + if param_start == -1: + return params + + param_end = content.find(')', param_start) + if param_end == -1: + return params + + param_content = content[param_start+1:param_end] + + # 瑙f瀽鍙傛暟 + param_parts = [p.strip() for p in param_content.split(',') if p.strip()] + for i, param in enumerate(param_parts): + parts = param.split() + if len(parts) >= 2: + param_type = ' '.join(parts[:-1]) + param_name = parts[-1] + params.append({ + 'type': param_type, + 'name': param_name + }) + + return params + + def generate_emmy_lua_annotations(self, parsed_data: Dict) -> str: + """鐢熸垚emmy-lua娉ㄨВ""" + output = [] + + # 鏂囦欢澶存敞閲 + output.append(f'-- 鑷姩鐢熸垚鐨別mmy-lua娉ㄨВ鏂囦欢') + output.append(f'-- 婧愭枃浠: {parsed_data["file_path"]}') + output.append('') + + # 鐢熸垚鏋氫妇娉ㄨВ + for enum in parsed_data['enums']: + output.append(f'---@enum {enum["name"]}') + output.append(f'local {enum["name"]} = {{') + for value in enum['values']: + output.append(f' {value["name"]} = {value["value"]},') + output.append('}') + output.append('') + + # 鐢熸垚缁撴瀯浣撴敞瑙 + for struct in parsed_data['structs']: + output.append(f'---@class {struct["name"]}') + for prop in struct['properties']: + lua_type = self._cpp_to_lua_type(prop['type']) + output.append(f'---@field {prop["name"]} {lua_type}') + output.append(f'local {struct["name"]} = {{}}') + output.append('') + + # 鐢熸垚绫绘敞瑙 + for cls in parsed_data['classes']: + output.append(f'---@class {cls["name"]} : {cls["parent"]}') + + # 娣诲姞灞炴 + for prop in cls['properties']: + lua_type = self._cpp_to_lua_type(prop['type']) + output.append(f'---@field {prop["name"]} {lua_type}') + + # 娣诲姞鏂规硶 + for func in cls['functions']: + lua_return_type = self._cpp_to_lua_type(func['return_type']) + param_annotations = [] + for param in func['params']: + lua_param_type = self._cpp_to_lua_type(param['type']) + param_annotations.append(f'---@param {param["name"]} {lua_param_type}') + + if param_annotations: + output.extend(param_annotations) + output.append(f'---@return {lua_return_type}') + output.append(f'function {cls["name"]}:{func["name"]}({", ".join(p["name"] for p in func["params"])}) end') + output.append('') + + output.append('') + + # 鐢熸垚濮旀墭娉ㄨВ + for delegate in parsed_data['delegates']: + output.append(f'---@class {delegate["name"]}') + param_types = [] + for param in delegate['params']: + lua_type = self._cpp_to_lua_type(param['type']) + param_types.append(f'{param["name"]}: {lua_type}') + + if param_types: + output.append(f'---@field Call fun({", ".join(param_types)})') + else: + output.append('---@field Call fun()') + output.append(f'local {delegate["name"]} = {{}}') + output.append('') + + return '\n'.join(output) + + def _cpp_to_lua_type(self, cpp_type: str) -> str: + """灏咰++绫诲瀷杞崲涓篖ua绫诲瀷""" + type_mapping = { + 'int32': 'integer', + 'int64': 'integer', + 'float': 'number', + 'double': 'number', + 'bool': 'boolean', + 'FString': 'string', + 'FText': 'string', + 'FName': 'string', + 'void': 'nil', + 'TArray': 'table', + 'TMap': 'table', + 'TSet': 'table' + } + + # 澶勭悊妯℃澘绫诲瀷 + if '<' in cpp_type and '>' in cpp_type: + base_type = cpp_type.split('<')[0] + inner_type = cpp_type.split('<')[1].split('>')[0] + lua_inner_type = self._cpp_to_lua_type(inner_type) + return f'{type_mapping.get(base_type, "any")}<{lua_inner_type}>' + + return type_mapping.get(cpp_type, 'any') + + def scan_directory(self, directory: str, output_dir: str = None): + """鎵弿鐩綍鎴栧崟涓枃浠跺苟鐢熸垚娉ㄨВ鏂囦欢""" + header_files = [] + + if os.path.isfile(directory) and directory.endswith('.h'): + # 鍗曚釜鏂囦欢 + header_files = [directory] + elif os.path.isdir(directory): + # 鐩綍 + for root, dirs, files in os.walk(directory): + for file in files: + if file.endswith('.h'): + header_files.append(os.path.join(root, file)) + else: + print(f'閿欒: {directory} 涓嶆槸鏈夋晥鐨勬枃浠舵垨鐩綍') + return + + print(f'鎵惧埌 {len(header_files)} 涓ご鏂囦欢') + + for header_file in header_files: + try: + print(f'姝e湪瑙f瀽: {header_file}') + parsed_data = self.parse_header_file(header_file) + + if any([parsed_data['classes'], parsed_data['structs'], parsed_data['enums'], parsed_data['delegates']]): + annotations = self.generate_emmy_lua_annotations(parsed_data) + + # 纭畾杈撳嚭鏂囦欢璺緞 + if output_dir: + if os.path.isfile(directory): + # 鍗曚釜鏂囦欢鐨勬儏鍐 + output_file = os.path.join(output_dir, os.path.basename(header_file).replace('.h', '.d.lua')) + else: + # 鐩綍鐨勬儏鍐 + relative_path = os.path.relpath(header_file, directory) + output_file = os.path.join(output_dir, relative_path.replace('.h', '.d.lua')) + os.makedirs(os.path.dirname(output_file), exist_ok=True) + else: + output_file = header_file.replace('.h', '.d.lua') + + with open(output_file, 'w', encoding='utf-8') as f: + f.write(annotations) + + print(f'宸茬敓鎴: {output_file}') + + except Exception as e: + print(f'瑙f瀽鏂囦欢 {header_file} 鏃跺嚭閿: {e}') + +def main(): + parser = argparse.ArgumentParser(description='UE澶存枃浠惰В鏋愬伐鍏 - 鐢熸垚slua鎻掍欢鐨別mmy-lua娉ㄨВ') + parser.add_argument('directory', help='瑕佹壂鎻忕殑鐩綍璺緞') + parser.add_argument('-o', '--output', help='杈撳嚭鐩綍璺緞锛堥粯璁や负婧愭枃浠跺悓鐩綍锛') + parser.add_argument('--recursive', action='store_true', help='閫掑綊鎵弿瀛愮洰褰') + + args = parser.parse_args() + + if not os.path.exists(args.directory): + print(f'閿欒: 鐩綍 {args.directory} 涓嶅瓨鍦') + return + + parser = UEHeaderParser() + parser.scan_directory(args.directory, args.output) + +if __name__ == '__main__': + main() diff --git a/Tools/浣跨敤绀轰緥.md b/Tools/浣跨敤绀轰緥.md new file mode 100644 index 0000000..657a5a1 --- /dev/null +++ b/Tools/浣跨敤绀轰緥.md @@ -0,0 +1,104 @@ +# UE澶存枃浠惰В鏋愬伐鍏蜂娇鐢ㄧず渚 + +## 鍩烘湰鐢ㄦ硶 + +### 鎵弿鏁翠釜椤圭洰 +```bash +python Tools/ue_header_parser.py Source/BusyRabbit/Public -o Content/Lua/@types +``` + +### 鎵弿鐗瑰畾鐩綍 +```bash +# 鎵弿Components鐩綍 +python Tools/ue_header_parser.py Source/BusyRabbit/Public/Components -o Content/Lua/@types + +# 鎵弿Level鐩綍 +python Tools/ue_header_parser.py Source/BusyRabbit/Public/Level -o Content/Lua/@types +``` + +### 鎵弿鍗曚釜鏂囦欢 +```bash +# 鐩存帴鎸囧畾鏂囦欢璺緞锛堥渶瑕佸厛纭繚杈撳嚭鐩綍瀛樺湪锛 +python Tools/ue_header_parser.py Source/BusyRabbit/Public/Components/InventoryComponent.h -o Content/Lua/@types +``` + +## 鐢熸垚缁撴灉绀轰緥 + +### 杈撳叆澶存枃浠 (InventoryComponent.h) +```cpp +USTRUCT(BlueprintType) +struct FInventoryGrid { + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly, DisplayName = "鐗╁搧ID") + int32 ItemID; + + UPROPERTY(BlueprintReadWrite, DisplayName = "褰撳墠鐨勬暟閲") + int32 CurrentCount; + + UPROPERTY(BlueprintReadWrite, DisplayName = "鏈澶у爢鍙犻檺鍒") + int32 MaxCount; + + UPROPERTY(BlueprintReadWrite, DisplayName = "浼樺厛绾") + int32 Priority; +}; + +UCLASS() +class BUSYRABBIT_API UInventoryComponent : public ULuaActorComponent { + GENERATED_BODY() +public: + UFUNCTION(BlueprintCallable) + bool IsCanContain(int32 ItemID, int32 Count); + + // ... 鍏朵粬鍑芥暟鍜屽睘鎬 +}; +``` + +### 杈撳嚭娉ㄨВ鏂囦欢 (InventoryComponent.d.lua) +```lua +-- 鑷姩鐢熸垚鐨別mmy-lua娉ㄨВ鏂囦欢 +-- 婧愭枃浠: Source/BusyRabbit/Public/Components\InventoryComponent.h + +---@class FInventoryGrid +---@field ItemID integer +---@field CurrentCount integer +---@field MaxCount integer +---@field Priority integer +local FInventoryGrid = {} + +---@class UInventoryComponent : ULuaActorComponent +---@field Capacity integer +---@field InventoryList table +---@param ItemID integer +---@param Count integer +---@return boolean +function UInventoryComponent:IsCanContain(ItemID, Count) end + +-- ... 鍏朵粬鍑芥暟娉ㄨВ +``` + +## 闆嗘垚鍒板紑鍙戞祦绋 + +### 1. 瀹氭湡鐢熸垚娉ㄨВ +寤鸿鍦ㄦ瘡娆E澶存枃浠舵洿鏂板悗杩愯宸ュ叿閲嶆柊鐢熸垚娉ㄨВ銆 + +### 2. 鐗堟湰鎺у埗 +灏嗙敓鎴愮殑`.d.lua`鏂囦欢娣诲姞鍒扮増鏈帶鍒朵腑锛屾柟渚垮洟闃熷叡浜 + +### 3. IDE閰嶇疆 +纭繚IDE锛堝VSCode锛夎兘澶熻瘑鍒玚Content/Lua/@types`鐩綍涓殑娉ㄨВ鏂囦欢銆 + +## 娉ㄦ剰浜嬮」 + +1. **绫诲瀷鏄犲皠**: 宸ュ叿浼氳嚜鍔ㄥ皢C++绫诲瀷鏄犲皠鍒癓ua绫诲瀷 +2. **妯℃澘绫诲瀷**: 鏀寔`TArray`绛夋ā鏉跨被鍨嬬殑瑙f瀽 +3. **濮旀墭鏀寔**: 鑷姩鐢熸垚濮旀墭绫诲瀷鐨凜all鍑芥暟娉ㄨВ +4. **閿欒澶勭悊**: 宸ュ叿浼氳烦杩囨棤娉曡В鏋愮殑鏂囦欢骞剁户缁鐞嗗叾浠栨枃浠 + +## 鏁呴殰鎺掗櫎 + +濡傛灉閬囧埌闂锛岃妫鏌ワ細 +- 澶存枃浠惰娉曟槸鍚︽纭 +- UE瀹忔牸寮忔槸鍚︾鍚堟爣鍑 +- 杈撳嚭鐩綍鏉冮檺鏄惁瓒冲 +- Python鐗堟湰鏄惁涓3.6+