x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

hot reload not working, possibly a compile issue?

I have been having issues with compiling and hot reloading. would someone be able to review my code to see if there is a reason it wont compile properly.

My best guess at this point is that despite my code compiling successfully, it doesn't actually compile properly for editor use. I think it might have something to do with using a class called Room as a C++ object, but I honestly have no idea. This code worked perfectly fine as-is 2 days ago but since yesterday I have been unable to compile unless I remove my Room class and any code requiring it in MapLayout (keeping in mind that this code DID work 2 days ago with no changes made since and then just stopped all of a sudden with no changes when I reopened my project yesterday).

here is another post I have made trying other fixes for similar-ish issues.

code and resources can be found here, but I will also include the code below

MapLayout.h

 #pragma once
 #include "CoreMinimal.h"
 #include "Engine.h"
 #include "GameFramework/Actor.h"
 #include "Components/InstancedStaticMeshComponent.h"
 #include <vector>
 #include "Room.h"
 #include "MapLayout.generated.h"

 UCLASS()
 class MAPGEN_API AMapLayout : public AActor {
 GENERATED_BODY()

 public:
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map")
     int MAIN_CHAIN_MIN = 5;
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     int MAIN_CHAIN_RAND = 4;
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     int EXT_LENGTH = 3;

 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     int ROOM_SIZE = 200;
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     int TILE_SIZE = 10;
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     float DOOR_WIDTH = 1.5f;

 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     UStaticMesh* FloorMesh;
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     UStaticMesh* DoorMesh;
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Generation")
     UStaticMesh* WallMesh;
 UPROPERTY()
     UInstancedStaticMeshComponent* floor_ISMC;
 UPROPERTY()
     UInstancedStaticMeshComponent* door_ISMC;
 UPROPERTY()
     UInstancedStaticMeshComponent* wall_ISMC;

 AMapLayout();

 protected:
 // Called when the game starts or when spawned
 virtual void BeginPlay() override;
 };


MapLayout.cpp

 #include "MapLayout.h"

 std::vector<Room*> rooms;                            // stores a pointer to each room in the map

 /**
  * Checks if a there is a room that already exists at a given coordinate
  */
 bool validLoc(int x, int y) {
     for (int i = 0; i < rooms.size(); i++)
         if ((*rooms[i]).posEquals(x, y))
             return false;
     return true;
 }

 /**
 * Generates a new room in the main chain of rooms
 */
 Room* genNextRoom() {
     Room *last = rooms[rooms.size() - 1];        // get a pointer to the most recently created room in the chain
     int dir = FMath::RandRange(0, 2);        // choose a random direction to place the next room in, (dont go DOWN because its easy to get locked in and no extra rooms can be added)
     int x = last->x;                        // get the x position of the last room
     int y = last->y;                        // get the y position of the last room
     switch (dir) {                            // calculate the coordinate of the new room going in the random direction
     case 0: x = last->x + 1; break;            // if the new room is to the left, x = last.x + 1
     case 1: y = last->y + 1; break;            // if the new room is above, y = last.y + 1
     case 2:    x = last->x - 1; break;            // if the new room is to the right, x = last.x - 1
     }
     if (!validLoc(x, y))                    // check if the location of the new room is not already occupied by another room
         return genNextRoom();                // if the room wasnt valid then try again (random has a good chance not to try the same direction again) [can RARELY cause a stack overflow]
     Room* next = new Room(x, y, dir, last);    // get a pointer to the new room
     next->addDoor();                        // create a doorway between this room and the last room
     return next;                            // return a pointer to the new room
 }

 /**
 * Generates any rooms that extend off of the main chain.
 * @param current A pointer to the Room that extensions should be added on to
 * @param extend The number of recursive extensions should be made on this tile (dont make this big, like 2..3 is sufficent)
 */
 void genExtRooms(Room* current, int extend) {
     std::vector<Room*> validPos;                                            // stores a pointer to each RoomPosition that is in a valid location

     int x = current->x + 1;
     int y = current->y;
     if (validLoc(x, y)) validPos.push_back(new Room(x, y, 0, current));        // Create a temporary room to the left if there is no room already there
     x = current->x;
     y = current->y + 1;
     if (validLoc(x, y)) validPos.push_back(new Room(x, y, 1, current));        // Create a temporary room above if there is no room already there
     x = current->x - 1;
     y = current->y;
     if (validLoc(x, y)) validPos.push_back(new Room(x, y, 2, current));        // Create a temporary room to the right if there is no room already there
     x = current->x;
     y = current->y - 1;
     if (validLoc(x, y)) validPos.push_back(new Room(x, y, 3, current));        // Create a temporary room below if there is no room already there

     int numRooms = FMath::RandRange(0, 2);                            // pick a random number of rooms to add onto the current room (0..2)
     while (numRooms-- > 0 && validPos.size() > 0) {                    // while we should still add another room and there is another valid location for an adjacent room
         int index = FMath::RandRange(0, validPos.size() - 1);        // randomly pick one of the available Rooms
         Room *nextRoom = validPos[index];                            // get the chosen room from the list of valid rooms
         nextRoom->addDoor();                                        // create a door between the new room and the current room
         rooms.push_back(nextRoom);                                    // add the new Room's pointer to the list of rooms
         if (extend > 0) genExtRooms(nextRoom, extend - 1);            // recursively call self so that each extension room on the main chain has a chance to be extended farther
         validPos[index] = validPos.back();                            // overwrite the used Room in the list of availble rooms to remove it from the list
         validPos.pop_back();                                        // remove the duplicate created by the overwrite
     }
 }

 AMapLayout::AMapLayout() {
     USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));    // create a sphere to use as the root of the map generator
     RootComponent = SphereComponent;                                                                        // set the sphere as the root component

     floor_ISMC = CreateDefaultSubobject<UInstancedStaticMeshComponent>(TEXT("Floor Instances"));            // create the instanced mesh component for placing floors down for each room
     floor_ISMC->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);            // make it a child of the root component

     door_ISMC = CreateDefaultSubobject<UInstancedStaticMeshComponent>(TEXT("Door Instances"));                // create the instanced mesh component for placing doors between each room
     door_ISMC->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);                // make it a child of the root component

     wall_ISMC = CreateDefaultSubobject<UInstancedStaticMeshComponent>(TEXT("Wall Instances"));                // create the instanced mesh component for placing walls
     wall_ISMC->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);                // make it a child of the root component
 }

 // Called when the game starts
 void AMapLayout::BeginPlay() {
     /* Setup variables and clearing old information */
     Super::BeginPlay();
     this->RegisterAllComponents();                        // Make sure all components are registered

     floor_ISMC->SetStaticMesh(FloorMesh);                // Set the mesh to use for the floor
     floor_ISMC->ClearInstances();                        // Clear any instances already on the map
     door_ISMC->SetStaticMesh(DoorMesh);                    // Set the mesh to use for the doors
     door_ISMC->ClearInstances();                        // Clear any instances already on the map
     wall_ISMC->SetStaticMesh(WallMesh);                    // Set the mesh to use for the walls in each room
     wall_ISMC->ClearInstances();                        // Clear any instances already on the map

     Room::ROOM_SIZE = ROOM_SIZE;                        // Set the size of rooms for the Room class
     Room::TILE_SIZE = TILE_SIZE;                        // Set the size of tiles for the Room class
     Room::DOOR_WIDTH = DOOR_WIDTH * TILE_SIZE;            // Set the size of doorways for the Room class

     rooms.clear();                                        // Clear any rooms stored from the last run
     rooms.push_back(new Room());                        // Create the first room in the map

     int roomCount = FMath::RandRange(MAIN_CHAIN_MIN, MAIN_CHAIN_RAND + MAIN_CHAIN_MIN);        // Calculate how many rooms should be in the main chain of rooms

     /* Generate the main chain of rooms */
     for (int i = 0; i < roomCount; i++)                                // For each room that should be created
         rooms.push_back(genNextRoom());                                // Generate a new room in a valid location adjacent to the previous room

     /* Generate extension rooms branching off the main chain of rooms */
     for (int i = 0; i < roomCount - 1; i++)                            // For all rooms in the main chain besides the last room (the exit)
         genExtRooms(rooms[i], EXT_LENGTH);                            // Generate rooms that branch off in different directions

     /* Start placing the objects in the world */
     for (int i = 0; i < rooms.size(); i++) {                        // For every room that was generated
         Room *cur = rooms[i];                                        // Store a pointer to the current room

         /* Place the floor for the room in the world */
         floor_ISMC->AddInstance(cur->getWorldPosition());            // Create an instance of the floor mesh in the world location

         /* Place doors in the world */
         std::vector<FTransform> doorPos = cur->getDoorPositions();    // Get the location of all the doors in the room
         for (int j = 0; j < doorPos.size(); j++)                    // For each door
             door_ISMC->AddInstance(doorPos[j]);                        // Create an instance of it in the world

         /* Place walls around each room */
         std::vector<FTransform> wallPos = cur->getWallPositions();    // Get the location of all the walls in the room
         for (int j = 0; j < wallPos.size(); j++)                    // For each wall
             wall_ISMC->AddInstance(wallPos[j]);                        // Create an instance of it in the world
     }
 }

Room.h

 #pragma once
 #include "CoreMinimal.h"
 #include <vector>


 /**
 * An object that represents an individual room in the level
 */
 class MAPGEN_API Room {
 private:
     struct Coord {                        // stores the real world coordinates of components in the room, ex: walls, doors
         float x;                        // the x position of the object
         float y;                        // the y position of the object
     };

     int worldX;                            // coodinate location of this room in world units
     int worldY;                            // coodinate location of this room in world units

     static int EDGE_OFFSET;                // constant value for the offset from the center of a room to the edge
     static int DOOR_OFF_RNG;            // constant value for how far a door can be offset from the center of a wall

     Room* last;                            // stores a pointer to the previous room in the chain

     std::vector<Coord> doors;            // stores the location of each door in the room

     float left;                            // stores the position of the door on the left wall if there is one
     float above;                        // stores the position of the door on the upper wall if there is one
     float right;                        // stores the position of the door on the right wall if there is one
     float below;                        // stores the position of the door on the lower wall if there is one

     /**
      * Gets the side of a room a door is on
      */
     int getDoorSide(Coord door);

 public:
     int x;                                // coordinate location of this room in relation to other rooms
     int y;                                // coordinate location of this room in relation to other rooms
     int dir;                            // stores the direction to the previous room

     static int ROOM_SIZE;                // constant value for the size in world units of each room
     static int TILE_SIZE;                // constant value for the size of each tile in world units
     static float DOOR_WIDTH;

     Room(int x = 0, int y = 0, int dir = -1, Room* last = NULL);

     /**
     * Add a door between this room and the previous room in the chain
     */
     void addDoor();

     /**
     * Add a door between this room and the previous room in the chain (only called from other Room objects)
     * @param doorPos The coordinates of the door on the new room, to be reveresed on this room so the doors line up
     */
     void addDoorEntrance(Coord doorPos);

     /**
     * Checks if this room already exists at the given coordinates
     */
     bool posEquals(int x, int y);

     /**
     * Gets the FTransform of where this room should be located in the world space
     */
     FTransform getWorldPosition();

     /**
     * Gets the FTansform for every door belonging to this Room
     */
     std::vector<FTransform> getDoorPositions();

     /**
     * Gets the FTansform for every wall belonging to this Room
     */
     std::vector<FTransform> getWallPositions();
 };

Room.cpp

 #include "Room.h"

 /* Init static constants */
 int Room::ROOM_SIZE;
 int Room::TILE_SIZE;
 float Room::DOOR_WIDTH;

 int Room::EDGE_OFFSET = (ROOM_SIZE / 2) - (TILE_SIZE / 2);
 int Room::DOOR_OFF_RNG = (ROOM_SIZE / TILE_SIZE) / 2 - 4;    // doors are 4 tiles wide + keeps doors atleast 2 tiles from a corner

 Room::Room(int x, int y, int dir, Room* last) {
     this->x = x;
     this->y = y;
     this->dir = dir;
     this->last = last;

     this->worldX = x * ROOM_SIZE;                // calculate this rooms position in world space
     this->worldY = y * ROOM_SIZE;                // calculate this rooms position in world space

     left = ROOM_SIZE + worldY + DOOR_WIDTH;        // simulate no door (distance is always larger than distance to a door, which would prevent a wall from spawning there)
     above = ROOM_SIZE + worldX + DOOR_WIDTH;    // simulate no door (distance is always larger than distance to a door, which would prevent a wall from spawning there)
     right = ROOM_SIZE + worldY + DOOR_WIDTH;    // simulate no door (distance is always larger than distance to a door, which would prevent a wall from spawning there)
     below = ROOM_SIZE + worldX + DOOR_WIDTH;    // simulate no door (distance is always larger than distance to a door, which would prevent a wall from spawning there)
 }

 void Room::addDoor() {
     Coord doorPos;                                // stores the location of a door in world space
     doorPos.x = 0;                                // coordinates allways start at 0
     doorPos.y = 0;                                // coordinates allways start at 0
     int door_offset = FMath::RandRange(-DOOR_OFF_RNG, DOOR_OFF_RNG) * TILE_SIZE;    // pick a random tile to shift the door by (so doors are not always centered on each wall)
     switch (this->dir) {                        // determine what wall the door is on
     case 0:                                        // if the door is on the left wall
         doorPos.x -= EDGE_OFFSET;                // set its x position to be on the left wall
         doorPos.y += door_offset;                // set its y position to be a random spot along the left wall
         left = doorPos.y + worldY;                // cache the offset location of this door in world cordinates to be used for wall placement
         break;
     case 1:                                        // if the door is on the above wall    
         doorPos.y -= EDGE_OFFSET;                // set its y position to be on the above wall
         doorPos.x += door_offset;                // set its x position to be a random spot along the above wall
         above = doorPos.x + worldX;                // cache the offset location of this door in world cordinates to be used for wall placement
         break;
     case 2:                                        // if the door is on the right wall
         doorPos.x += EDGE_OFFSET;                // set its x position to be on the right wall
         doorPos.y += door_offset;                // set its y position to be a random spot along the right wall
         right = doorPos.y + worldY;                // cache the offset location of this door in world cordinates to be used for wall placement
         break;
     case 3:                                        // if the door is on the bottom wall
         doorPos.y += EDGE_OFFSET;                // set its y position to be on the bottom wall
         doorPos.x += door_offset;                // set its x position to be a random spot along the bottom wall
         below = doorPos.x + worldX;                // cache the offset location of this door in world cordinates to be used for wall placement
         break;
     }

     this->doors.push_back(doorPos);                // add the door to the list of doors for this room
     last->addDoorEntrance(doorPos);                // add a door on the previous room that connects to the new door on this room
 }

 void Room::addDoorEntrance(Coord doorPos) {
     /* flip the direction of the door so it lines up with the door on the new room */
     if (abs(doorPos.x) == EDGE_OFFSET) doorPos.x = -doorPos.x;
     else if (abs(doorPos.y) == EDGE_OFFSET) doorPos.y = -doorPos.y;

     /* cache the offset location of this door in world cordinates to be used for wall placement */
     switch (getDoorSide(doorPos)) {
     case 0: left = doorPos.y + worldY; break;
     case 1:    above = doorPos.x + worldX; break;
     case 2:    right = doorPos.y + worldY; break;
     case 3:    below = doorPos.x + worldX; break;
     }
     this->doors.push_back(doorPos);                // add the door to the list of doors for this room
 }

 int Room::getDoorSide(Coord door) {
     if (door.x == -EDGE_OFFSET) return 0;
     else if (door.y == -EDGE_OFFSET) return 1;
     else if (door.x == EDGE_OFFSET) return 2;
     return 3; //else if (door.y == EDGE_OFFSET) , This will never be somthing else because a Door will always have 1 coordinate = EDGE_OFFSET
 }

 bool Room::posEquals(int x, int y) {
     if (this->x == x && this->y == y)
         return true;
     return false;
 }

 FTransform Room::getWorldPosition() {
     return FTransform(FVector(this->x * ROOM_SIZE, this->y * ROOM_SIZE, 0));
 }

 std::vector<FTransform> Room::getDoorPositions() {
     std::vector<FTransform> doorPositions;                                                        // stores the FTransform for all doors in this room
     for (int i = 0; i < this->doors.size(); i++) {                                                // for every door
         Coord door = doors[i];
         FTransform trans_door = FTransform(FVector(door.x + worldX, door.y + worldY, 0));        // create the FTransform using the world coordinates of the door
         trans_door.SetRotation(FQuat::MakeFromEuler({ 0.f, 0.f, getDoorSide(door) * 90.0f }));    // rotate the door to match the wall it is against
         doorPositions.push_back(trans_door);                                                    // add the FTransform to the list
     }
     return doorPositions;                                                                        // return the list of FTransforms for all the doors
 }

 std::vector<FTransform> Room::getWallPositions() {
     std::vector<Coord> wallPositions;
     /* calculates the range of world coordinates that this room occupies */
     float startX = worldX - EDGE_OFFSET;
     float endX = worldX + EDGE_OFFSET;
     float startY = worldY - EDGE_OFFSET;
     float endY = worldY + EDGE_OFFSET;

     /* Calculate wall positions around the edge of the room */
     /* This is kindof hard to explain step by step but basically it puts a wall on every tile that is on the edge of room
      * if the distance from the cached door location for that wall and that particular peice of wall is less than the width of the door then dont place that wall peice.
     */
     Coord wall;
     for (int i = 0; i < ROOM_SIZE; i += TILE_SIZE) {
         /* place wall peice on the top wall */
         wall.x = startX + i;
         wall.y = startY;
         if (abs(wall.x - above) >= DOOR_WIDTH) wallPositions.push_back(wall);
         /* place wall peice on the bottom wall */
         wall.x = startX + i;
         wall.y = endY;
         if (abs(wall.x - below) >= DOOR_WIDTH) wallPositions.push_back(wall);
     }
     for (int i = TILE_SIZE; i < ROOM_SIZE - TILE_SIZE; i += TILE_SIZE) {        // top/bottom walls cover the corner peices so dont also do corners with the left/right
                                                                                 /* place wall peice on the left wall */
         wall.x = startX;
         wall.y = startY + i;
         if (abs(wall.y - left) >= DOOR_WIDTH) wallPositions.push_back(wall);
         /* place wall peice on the right wall */
         wall.x = endX;
         wall.y = startY + i;
         if (abs(wall.y - right) >= DOOR_WIDTH) wallPositions.push_back(wall);
     }

     /* create an FTransform for each wall and return them in a list */
     std::vector<FTransform> walls;
     for (int i = 0; i < wallPositions.size(); i++) {
         Coord wall = wallPositions[i];
         walls.push_back(FTransform(FVector(wall.x, wall.y, 0)));
     }
     return walls;
 }
Product Version: UE 4.16
Tags:
more ▼

asked Oct 12 '17 at 07:17 PM in C++ Programming

avatar image

Jacob Pozaic
16 1 5

(comments are locked)
10|2000 characters needed characters left

2 answers: sort voted first

I have found out what the issue was, I had done all your suggestions and still no fix. I ended up attaching a debugger to the unreal engine editor then opening the project, turns out there was a divide by 0 in Room because TILE_SIZE wasn't assigned a value before the DLL tried to calculate its value. after correcting this the editor opened with the debugger and seemed to be working properly, I am currently testing if it will open without a debugger.

more ▼

answered Oct 16 '17 at 12:51 AM

avatar image

Jacob Pozaic
16 1 5

(comments are locked)
10|2000 characters needed characters left

First of all don't post any new quastion about this, try to compile everything in to this one since it seems everything is related to same issues

Ok, let me start with basic issues with you code, not sure if this gonna fix your issies, but might help

1.Don't use standard C++ library use UE4 APIs as much as you can, insted of std::vector use TArray ot other UE4 contianer it is compatible with UE4 reflection system. Not to mention if you place any UObject in std::vector it refrence won't be visible by the engine and if object is not refrences anywhere it will be garbage collected

2.In case of non-UObject clases use F prefix so FRoom, if we in matter of style function names should start with upper case in UE4 code. Would be good if you also consider to use UObject for rooms as it will help you with debuggin, rooms will be visible by the engine and you will be able to reference those rooms in blueprints

3.Don't do global functions and global variables, use static functions insted (they even supported by the blueprints) and try to avoid global and static variables at all

4.Don't use int, due to size difference between compilers of this type UE4 uses size defined ints insted (int8, int16,int32, uint8, uint16, uint32), blueprint integer is int32 and bluprint byte type is uint8, other int types aren't supported by blueprint and property editor but you can still use them in C++. You should get UnrealHeaderTool errors if you use int.

In other words in light of UE4 conventions and styles sorry to say that but your code is a mess and compilation issues might be related to that as you coding in away that engine and it's tools don't expect you to code that way. AMapLayout aspecially is style mess, you use 3 diffrent naming conventions in same time. You seem to have C++ knowlage, so i recommand you to looks on example project or engine code it self so you can get fimilar with the style. Think that you working for Epic and you need to adopt this style so other Epic employees (but technically anyone who code in UE4) can understand your code. There also docs:

https://docs.unrealengine.com/latest/INT/Programming/Development/CodingStandard/

As for hot reload lot loading and thigns not showing at first time, this is normal. Hot reload is not perfect and sometimes mess ups and oyu need to restart the editor, this aspacially happens when you introduce new properties and classes, if you do so compile without editor. But before jurging that please clean up your code as your issues related to hot reload might be also related.

more ▼

answered Oct 15 '17 at 02:42 AM

avatar image

Shadowriver
34.6k 917 164 1095

avatar image Jacob Pozaic Oct 15 '17 at 02:59 AM

Ok, thanks. I will rewrite my code to fit UE's model. as for coding, I am actually not too much of a C++ developer, I work primarily in Java and Assembly.

also as far as the hot reload goes, my best guess is that my code does compile successfully, but when the engine tries to load the new DLL it fails because it didn't compile right (might be coding style-related) and then when I re-open the editor it will by default try to open the most recently created DLL, that DLL being the broken one.

Thanks for your response though! Hopefully that will resolve my issue.

(comments are locked)
10|2000 characters needed characters left
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question