Getting very angry at Plugin Development

I’m new to C++ and Plugin Development. Trying to follow the guides is confusing but what gets me is that I can’t even do the first basic Copy and Paste instruction without running into issues.

Intellisense doesn’t work as it’s supposed to when I try to follow the instructions Letter for Letter.

Like, I tried to take the “UObjectPlugin” folder and copy into: Games/Plugins/UObjectPlugin so I have the following:

a31c68bb7b.png

But look at this, freaking red line minefield:

First step, ignore most of those - the built-in Intellisense in VS is garbage for this kind of stuff, and can’t handle all of the macros etc. It’s actually recommended that you turn intellisense off. Trust the non-intellisense errors you get when you compile, and nothing else.

Secondly, seriously consider buying Visual Assist - it’s like an improved Intellisense that is so much better, and can react to your changes faster. IIRC, even Epic uses it internally (I know we do!).

Lastly, try creating a plugin via this website, and look at some of the files generated. These plugins definitely work.

So I used the website, did some renaming and such and it accepted all the files. Now I try to add my own file called “RandomNumberGeneratorsLibrary.h” and try to do like did in his Victory Library. He wrote the following:


#pragma once

#include "VictoryAIBPLibrary.generated.h"

// BP Library for You
//
// Written by 

//note about UBlueprintFunctionLibrary
// This class is a base class for any function libraries exposed to blueprints.
// Methods in subclasses are expected to be static, and no methods should be added to the base class.

UCLASS()
class VICTORYAI_API UVictoryAIBPLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_UCLASS_BODY()
	
	/** SQUARED distanced between actors */
	UFUNCTION(BlueprintPure, Category = "VictoryAILibrary")
	static float Calculations__SquaredDistanceBetweenActors(AActor* Actor1,AActor* Actor2);
...
...
};

And I write:


#pragma once

UCLASS()
class RandomNumberGeneratorsLibrary : UBlueprintFunctionLibrary
{
	GENERATED_UCLASS_BODY()
		UFUNCTION(BlueprintPure, Category = "RandomNumberGeneratorsLibrary", meta = (FriendlyName = "Mersenne Twister"), CompactNodeTitle = "->", Keywords = "Mersenne Twister RNG Random Number Generator"))
		static FInt32] GenerateMersenneArray(FInt32* NumberOfEntries);
};

But get errors everywhere and it refuses to rebuild. And you want me to spend 279 dollars that I don’t have, to make the project work in the IDE that Epic choose to use themselves ._.

I know the IDE situation sucks - I’m just telling you what works. Grab a personal license for $99 if you can. I use mine at work and at home. Keep in mind that they use Visual Assist in this IDE.

In regards to your code, I’m not sure you can return a static array like that, or that you should be using FInt32 (it’s just int32). If you’re playing with arrays, return something like a TArray<int32> (similar to std::vector<int>).

The plugin tutorials are rubbish, I agree completely. Fortunately you don’t need them.

Tip #1: Try the built-in plugin creation wizard. I think it’s out of beta now so you should have it on by default, but if not you’ll likely need to enable it under plugins (since it’s a plugin too) then reload. Then you can use it to make your plugin skeleton and just start adding code to it. You can find it under the File menu once it’s enabled.

Tip #2: don’t use VS to create any files. Make the files yourself in windows in the proper location, name them correctly then drag them into the VS project explorer to get them into that. If you let VS make them, it’ll put them into your intermediate folder which is annoying and dangerous.

Tip #3: UE won’t put your class files in the right place for your plugin (it’s fine for actual code projects), but it’s still a good way to get the files created and populated with some sample code.

Definitely post your build errors as there’s a lot of gotchas about UE code projects that you need to learn. They’re not too bad though as everyone here can help you out with them as you come across them. One of the main ones that always gets me is the “missing module” problem. Just including header files isn’t enough, you need to put in your build.cs file for your plugin that it’s using the right module. If you already know about this then cool, otherwise there’s a specific way to solve this problem and get the info you need.

1 Like

Okay so, I used the Wizard and went through the tedious task of making folders in VS and drag and drop files in there. Here are all the Errors:

Most of them got solved by making it auto-solve the issue. It added


#include "..\Public\RandomNumberGeneratorsPlugin.h"

at the top of the file. Now I have the following errors:

And here is what that file looks like:

How odd. Check your PCH file as well, but that’s really strange. That include line you used also expects both the header and the cpp file to be in the same directory, so check that they are.

Structure is a funny thing in UE. I’ve followed a pretty strict setup so I don’t run into many problems, but I do use sub-folders and stuff without too much drama. Also make sure you have “#pragma once” at the top of pretty much every class and header file you make.

One thing about building: see that line that mentions -rocket? If you ever feel like you’re not getting all the errors or it’s masking them, run the UBT directly. Here’s an example from my cmd prompt:

justin@WORKSTATION /c/Program Files/Epic Games/4.8/Engine/Binaries/DotNET
$ UnrealBuildTool.exe MyProject Win64 DebugGame “C:\UnrealEngine\Projects\MyProject \MyProject .uproject” -rocket

So in this example I’m in /c/Program Files/Epic Games/4.8/Engine/Binaries/DotNET and I run the command from the error log above to replay the build. I often get better and more informative errors from doing this. (It looks a litle funny because I run it in GitBash, which emulates a Linux shell on Windows).

It’s probably best if you started posting your code in full so we can look over it.

1 Like

But that’s the thing, I didn’t make any code at all. I did exactly as you asked me to and generated a project to put in Visual Studio.

So I just did the following:


// Some copyright should be here...
#pragma once

#include "..\Public\RandomNumberGeneratorsPlugin.h"

// You should place include statements to your module's private header files here.  You only need to
// add includes for headers that are used in most of your module's source files though.

And it solved the issue. Now I just have those two command line errors.

I might not be following, but did the above error not specifically say to use forward slashes instead of backwards? ‘/’ instead of '' in your include paths. Might work :slight_smile:

The “access denied” error mostly happens to me if I try to rebuilt it while I’m also still running it - even if it’s just the UE crash reporter that’s still open.

The best way to run it is actually through the local debugger, not a rebuild. It’ll automatically build any changes for you and it makes tracing out errors easier, plus it preserves your output log after you crash out or quit. I don’t launch any other way now.

I can’t include <iostream> as it’s not in any of the Modules (???)

It should work.

Okay seems it didn’t matter any way. For what I need it to do I don’t need the <iostream> include even though it confuses the shat out of me as to why it didn’t work.
Now I have a file where some uses of NULL are underlined as undefined while others are not in the same file.


/**
 * C++ Mersenne Twister wrapper class written by
 * Jason R. Blevins <jrblevin@sdf.lonestar.org> on July 24, 2006.
 * Based on the original MT19937 C code by
 * Takuji Nishimura and Makoto Matsumoto.
 */

/* 
   A C-program for MT19937, with initialization improved 2002/1/26.
   Coded by Takuji Nishimura and Makoto Matsumoto.

   Before using, initialize the state by using init_genrand(seed)  
   or init_by_array(init_key, key_length).

   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
   All rights reserved.                          

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.

     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.

     3. The names of its contributors may not be used to endorse or promote 
        products derived from this software without specific prior written 
        permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

   Any feedback is very welcome.
   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/

#include <cassert>

#include "mt.h"

/**
 * Constructor
 */
MersenneTwister::MersenneTwister(void):
    mt_(new unsigned long[N]), mti_(N+1),
    init_key_(NULL), key_length_(0), s_(0),
    seeded_by_array_(false), seeded_by_int_(false)
{
    unsigned long init[4] = { 0x123, 0x234, 0x345, 0x456 };
    unsigned long length = 4;
    init_by_array(init, length);
}

/**
 * Destructor
 */
MersenneTwister::~MersenneTwister(void)
{
    assert(mt_ != NULL);
    delete] mt_;
    mt_ = NULL;

    assert(init_key_ != NULL);
    delete] init_key_;
    init_key_ = NULL;
}

/**
 * Initializes the Mersenne Twister with a seed.
 *
 * \param s seed
 */
void MersenneTwister::init_genrand(unsigned long s)
{
    mt_[0]= s & 0xffffffffUL;
    for (mti_=1; mti_<N; mti_++) {
        mt_[mti_] = 
	    (1812433253UL * (mt_[mti_-1] ^ (mt_[mti_-1] >> 30)) + mti_); 
        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
        /* In the previous versions, MSBs of the seed affect   */
        /* only MSBs of the array mt_].                        */
        /* 2002/01/09 modified by Makoto Matsumoto             */
        mt_[mti_] &= 0xffffffffUL;
        /* for >32 bit machines */
    }
    // Store the seed
    s_ = s;
    seeded_by_array_ = false;
    seeded_by_int_ = true;
}

/**
 * Seed the Mersenne Twister using an array.
 *
 * \param init_key an array for initializing keys
 * \param key_length the length of \a init_key
 */
void MersenneTwister::init_by_array(unsigned long* init_key, int key_length)
{
    // Store the key array
    int i, j, k;
    init_genrand(19650218UL);
    i=1; j=0;
    k = (N>key_length ? N : key_length);
    for (; k; k--) {
        mt_* = (mt_* ^ ((mt_[i-1] ^ (mt_[i-1] >> 30)) * 1664525UL))
          + init_key[j] + j; /* non linear */
        mt_* &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
        i++; j++;
        if (i>=N) { mt_[0] = mt_[N-1]; i=1; }
        if (j>=key_length) j=0;
    }
    for (k=N-1; k; k--) {
        mt_* = (mt_* ^ ((mt_[i-1] ^ (mt_[i-1] >> 30)) * 1566083941UL))
          - i; /* non linear */
        mt_* &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
        i++;
        if (i>=N) { mt_[0] = mt_[N-1]; i=1; }
    }

    mt_[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ 

    // Store the seed
    if (init_key_ != NULL) {
        delete] init_key_;
    }
    init_key_ = new unsigned long[key_length];
    for (int k = 0; k < key_length; k++) {
        init_key_[k] = init_key[k];
    }
    key_length_ = key_length;
    seeded_by_int_ = false;
    seeded_by_array_ = true;
}

/**
 * Generates a random number on [0,0xffffffff]-interval
 *
 * \return random number on [0, 0xffffffff]
 */
unsigned long MersenneTwister::genrand_int32(void)
{
    unsigned long y;
    static unsigned long mag01[2]={0x0UL, MATRIX_A};
    /* mag01[x] = x * MATRIX_A  for x=0,1 */

    if (mti_ >= N) { /* generate N words at one time */
        int kk;

        if (mti_ == N+1)   /* if init_genrand() has not been called, */
            init_genrand(5489UL); /* a default initial seed is used */

        for (kk=0;kk<N-M;kk++) {
            y = (mt_[kk]&UPPER_MASK)|(mt_[kk+1]&LOWER_MASK);
            mt_[kk] = mt_[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
        }
        for (;kk<N-1;kk++) {
            y = (mt_[kk]&UPPER_MASK)|(mt_[kk+1]&LOWER_MASK);
            mt_[kk] = mt_[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
        }
        y = (mt_[N-1]&UPPER_MASK)|(mt_[0]&LOWER_MASK);
        mt_[N-1] = mt_[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];

        mti_ = 0;
    }
  
    y = mt_[mti_++];

    /* Tempering */
    y ^= (y >> 11);
    y ^= (y << 7) & 0x9d2c5680UL;
    y ^= (y << 15) & 0xefc60000UL;
    y ^= (y >> 18);

    return y;
}

/**
 * Generates a random integer on [0,0x7fffffff].
 *
 * \return a random integer on [0,0x7fffffff]
 */
long MersenneTwister::genrand_int31(void)
{
    return (long)(genrand_int32()>>1);
}

/**
 * Generates a random real number on [0,1].
 *
 * \return a random real number on [0,1]
 */
double MersenneTwister::genrand_real1(void)
{
    return genrand_int32()*(1.0/4294967295.0); 
    /* divided by 2^32-1 */ 
}

/**
 * Generates a random real number on 0,1).
 *
 * \return a random real number on 0,1)
 */
double MersenneTwister::genrand_real2(void)
{
    return genrand_int32()*(1.0/4294967296.0); 
    /* divided by 2^32 */
}

/**
 * Generates a random real number on (0,1).
 *
 * \return a random real number on (0,1)
 */
double MersenneTwister::genrand_real3(void)
{
    return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); 
    /* divided by 2^32 */
}

/**
 * Generates a random real number on 0,1) with 53-bit precision.
 *
 * \return a random 53-bit real number on 0,1)
 */
double MersenneTwister::genrand_res53(void)
{ 
    unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; 
    return(a*67108864.0+b)*(1.0/9007199254740992.0); 
} 
/* These real versions are due to Isaku Wada, 2002/01/09 added */

NULL is case sensitive, so check that it’s all uppercase. Want to paste your entire code file so I can try it in my VS?

It’s in my post above. It has a header too:


/**
 * mt.h: Mersenne Twister header file
 *
 * Jason R. Blevins <jrblevin@sdf.lonestar.org>
 * Durham, March  7, 2007
 */
#pragma once
#ifndef METRICS_MT_H
#define METRICS_MT_H

/**
 * Mersenne Twister.
 *
 * M. Matsumoto and T. Nishimura, "Mersenne Twister: A
 * 623-dimensionally equidistributed uniform pseudorandom number
 * generator", ACM Trans. on Modeling and Computer Simulation Vol. 8,
 * No. 1, January pp.3-30 (1998).
 *
 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html.
 */
class MersenneTwister
{
public:
    MersenneTwister(void);
    ~MersenneTwister(void);

    double random(void) { return genrand_real1(); }
    void print(void);

    void init_genrand(unsigned long s);
    void init_by_array(unsigned long* init_key, int key_length);

    unsigned long genrand_int32(void);
    long genrand_int31(void);
    double genrand_real1(void);
    double genrand_real2(void);
    double genrand_real3(void);
    double genrand_res53(void);

private:
    static const int N                    = 624;
    static const int M                    = 397;
    // constant vector a
    static const unsigned long MATRIX_A   = 0x9908b0dfUL;
    // most significant w-r bits
    static const unsigned long UPPER_MASK = 0x80000000UL;
    // least significant r bits
    static const unsigned long LOWER_MASK = 0x7fffffffUL;

    unsigned long* mt_;                  // the state vector
    int mti_;                            // mti == N+1 means mt not initialized

    unsigned long* init_key_;            // Storage for the seed vector
    int key_length_;                     // Seed vector length
    unsigned long s_;                    // Seed integer
    bool seeded_by_array_;               // Seeded by an array
    bool seeded_by_int_;                 // Seeded by an integer
};

#endif // METRICS_MT_H


But no problems are reported in that file.

You can’t use NULL for a null pointer. Use nullptr instead.

Unless you’re planning on building on some funny platforms, #pragma once should remove the need to do the #ifndef METRICS_MT_H block.

So you also don’t have a precompiled header file. I’m not 100% on exactly how they work, but it’ll both speed up your builds and the UBT will throw an error without one. It must be your first include on every header file.

I suspect VisualAssist would make your life a ton easier. There’s a demo you can try out - see if it helps. I was lucky enough that work bought me a copy, but apparently it’s bog standard to own it in the C++ world.

I believe the precompiled header should be included at the start of the .cpp file, not the header.

Okay, now I can’t include “<cassert>” because:

Error 1 error : The first include statement in source file ‘E:\UE4 Projects\RandGenLib\Plugins\RandomNumberGeneratorsPlugin\Source\RandomNumberGeneratorsPlugin\Private\MersenneTwister\mt.cpp’ is trying to include the file ‘cassert’ as the precompiled header, but that file could not be located in any of the module’s include search path.

Yep, see what we said about needing a precomputed header file. The plugin wizard created one for you - just use that. Basically put any headers you’re using into it and then include that file.