您的位置:首页 > 新闻动态 > UE4

UE4插件,展示如何使用第三方库制作UE4插件

来源: 2018/3/20      点击:

如何调用第三方封装好的库制作UE4插件? 


MyEEGPlugin.uplugin

{

    "FileVersion": 3,

    "Version": 1,

    "VersionName": "1.0",

    "FriendlyName": "MyEEGPlugin",

    "Description": "",

    "Category": "Other",

    "CreatedBy": "",

    "CreatedByURL": "",

    "DocsURL": "",

    "MarketplaceURL": "",

    "SupportURL": "",

    "CanContainContent": true,

    "IsBetaVersion": false,

    "Installed": false,

    "Modules": [

        {

            "Name": "MyEEGPlugin",

            "Type": "Runtime",

            "LoadingPhase": "Default"

        }

    ]

}

MyEEGPlugin.Build.cs

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.


using UnrealBuildTool;

using System.IO;


public class MyEEGPlugin : ModuleRules

{

    public MyEEGPlugin(TargetInfo Target)

    {


        PublicIncludePaths.AddRange(

            new string[] {

                "MyEEGPlugin/Public"

                // ... add public include paths required here ...

            }

            );



        PrivateIncludePaths.AddRange(

            new string[] {

                "MyEEGPlugin/Private",

                // ... add other private include paths required here ...

            }

            );



        PublicDependencyModuleNames.AddRange(

            new string[]

            {

                "Core", "CoreUObject", "Engine", "InputCore", "Projects"

                // ... add other public dependencies that you statically link with here ...

            }

            );



        PrivateDependencyModuleNames.AddRange(

            new string[]

            {

                // ... add private dependencies that you statically link with here ...   

            }

            );



        DynamicallyLoadedModuleNames.AddRange(

            new string[]

            {

                // ... add any modules that your module loads dynamically here ...

            }

            );


        LoadThinkGearLib(Target);//添加第三方库

        //LoadAlgoSdkDll(Target);//添加第三方库

    }


    private string ThirdPartyPath

    {

        get

        {

            return Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty/"));

        }

    }

    public void LoadThinkGearLib(TargetInfo Target)

    {

        if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))

        {

            string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "64" : "";

            string LibrariesPath = Path.Combine(ThirdPartyPath, "ThinkGear", "lib");

            //test your path

            System.Console.WriteLine("... LibrariesPath -> " + LibrariesPath);


            PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "ThinkGear", "include"));

            PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "thinkgear" + PlatformString + ".lib"));

        }


        //Definitions.Add(string.Format("MY_DEFINE={0}", 0));

    }


    public void LoadAlgoSdkDll(TargetInfo Target)

    {

        if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))

        {

            string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "64" : "";

            string DllPath = Path.Combine(ThirdPartyPath, "bin", "AlgoSdkDll" + PlatformString + ".dll");


            PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "EEGAlgoSDK", "include"));

            PublicDelayLoadDLLs.Add(DllPath);

            //RuntimeDependencies.Add(new RuntimeDependency(DllPath));

        }

    }


}

MyEEGPlugin.h

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.


#pragma once


#include "ModuleManager.h"


class FMyEEGPluginModule : public IModuleInterface

{

public:


    /** IModuleInterface implementation */

    virtual void StartupModule() override;

    virtual void ShutdownModule() override;


private:

    /** Handle to the test dll we will load */

    void*    ExampleLibraryHandle;

};

MyEEGPlugin.cpp

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.


#include "MyEEGPlugin.h"

#include "Core.h"

#include "ModuleManager.h"

#include "IPluginManager.h"

//#include "ExampleLibrary.h"


#define LOCTEXT_NAMESPACE "FMyEEGPluginModule"


void FMyEEGPluginModule::StartupModule()

{

    // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module


    // Get the base directory of this plugin

    FString BaseDir = IPluginManager::Get().FindPlugin("MyEEGPlugin")->GetBaseDir();


    // Add on the relative location of the third party dll and load it

    FString LibraryPath;

#if PLATFORM_WINDOWS

    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/MyEEGPluginLibrary/Win64/ExampleLibrary.dll"));

#elif PLATFORM_MAC

    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/MyEEGPluginLibrary/Mac/Release/libExampleLibrary.dylib"));

#endif // PLATFORM_WINDOWS


    ExampleLibraryHandle = !LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;


    if (ExampleLibraryHandle)

    {

        // Call the test function in the third party library that opens a message box

        //ExampleLibraryFunction();

    }

    else

    {

        //FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load example third party library"));

    }

}


void FMyEEGPluginModule::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.


    // Free the dll handle

    FPlatformProcess::FreeDllHandle(ExampleLibraryHandle);

    ExampleLibraryHandle = nullptr;

}


#undef LOCTEXT_NAMESPACE


IMPLEMENT_MODULE(FMyEEGPluginModule, MyEEGPlugin)

MyEEGReceiver.h

// Fill out your copyright notice in the Description page of Project Settings.


#pragma once

#include "Engine.h"

#include "GameFramework/Actor.h"

#include "MyEEGReceiver.generated.h"


UCLASS()

class AMyEEGReceiver : public AActor

{

    GENERATED_BODY()


public:   

    // Sets default values for this actor‘s properties

    AMyEEGReceiver();


protected:

    // Called when the game starts or when spawned

    virtual void BeginPlay() override;

    int rawDataIndex;

    int lerpDataIndex;

    float totalAngle;


    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float v;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float s;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float a;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    TArrayrawAttentions;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    TArrayrawMeditations;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    TArraylerpAttentions;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    TArraylerpMeditations;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float attention1;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float attention2;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float meditation1;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    float meditation2;

public:   

    // Called every frame

    virtual void Tick(float DeltaTime) override;


    /** Called whenever this actor is being removed from a level */

    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;



    UFUNCTION(BlueprintImplementableEvent, Category = "EEG")

    void BPEvent_GetNewAttention(float newAttention);


    UFUNCTION(BlueprintCallable, Category = "EEG")

    void IndexFunc();


    UFUNCTION(BlueprintCallable, Category = "EEG")

    void ComputeNewPos(float factor, UStaticMeshComponent* cube, float DeltaTime, float scaleFactorAtten=1, float scaleFactorMedi = 1, bool debug=false);


    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    int32 LatestMeditation;        //*新放松度

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    int32 LatestAttention;        //*新专注度


    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")

    bool ShowOnScreenDebugMessages;


    FORCEINLINE void ScreenMsg(const FString& Msg)

    {

        if (!ShowOnScreenDebugMessages) return;

        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, *Msg);

    }

    FORCEINLINE void ScreenMsg(const FString& Msg, const int32 Value)

    {

        if (!ShowOnScreenDebugMessages) return;

        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %d"), *Msg, Value));

    }

};

MyEEGReceiver.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyEEGPlugin.h"

#include "MyEEGReceiver.h"

#include "thinkgear.h"


#define NUM 3

// Sets default values

AMyEEGReceiver::AMyEEGReceiver()

{

     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don‘t need it.

    PrimaryActorTick.bCanEverTick = true;


    ShowOnScreenDebugMessages = true;

    v = 0; a = 1; s = 0;

    rawDataIndex = 0;

    lerpDataIndex = 0;

    rawAttentions.Init(0, NUM);

    rawMeditations.Init(0, NUM);

    totalAngle = 0;

}


long raw_data_count = 0;

short *raw_data = NULL;

bool bRunning = false;

bool bInited = false;

char *comPortName = NULL;

int   dllVersion = 0;

int   connectionId = -1;

int   packetsRead = 0;

int   errCode = 0;

bool bConnectedHeadset = false;



// Called when the game starts or when spawned

void AMyEEGReceiver::BeginPlay()

{

    Super::BeginPlay();


    /* Print driver version number */

    dllVersion = TG_GetVersion();

    ScreenMsg("ThinkGear DLL version:",dllVersion);

    //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ThinkGear DLL version: %d\n"), dllVersion));

    /* Get a connection ID handle to ThinkGear */

    connectionId = TG_GetNewConnectionId();

    if (connectionId < 0) {

        ScreenMsg("Failed to new connection ID");

    }

    else {

        /* Attempt to connect the connection ID handle to serial port "COM5" */

        /* NOTE: On Windows, COM10 and higher must be preceded by \\.\, as in

        *       "\\\\.\\COM12" (must escape backslashes in strings).  COM9

        *       and lower do not require the \\.\, but are allowed to include

        *       them.  On Mac OS X, COM ports are named like

        *       "/dev/tty.MindSet-DevB-1".

        */

        comPortName = "\\\\.\\COM6";

        errCode = TG_Connect(connectionId,

            comPortName,

            TG_BAUD_57600,

            TG_STREAM_PACKETS);

        if (errCode < 0)

        {

            ScreenMsg("TG_Connect() failed", errCode);

        }

        else

        {

            ScreenMsg("TG_Connect OK",connectionId);

        }

    }


}


// Called every frame

void AMyEEGReceiver::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);


    v = v + a*DeltaTime;

    s += v*DeltaTime;

    /* Read all currently available Packets, one at a time... */

    do {

        /* Read a single Packet from the connection */

        packetsRead = TG_ReadPackets(connectionId, 1);


        /* If TG_ReadPackets() was able to read a Packet of data... */

        if (packetsRead == 1) {

            //ScreenMsg("TG_ReadPackets");

            /* If the Packet containted a new raw wave value... */

            if (TG_GetValueStatus(connectionId, TG_DATA_RAW) != 0) {

                int rawData = (int)TG_GetValue(connectionId, TG_DATA_RAW);

                //ScreenMsg("TG_DATA_RAW",rawData);

            } /* end "If Packet contained a raw wave value..." */


            if (TG_GetValueStatus(connectionId, TG_DATA_POOR_SIGNAL) != 0) {

                int ps=TG_GetValue(connectionId, TG_DATA_POOR_SIGNAL);

                //ScreenMsg("TG_DATA_POOR_SIGNAL",ps);

            }


            if (TG_GetValueStatus(connectionId, TG_DATA_MEDITATION) != 0) {

                float medi = TG_GetValue(connectionId, TG_DATA_MEDITATION);

                LatestMeditation = (int32)medi;

                //ScreenMsg("TG_DATA_MEDITATION", LatestMeditation);

                rawMeditations[rawDataIndex] = medi;

                float total = 0;

                for (int i = 0; i < NUM; i++)

                    total += rawMeditations[i];

                float avg_medi = total / NUM;

                lerpMeditations.Add(avg_medi);

            }


            if (TG_GetValueStatus(connectionId, TG_DATA_ATTENTION) != 0) {

                float atten = TG_GetValue(connectionId, TG_DATA_ATTENTION);

                LatestAttention = (int32)atten;

                rawAttentions[rawDataIndex] = atten;

                float total = 0;

                for (int i = 0; i < NUM; i++)

                    total += rawAttentions[i];

                float avg_atten = total / NUM;

                lerpAttentions.Add(avg_atten);


                rawDataIndex++;

                if (rawDataIndex == NUM)

                {

                    rawDataIndex = 0;

                }


                ScreenMsg("avg_atten", avg_atten);

                //BPEvent_GetNewAttention(TG_GetValue(connectionId, TG_DATA_ATTENTION));

                //float atten=TG_GetValue(connectionId, TG_DATA_ATTENTION);

                //float delta = atten - s;

                //a = delta;

                ScreenMsg("TG_DATA_ATTENTION", LatestAttention);

                //ScreenMsg("delta", delta);

                //ScreenMsg("s", s);

            }


        } /* end "If TG_ReadPackets() was able to read a Packet..." */


    } while (packetsRead > 0); /* Keep looping until all Packets read */

}


void AMyEEGReceiver::EndPlay(const EEndPlayReason::Type EndPlayReason)

{

    Super::EndPlay(EndPlayReason);


    /* Clean up */

    TG_FreeConnection(connectionId);

}


void AMyEEGReceiver::IndexFunc()

{

    int lerpNum = lerpAttentions.Num();

    if (lerpNum ==0)

        return;

    int idx1 = lerpDataIndex - 1;

    int idx2 = lerpDataIndex;

    idx1 = FMath::Max(idx1,0);

    idx2 = FMath::Min(idx2, lerpNum-1);

    attention1 = lerpAttentions[idx1];

    attention2 = lerpAttentions[idx2];

    meditation1 = lerpMeditations[idx1];

    meditation2 = lerpMeditations[idx2];

    if (lerpDataIndex < lerpNum-1)

    {

        lerpDataIndex++;

    }

}


void AMyEEGReceiver::ComputeNewPos(float factor, UStaticMeshComponent* cube, float DeltaTime,

    float scaleFactorAtten/*=1*/, float scaleFactorMedi/* = 1*/, bool debug/* = false*/)

{

    float tmpAtten = FMath::Lerp(attention1, attention2, factor);

    float tmpMedit = FMath::Lerp(meditation1, meditation2, factor);

    static float testTime = 0;

    if (debug)

    {

        tmpMedit = 50 + sin(testTime) * 50;

        tmpAtten = 50 + sin(testTime) * 50; testTime += DeltaTime;

    }

    float s0 = tmpMedit*DeltaTime*scaleFactorMedi;

    FVector oldPos = cube->GetComponentLocation();

    float angle = FMath::Atan(s0 / (oldPos.Size()));

    FVector normalVec = oldPos.GetSafeNormal();

    FVector newPos = normalVec*(10000 + tmpAtten*scaleFactorAtten);

    cube->SetWorldLocation(newPos.RotateAngleAxis(FMath::RadiansToDegrees(angle),FVector(0,1,0)));

    FRotator Rotator = FRotator::ZeroRotator;

    totalAngle += FMath::RadiansToDegrees(angle);

    Rotator.Add(-totalAngle, 0, 0);

    if (totalAngle >= 360)

    {

        totalAngle = 0;

    }

    cube->SetWorldRotation(Rotator);

    UTextRenderComponent* text = dynamic_cast(cube->GetChildComponent(0));

    if (text)

    {

        FString t1 = FString::FromInt(tmpAtten);

        FString t2 = FString::FromInt(tmpMedit);

        FString t3 = FString::FromInt(totalAngle);

        FString tmp(", ");

        tmp = t1 + tmp + t2;

        text->SetText(FText::FromString(tmp));

    }

}