├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── Resources ├── ButtonIcon_40x.png └── Icon128.png ├── ServerRecast.uplugin └── Source └── ServerRecast ├── Private ├── ExportNavMesh.cpp ├── ServerRecast.cpp ├── ServerRecastCommands.cpp └── ServerRecastStyle.cpp ├── Public ├── ExportNavMesh.h ├── ServerRecast.h ├── ServerRecastCommands.h └── ServerRecastStyle.h └── ServerRecast.Build.cs /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Visual Studio 2015 database file 5 | *.VC.db 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.ipa 36 | 37 | # These project files can be generated by the engine 38 | *.xcodeproj 39 | *.xcworkspace 40 | *.sln 41 | *.suo 42 | *.opensdf 43 | *.sdf 44 | *.VC.db 45 | *.VC.opendb 46 | 47 | # Precompiled Assets 48 | SourceArt/**/*.png 49 | SourceArt/**/*.tga 50 | 51 | # Binary Files 52 | Binaries/* 53 | 54 | # Builds 55 | Build/* 56 | 57 | # Whitelist PakBlacklist-.txt files 58 | !Build/*/ 59 | Build/*/** 60 | !Build/*/PakBlacklist*.txt 61 | 62 | # Don't ignore icon files in Build 63 | !Build/**/*.ico 64 | 65 | # Built data for maps 66 | *_BuiltData.uasset 67 | 68 | # Configuration files generated by the Editor 69 | Saved/* 70 | 71 | # Compiled source files for the engine to use 72 | Intermediate/* 73 | 74 | # Cache files for the editor to use 75 | DerivedDataCache/* 76 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "recastnavigation"] 2 | path = recastnavigation 3 | url = https://github.com/recastnavigation/recastnavigation.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ServerRecast 2 | 3 | WARNING! This version was tested for compatibility with UE 4.21 version only! 4 | 5 | UE4 plugin for navmesh export 6 | 7 | Usage: 8 | 9 | 1. Clone https://github.com/darkwere/ServerRecast.git repo. 10 | 2. In ServerRecast folder run git command: git submodule update --init --remote 11 | 3. Put ServerRecast into [Your project]\Plugins folder. 12 | 4. In ServerRecast\recastnavigation folder look for readme.md file for instructions to build the solution. (Look down for explanations) 13 | 5. Open the level in Unreal Engine 4. 14 | 6. Put Navmesh Bounds Volume into the level. 15 | 7. Resize Navmesh Bounds Volume to fill all the necessary space in the level. You can check it by pressing 'P' key. 16 | 8. Press ServerRecast button in the top panel of Unreal Engine (it will appear there if you install the plugin successfully). 17 | 9. RecastDemo program will show up. 18 | 10. Select the type of sample mesh (solo mesh or tile mesh). 19 | 11. Select input mesh .obj 20 | 12. Press Build button. 21 | 13. Press Save after Build is finished. 22 | 14. solo_navmesh.bin or all_tiles_navmesh.bin (depends on selected sample) is your Navmesh file, now you can use it. 23 | 24 | Explanations for p.4: 25 | 1. Put premake5.exe file into recastnavigation\RecastDemo folder. 26 | 2. Run "premake5.exe vs2017" at the command prompt. 27 | 3. Extract SDL library into recastnavigation\RecastDemo\Contrib folder and rename "SDL2-2.0.9" folder to "SDL". 28 | 4. Open recastnavigation.sln at recastnavigation\RecastDemo\Build\vs2017 folder with VS2017 and build solution. 29 | 5. Check RecastDemo.exe at recastnavigation\RecastDemo\bin folder, run and test it with build-in meshes. -------------------------------------------------------------------------------- /Resources/ButtonIcon_40x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwere/ServerRecast/9bf6f5b5d25436e102b5942fa8e67582c96f2a28/Resources/ButtonIcon_40x.png -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwere/ServerRecast/9bf6f5b5d25436e102b5942fa8e67582c96f2a28/Resources/Icon128.png -------------------------------------------------------------------------------- /ServerRecast.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "ServerRecast", 6 | "Description": "", 7 | "Category": "Recast", 8 | "CreatedBy": "", 9 | "CreatedByURL": "", 10 | "DocsURL": "", 11 | "MarketplaceURL": "", 12 | "SupportURL": "", 13 | "EnabledByDefault": true, 14 | "CanContainContent": false, 15 | "IsBetaVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "ServerRecast", 20 | "Type": "Editor", 21 | "LoadingPhase": "Default" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /Source/ServerRecast/Private/ExportNavMesh.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | #include "ExportNavMesh.h" 3 | #include "ServerRecast.h" 4 | #include "Navmesh/RecastHelpers.h" 5 | #include "Runtime/Core/Public/GenericPlatform/GenericPlatform.h" 6 | #include "Runtime/Navmesh/Public/Detour/DetourNavMesh.h" 7 | #include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h" 8 | #include "NavigationSystem.h" 9 | #include "RecastNavMeshGenerator.h" 10 | 11 | 12 | FServerRecastGeometryCache::FServerRecastGeometryCache(const uint8* Memory) 13 | { 14 | Header = *((FHeader*)Memory); 15 | Verts = (float*)(Memory + sizeof(FServerRecastGeometryCache)); 16 | Indices = (int32*)(Memory + sizeof(FServerRecastGeometryCache) + (sizeof(float) * Header.NumVerts * 3)); 17 | } 18 | 19 | void FExportNavMesh::MyExportNavigationData(const FString& FileName) 20 | { 21 | const UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent(GetWorld()); 22 | const FNavigationOctree* NavOctree = NavSys ? NavSys->GetNavOctree() : NULL; 23 | if (NavOctree == NULL) 24 | { 25 | UE_LOG(LogNavigation, Error, TEXT("Failed to export navigation data due to %s being NULL"), NavSys == NULL ? TEXT("NavigationSystem") : TEXT("NavOctree")); 26 | return; 27 | } 28 | 29 | const double StartExportTime = FPlatformTime::Seconds(); 30 | 31 | FString CurrentTimeStr = FDateTime::Now().ToString(); 32 | for (int32 Index = 0; Index < NavSys->NavDataSet.Num(); ++Index) 33 | { 34 | // feed data from octtree and mark for rebuild 35 | TNavStatArray CoordBuffer; 36 | TNavStatArray IndexBuffer; 37 | const ARecastNavMesh* NavData = Cast(NavSys->NavDataSet[Index]); 38 | if (NavData) 39 | { 40 | struct FAreaExportData 41 | { 42 | FConvexNavAreaData Convex; 43 | uint8 AreaId; 44 | }; 45 | TArray AreaExport; 46 | 47 | for (FNavigationOctree::TConstElementBoxIterator It(*NavOctree, GetTotalBounds()); 48 | It.HasPendingElements(); 49 | It.Advance()) 50 | { 51 | const FNavigationOctreeElement& Element = It.GetCurrentElement(); 52 | const bool bExportGeometry = Element.Data->HasGeometry() && Element.ShouldUseGeometry(GetOwner()->GetConfig()); 53 | 54 | if (bExportGeometry && Element.Data->CollisionData.Num()) 55 | { 56 | FServerRecastGeometryCache CachedGeometry(Element.Data->CollisionData.GetData()); 57 | IndexBuffer.Reserve(IndexBuffer.Num() + (CachedGeometry.Header.NumFaces * 3)); 58 | CoordBuffer.Reserve(CoordBuffer.Num() + (CachedGeometry.Header.NumVerts * 3)); 59 | 60 | // For is invert it need for invert normals 61 | for (int32 i = CachedGeometry.Header.NumFaces * 3 - 1; i >= 0 ; --i) 62 | { 63 | IndexBuffer.Add(CachedGeometry.Indices[i] + CoordBuffer.Num() / 3); 64 | } 65 | 66 | // Calcilate the Vertecs 67 | for (int32 i = 0; i < CachedGeometry.Header.NumVerts * 3; i += 3) 68 | { 69 | FVector Coord = FVector( 70 | CachedGeometry.Verts[i] / 100.f * -1.f, 71 | CachedGeometry.Verts[i + 2] / 100.f, 72 | CachedGeometry.Verts[i + 1] / 100.f 73 | ); 74 | FVector NewCoord = ChangeDirectionOfPoint(Coord); 75 | 76 | ///CoordBuffer.Add(CachedGeometry.Verts[i] / 100.f); 77 | CoordBuffer.Add(NewCoord.X); 78 | CoordBuffer.Add(NewCoord.Z ); 79 | CoordBuffer.Add(NewCoord.Y ); 80 | } 81 | } 82 | else 83 | { 84 | const TArray& AreaMods = Element.Data->Modifiers.GetAreas(); 85 | for (int32 i = 0; i < AreaMods.Num(); i++) 86 | { 87 | FAreaExportData ExportInfo; 88 | ExportInfo.AreaId = NavData->GetAreaID(AreaMods[i].GetAreaClass()); 89 | 90 | if (AreaMods[i].GetShapeType() == ENavigationShapeType::Convex) 91 | { 92 | AreaMods[i].GetConvex(ExportInfo.Convex); 93 | 94 | TArray ConvexVerts; 95 | GrowConvexHull(NavData->AgentRadius, ExportInfo.Convex.Points, ConvexVerts); 96 | ExportInfo.Convex.MinZ -= NavData->CellHeight; 97 | ExportInfo.Convex.MaxZ += NavData->CellHeight; 98 | ExportInfo.Convex.Points = ConvexVerts; 99 | 100 | AreaExport.Add(ExportInfo); 101 | } 102 | } 103 | } 104 | } 105 | 106 | // I don't now what doing this part 107 | UWorld* NavigationWorld = GetWorld(); 108 | for (int32 LevelIndex = 0; LevelIndex < NavigationWorld->GetNumLevels(); ++LevelIndex) 109 | { 110 | const ULevel* const Level = NavigationWorld->GetLevel(LevelIndex); 111 | if (Level == NULL) 112 | { 113 | continue; 114 | } 115 | 116 | const TArray* LevelGeom = Level->GetStaticNavigableGeometry(); 117 | if (LevelGeom != NULL && LevelGeom->Num() > 0) 118 | { 119 | TNavStatArray Verts; 120 | TNavStatArray Faces; 121 | // For every ULevel in World take its pre-generated static geometry vertex soup 122 | TransformVertexSoupToRecast(*LevelGeom, Verts, Faces); //RecastGeometryExport:: 123 | 124 | IndexBuffer.Reserve(IndexBuffer.Num() + Faces.Num()); 125 | CoordBuffer.Reserve(CoordBuffer.Num() + Verts.Num() * 3); 126 | 127 | for (int32 i = 0; i < Faces.Num(); i++) 128 | { 129 | IndexBuffer.Add(Faces[i] + CoordBuffer.Num() / 3); 130 | } 131 | // 132 | 133 | for (int32 i = 0; i < Verts.Num(); i++) 134 | { 135 | CoordBuffer.Add(Verts[i].X); 136 | CoordBuffer.Add(Verts[i].Y); 137 | CoordBuffer.Add(Verts[i].Z); 138 | } 139 | } 140 | } 141 | 142 | FString AreaExportStr; 143 | for (int32 i = 0; i < AreaExport.Num(); i++) 144 | { 145 | const FAreaExportData& ExportInfo = AreaExport[i]; 146 | AreaExportStr += FString::Printf(TEXT("\nAE %d %d %f %f\n"), 147 | ExportInfo.AreaId, ExportInfo.Convex.Points.Num(), ExportInfo.Convex.MinZ, ExportInfo.Convex.MaxZ); 148 | 149 | for (int32 iv = 0; iv < ExportInfo.Convex.Points.Num(); iv++) 150 | { 151 | FVector Pt = Unreal2RecastPoint(ExportInfo.Convex.Points[iv]); 152 | AreaExportStr += FString::Printf(TEXT("Av %f %f %f\n"), Pt.X, Pt.Y, Pt.Z); 153 | } 154 | } 155 | 156 | FString AdditionalData; 157 | 158 | if (AreaExport.Num()) 159 | { 160 | AdditionalData += "# Area export\n"; 161 | AdditionalData += AreaExportStr; 162 | AdditionalData += "\n"; 163 | } 164 | 165 | AdditionalData += "# RecastDemo specific data\n"; 166 | #if 0 167 | // use this bounds to have accurate navigation data bounds 168 | const FVector Center = Unreal2RecastPoint(NavData->GetBounds().GetCenter()); 169 | FVector Extent = FVector(NavData->GetBounds().GetExtent()); 170 | Extent = FVector(Extent.X, Extent.Z, Extent.Y); 171 | #else 172 | // this bounds match navigation bounds from level 173 | FBox RCNavBounds = Unreal2RecastBox(GetTotalBounds()); 174 | const FVector Center = RCNavBounds.GetCenter(); 175 | const FVector Extent = RCNavBounds.GetExtent(); 176 | #endif 177 | const FBox Box = FBox::BuildAABB(Center, Extent); 178 | AdditionalData += FString::Printf( 179 | TEXT("rd_bbox %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f\n"), 180 | Box.Min.X, Box.Min.Y, Box.Min.Z, 181 | Box.Max.X, Box.Max.Y, Box.Max.Z 182 | ); 183 | 184 | const FRecastNavMeshGenerator* CurrentGen = static_cast(NavData->GetGenerator()); 185 | check(CurrentGen); 186 | AdditionalData += FString::Printf(TEXT("# AgentHeight\n")); 187 | AdditionalData += FString::Printf(TEXT("rd_agh %5.5f\n"), CurrentGen->GetConfig().AgentHeight); 188 | AdditionalData += FString::Printf(TEXT("# AgentRadius\n")); 189 | AdditionalData += FString::Printf(TEXT("rd_agr %5.5f\n"), CurrentGen->GetConfig().AgentRadius); 190 | 191 | AdditionalData += FString::Printf(TEXT("# Cell Size\n")); 192 | AdditionalData += FString::Printf(TEXT("rd_cs %5.5f\n"), CurrentGen->GetConfig().cs); 193 | AdditionalData += FString::Printf(TEXT("# Cell Height\n")); 194 | AdditionalData += FString::Printf(TEXT("rd_ch %5.5f\n"), CurrentGen->GetConfig().ch); 195 | 196 | AdditionalData += FString::Printf(TEXT("# Agent max climb\n")); 197 | AdditionalData += FString::Printf(TEXT("rd_amc %d\n"), (int)CurrentGen->GetConfig().AgentMaxClimb); 198 | AdditionalData += FString::Printf(TEXT("# Agent max slope\n")); 199 | AdditionalData += FString::Printf(TEXT("rd_ams %5.5f\n"), CurrentGen->GetConfig().walkableSlopeAngle); 200 | 201 | AdditionalData += FString::Printf(TEXT("# Region min size\n")); 202 | AdditionalData += FString::Printf(TEXT("rd_rmis %d\n"), (uint32)FMath::Sqrt(CurrentGen->GetConfig().minRegionArea)); 203 | AdditionalData += FString::Printf(TEXT("# Region merge size\n")); 204 | AdditionalData += FString::Printf(TEXT("rd_rmas %d\n"), (uint32)FMath::Sqrt(CurrentGen->GetConfig().mergeRegionArea)); 205 | 206 | AdditionalData += FString::Printf(TEXT("# Max edge len\n")); 207 | AdditionalData += FString::Printf(TEXT("rd_mel %d\n"), CurrentGen->GetConfig().maxEdgeLen); 208 | 209 | AdditionalData += FString::Printf(TEXT("# Perform Voxel Filtering\n")); 210 | AdditionalData += FString::Printf(TEXT("rd_pvf %d\n"), CurrentGen->GetConfig().bPerformVoxelFiltering); 211 | AdditionalData += FString::Printf(TEXT("# Generate Detailed Mesh\n")); 212 | AdditionalData += FString::Printf(TEXT("rd_gdm %d\n"), CurrentGen->GetConfig().bGenerateDetailedMesh); 213 | AdditionalData += FString::Printf(TEXT("# MaxPolysPerTile\n")); 214 | AdditionalData += FString::Printf(TEXT("rd_mppt %d\n"), CurrentGen->GetConfig().MaxPolysPerTile); 215 | AdditionalData += FString::Printf(TEXT("# maxVertsPerPoly\n")); 216 | AdditionalData += FString::Printf(TEXT("rd_mvpp %d\n"), CurrentGen->GetConfig().maxVertsPerPoly); 217 | AdditionalData += FString::Printf(TEXT("# Tile size\n")); 218 | AdditionalData += FString::Printf(TEXT("rd_ts %d\n"), CurrentGen->GetConfig().tileSize); 219 | 220 | AdditionalData += FString::Printf(TEXT("\n")); 221 | 222 | const FString FilePathName = FileName + ".obj";// +FString::Printf(TEXT("_NavDataSet%d_%s.obj"), Index, *CurrentTimeStr); 223 | ExportGeomToOBJFile(FilePathName, CoordBuffer, IndexBuffer, AdditionalData); 224 | } 225 | } 226 | UE_LOG(LogNavigation, Log, TEXT("ExportNavigation time: %.3f sec ."), FPlatformTime::Seconds() - StartExportTime); 227 | } 228 | 229 | void FExportNavMesh::GrowConvexHull(const float ExpandBy, const TArray& Verts, TArray& OutResult) 230 | { 231 | if (Verts.Num() < 3) 232 | { 233 | return; 234 | } 235 | 236 | struct FSimpleLine 237 | { 238 | FVector P1, P2; 239 | 240 | FSimpleLine() {} 241 | 242 | FSimpleLine(FVector Point1, FVector Point2) 243 | : P1(Point1), P2(Point2) 244 | { 245 | 246 | } 247 | static FVector Intersection(const FSimpleLine& Line1, const FSimpleLine& Line2) 248 | { 249 | const float A1 = Line1.P2.X - Line1.P1.X; 250 | const float B1 = Line2.P1.X - Line2.P2.X; 251 | const float C1 = Line2.P1.X - Line1.P1.X; 252 | 253 | const float A2 = Line1.P2.Y - Line1.P1.Y; 254 | const float B2 = Line2.P1.Y - Line2.P2.Y; 255 | const float C2 = Line2.P1.Y - Line1.P1.Y; 256 | 257 | const float Denominator = A2*B1 - A1*B2; 258 | if (Denominator != 0) 259 | { 260 | const float t = (B1*C2 - B2*C1) / Denominator; 261 | return Line1.P1 + t * (Line1.P2 - Line1.P1); 262 | } 263 | 264 | return FVector::ZeroVector; 265 | } 266 | }; 267 | 268 | TArray AllVerts(Verts); 269 | AllVerts.Add(Verts[0]); 270 | AllVerts.Add(Verts[1]); 271 | 272 | const int32 VertsCount = AllVerts.Num(); 273 | const FQuat Rotation90(FVector(0, 0, 1), FMath::DegreesToRadians(90)); 274 | 275 | float RotationAngle = MAX_FLT; 276 | for (int32 Index = 0; Index < VertsCount - 2; ++Index) 277 | { 278 | const FVector& V1 = AllVerts[Index + 0]; 279 | const FVector& V2 = AllVerts[Index + 1]; 280 | const FVector& V3 = AllVerts[Index + 2]; 281 | 282 | const FVector V01 = (V1 - V2).GetSafeNormal(); 283 | const FVector V12 = (V2 - V3).GetSafeNormal(); 284 | const FVector NV1 = Rotation90.RotateVector(V01); 285 | const float d = FVector::DotProduct(NV1, V12); 286 | 287 | if (d < 0) 288 | { 289 | // CW 290 | RotationAngle = -90; 291 | break; 292 | } 293 | else if (d > 0) 294 | { 295 | //CCW 296 | RotationAngle = 90; 297 | break; 298 | } 299 | } 300 | 301 | // check if we detected CW or CCW direction 302 | if (RotationAngle >= BIG_NUMBER) 303 | { 304 | return; 305 | } 306 | 307 | const float ExpansionThreshold = 2 * ExpandBy; 308 | const float ExpansionThresholdSQ = ExpansionThreshold * ExpansionThreshold; 309 | const FQuat Rotation(FVector(0, 0, 1), FMath::DegreesToRadians(RotationAngle)); 310 | FSimpleLine PreviousLine; 311 | OutResult.Reserve(Verts.Num()); 312 | for (int32 Index = 0; Index < VertsCount - 2; ++Index) 313 | { 314 | const FVector& V1 = AllVerts[Index + 0]; 315 | const FVector& V2 = AllVerts[Index + 1]; 316 | const FVector& V3 = AllVerts[Index + 2]; 317 | 318 | FSimpleLine Line1; 319 | if (Index > 0) 320 | { 321 | Line1 = PreviousLine; 322 | } 323 | else 324 | { 325 | const FVector V01 = (V1 - V2).GetSafeNormal(); 326 | const FVector N1 = Rotation.RotateVector(V01).GetSafeNormal(); 327 | const FVector MoveDir1 = N1 * ExpandBy; 328 | Line1 = FSimpleLine(V1 + MoveDir1, V2 + MoveDir1); 329 | } 330 | 331 | const FVector V12 = (V2 - V3).GetSafeNormal(); 332 | const FVector N2 = Rotation.RotateVector(V12).GetSafeNormal(); 333 | const FVector MoveDir2 = N2 * ExpandBy; 334 | const FSimpleLine Line2(V2 + MoveDir2, V3 + MoveDir2); 335 | 336 | const FVector NewPoint = FSimpleLine::Intersection(Line1, Line2); 337 | if (NewPoint == FVector::ZeroVector) 338 | { 339 | // both lines are parallel so just move our point by expansion distance 340 | OutResult.Add(V2 + MoveDir2); 341 | } 342 | else 343 | { 344 | const FVector VectorToNewPoint = NewPoint - V2; 345 | const float DistToNewVector = VectorToNewPoint.SizeSquared2D(); 346 | if (DistToNewVector > ExpansionThresholdSQ) 347 | { 348 | //clamp our point to not move to far from original location 349 | const FVector HelpPos = V2 + VectorToNewPoint.GetSafeNormal2D() * ExpandBy * 1.4142; 350 | OutResult.Add(HelpPos); 351 | } 352 | else 353 | { 354 | OutResult.Add(NewPoint); 355 | } 356 | } 357 | 358 | PreviousLine = Line2; 359 | } 360 | } 361 | 362 | void FExportNavMesh::TransformVertexSoupToRecast(const TArray& VertexSoup, TNavStatArray& Verts, TNavStatArray& Faces) 363 | { 364 | if (VertexSoup.Num() == 0) 365 | { 366 | return; 367 | } 368 | 369 | check(VertexSoup.Num() % 3 == 0); 370 | 371 | const int32 StaticFacesCount = VertexSoup.Num() / 3; 372 | int32 VertsCount = Verts.Num(); 373 | const FVector* Vertex = VertexSoup.GetData(); 374 | 375 | for (int32 k = 0; k < StaticFacesCount; ++k, Vertex += 3) 376 | { 377 | Verts.Add(Unreal2RecastPoint(Vertex[0])); 378 | Verts.Add(Unreal2RecastPoint(Vertex[1])); 379 | Verts.Add(Unreal2RecastPoint(Vertex[2])); 380 | Faces.Add(VertsCount + 2); 381 | Faces.Add(VertsCount + 1); 382 | Faces.Add(VertsCount + 0); 383 | 384 | VertsCount += 3; 385 | } 386 | } 387 | 388 | void FExportNavMesh::ExportGeomToOBJFile(const FString& InFileName, const TNavStatArray& GeomCoords, const TNavStatArray& GeomFaces, const FString& AdditionalData) 389 | { 390 | #define USE_COMPRESSION 0 391 | 392 | #if ALLOW_DEBUG_FILES 393 | //SCOPE_CYCLE_COUNTER(STAT_Navigation_TileGeometryExportToObjAsync); 394 | 395 | FString FileName = InFileName; 396 | 397 | #if USE_COMPRESSION 398 | FileName += TEXT("z"); 399 | struct FDataChunk 400 | { 401 | TArray UncompressedBuffer; 402 | TArray CompressedBuffer; 403 | void CompressBuffer() 404 | { 405 | const int32 HeaderSize = sizeof(int32); 406 | const int32 UncompressedSize = UncompressedBuffer.Num(); 407 | CompressedBuffer.Init(0, HeaderSize + FMath::Trunc(1.1f * UncompressedSize)); 408 | 409 | int32 CompressedSize = CompressedBuffer.Num() - HeaderSize; 410 | uint8* DestBuffer = CompressedBuffer.GetData(); 411 | FMemory::Memcpy(DestBuffer, &UncompressedSize, HeaderSize); 412 | DestBuffer += HeaderSize; 413 | 414 | FCompression::CompressMemory((ECompressionFlags)(COMPRESS_ZLIB | COMPRESS_BiasMemory), (void*)DestBuffer, CompressedSize, (void*)UncompressedBuffer.GetData(), UncompressedSize); 415 | CompressedBuffer.SetNum(CompressedSize + HeaderSize, false); 416 | } 417 | }; 418 | FDataChunk AllDataChunks[3]; 419 | const int32 NumberOfChunks = sizeof(AllDataChunks) / sizeof(FDataChunk); 420 | { 421 | FMemoryWriter ArWriter(AllDataChunks[0].UncompressedBuffer); 422 | for (int32 i = 0; i < GeomCoords.Num(); i += 3) 423 | { 424 | FVector Vertex(GeomCoords[i + 0], GeomCoords[i + 1], GeomCoords[i + 2]); 425 | ArWriter << Vertex; 426 | } 427 | } 428 | 429 | { 430 | FMemoryWriter ArWriter(AllDataChunks[1].UncompressedBuffer); 431 | for (int32 i = 0; i < GeomFaces.Num(); i += 3) 432 | { 433 | FVector Face(GeomFaces[i + 0] + 1, GeomFaces[i + 1] + 1, GeomFaces[i + 2] + 1); 434 | ArWriter << Face; 435 | } 436 | } 437 | 438 | { 439 | auto AnsiAdditionalData = StringCast(*AdditionalData); 440 | FMemoryWriter ArWriter(AllDataChunks[2].UncompressedBuffer); 441 | ArWriter.Serialize((ANSICHAR*)AnsiAdditionalData.Get(), AnsiAdditionalData.Length()); 442 | } 443 | 444 | FArchive* FileAr = IFileManager::Get().CreateDebugFileWriter(*FileName); 445 | if (FileAr != NULL) 446 | { 447 | for (int32 Index = 0; Index < NumberOfChunks; ++Index) 448 | { 449 | AllDataChunks[Index].CompressBuffer(); 450 | int32 BufferSize = AllDataChunks[Index].CompressedBuffer.Num(); 451 | FileAr->Serialize(&BufferSize, sizeof(int32)); 452 | FileAr->Serialize((void*)AllDataChunks[Index].CompressedBuffer.GetData(), AllDataChunks[Index].CompressedBuffer.Num()); 453 | } 454 | UE_LOG(LogNavigation, Error, TEXT("UncompressedBuffer size:: %d "), AllDataChunks[0].UncompressedBuffer.Num() + AllDataChunks[1].UncompressedBuffer.Num() + AllDataChunks[2].UncompressedBuffer.Num()); 455 | FileAr->Close(); 456 | } 457 | 458 | #else 459 | FArchive* FileAr = IFileManager::Get().CreateDebugFileWriter(*FileName); 460 | if (FileAr != NULL) 461 | { 462 | for (int32 Index = 0; Index < GeomCoords.Num(); Index += 3) 463 | { 464 | FString LineToSave = FString::Printf(TEXT("v %f %f %f \n"), GeomCoords[Index + 0], GeomCoords[Index + 1], GeomCoords[Index + 2]); 465 | auto AnsiLineToSave = StringCast(*LineToSave); 466 | FileAr->Serialize((ANSICHAR*)AnsiLineToSave.Get(), AnsiLineToSave.Length()); 467 | } 468 | 469 | for (int32 Index = 0; Index < GeomFaces.Num(); Index += 3) 470 | { 471 | FString LineToSave = FString::Printf(TEXT("f %d %d %d \n"), GeomFaces[Index + 0] + 1, GeomFaces[Index + 1] + 1, GeomFaces[Index + 2] + 1); 472 | auto AnsiLineToSave = StringCast(*LineToSave); 473 | FileAr->Serialize((ANSICHAR*)AnsiLineToSave.Get(), AnsiLineToSave.Length()); 474 | } 475 | 476 | auto AnsiAdditionalData = StringCast(*AdditionalData); 477 | FileAr->Serialize((ANSICHAR*)AnsiAdditionalData.Get(), AnsiAdditionalData.Length()); 478 | FileAr->Close(); 479 | } 480 | #endif 481 | 482 | #undef USE_COMPRESSION 483 | #endif 484 | } 485 | 486 | FVector FExportNavMesh::ChangeDirectionOfPoint(FVector Coord) 487 | { 488 | FRotator Direction = UKismetMathLibrary::FindLookAtRotation(FVector::ZeroVector, Coord); 489 | Direction.Yaw += 90.f; 490 | // Direction.Roll += 180.f; 491 | 492 | FVector ReturnCoord = Direction.Vector() * Coord.Size(); 493 | return ReturnCoord; 494 | } 495 | -------------------------------------------------------------------------------- /Source/ServerRecast/Private/ServerRecast.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "ServerRecast.h" 4 | #include "ServerRecastStyle.h" 5 | #include "ServerRecastCommands.h" 6 | #include "Misc/MessageDialog.h" 7 | #include "Framework/MultiBox/MultiBoxBuilder.h" 8 | 9 | // Nav Data 10 | #include "NavigationData.h" 11 | #include "ExportNavMesh.h" 12 | 13 | //Test 14 | #include "Runtime/Navmesh/Public/Detour/DetourNavMesh.h" 15 | #include "Navmesh/PImplRecastNavMesh.h" 16 | #include "Navmesh/RecastNavMesh.h" 17 | #include "Runtime/Navmesh/Public/Detour/DetourNavMeshBuilder.h" 18 | #include "NavigationSystem.h" 19 | 20 | // Editor 21 | #include "Editor/UnrealEd/Public/Editor.h" 22 | #include "Runtime/Engine/Classes/Engine/World.h" 23 | #include "UnrealEd.h" 24 | #include "LevelEditor.h" 25 | 26 | #include "Runtime/Core/Public/GenericPlatform/GenericPlatformProcess.h" 27 | #include 28 | 29 | static const FName ServerRecastTabName("ServerRecast"); 30 | 31 | #define LOCTEXT_NAMESPACE "FServerRecastModule" 32 | 33 | void FServerRecastModule::StartupModule() 34 | { 35 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 36 | 37 | FServerRecastStyle::Initialize(); 38 | FServerRecastStyle::ReloadTextures(); 39 | 40 | FServerRecastCommands::Register(); 41 | 42 | PluginCommands = MakeShareable(new FUICommandList); 43 | 44 | PluginCommands->MapAction( 45 | FServerRecastCommands::Get().PluginAction, 46 | FExecuteAction::CreateRaw(this, &FServerRecastModule::PluginButtonClicked), 47 | FCanExecuteAction()); 48 | 49 | FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); 50 | 51 | { 52 | TSharedPtr MenuExtender = MakeShareable(new FExtender()); 53 | MenuExtender->AddMenuExtension("WindowLayout", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FServerRecastModule::AddMenuExtension)); 54 | 55 | LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); 56 | } 57 | 58 | { 59 | TSharedPtr ToolbarExtender = MakeShareable(new FExtender); 60 | ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FServerRecastModule::AddToolbarExtension)); 61 | 62 | LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); 63 | } 64 | } 65 | 66 | void FServerRecastModule::ShutdownModule() 67 | { 68 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 69 | // we call this function before unloading the module. 70 | FServerRecastStyle::Shutdown(); 71 | 72 | FServerRecastCommands::Unregister(); 73 | } 74 | 75 | class ARecastNavMeshTrick : public ARecastNavMesh { public: const FPImplRecastNavMesh* GetRecastNavMeshImplTrick() const { return GetRecastNavMeshImpl(); } }; 76 | 77 | void FServerRecastModule::PluginButtonClicked() 78 | { 79 | 80 | if (UWorld* World = GEditor->GetEditorWorldContext().World()) 81 | { 82 | // Create mesh 83 | if (UNavigationSystemV1* NavSys = Cast(World->GetNavigationSystem())) 84 | { 85 | NavSys->GetAbstractNavData(); 86 | if (ANavigationData* NavData = NavSys->GetDefaultNavDataInstance(FNavigationSystem::ECreateIfEmpty::Create)) 87 | { 88 | const FString Name = World->GetMapName() ;// "UE_ExportingLevel";//NavData->GetName(); 89 | const FString Path = FPaths::ProjectPluginsDir() + "/ServerRecast/recastnavigation/RecastDemo/Bin/Meshes"; 90 | 91 | FExportNavMesh* NewRecast = static_cast(NavData->GetGenerator()); 92 | 93 | // Export Landscape 94 | NewRecast->MyExportNavigationData(FString::Printf(TEXT("%s/%s"), *Path, *Name)); 95 | 96 | // Create PathToExecutable. Adding "..." 97 | FString PathToExecutable = "\"" + FPaths::ProjectPluginsDir() + TEXT("ServerRecast/recastnavigation/RecastDemo/Bin/\" RecastDemo.exe"); 98 | PathToExecutable = PathToExecutable.Replace(TEXT("/"), TEXT("\\"), ESearchCase::IgnoreCase); 99 | 100 | // Create SaveNavmeshPath 101 | FString SaveNavmeshPath = FPaths::ProjectDir(); 102 | //SaveNavmeshPath.RemoveFromEnd(FApp::GetProjectName() + FString("/")); 103 | SaveNavmeshPath = SaveNavmeshPath.Replace(TEXT("/"), TEXT("\\"), ESearchCase::IgnoreCase); 104 | 105 | // Create PathToExecutable. SaveNavmeshPath haven't "...". It already adding to Sample_TileMesh 106 | FString EndCommand = TEXT("cmd /c start /D ") + PathToExecutable + TEXT(" 1 ") + Name + TEXT(".obj ") + Name + TEXT(".navmesh ") + "\"" + SaveNavmeshPath + TEXT("Navmeshes\\") ; 107 | 108 | UE_LOG(LogTemp, Log, TEXT(" %s "), *EndCommand); 109 | system(TCHAR_TO_ANSI(*EndCommand)); 110 | ///FPlatformProcess::CreateProc(*PathToExecutable, NULL, true, false, false, NULL, 0, NULL, NULL); 111 | } 112 | } 113 | } 114 | 115 | } 116 | 117 | 118 | void FServerRecastModule::AddMenuExtension(FMenuBuilder& Builder) 119 | { 120 | Builder.AddMenuEntry(FServerRecastCommands::Get().PluginAction); 121 | } 122 | 123 | void FServerRecastModule::AddToolbarExtension(FToolBarBuilder& Builder) 124 | { 125 | Builder.AddToolBarButton(FServerRecastCommands::Get().PluginAction); 126 | } 127 | 128 | #undef LOCTEXT_NAMESPACE 129 | 130 | IMPLEMENT_MODULE(FServerRecastModule, ServerRecast) -------------------------------------------------------------------------------- /Source/ServerRecast/Private/ServerRecastCommands.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "ServerRecastCommands.h" 4 | 5 | #define LOCTEXT_NAMESPACE "FServerRecastModule" 6 | 7 | void FServerRecastCommands::RegisterCommands() 8 | { 9 | UI_COMMAND(PluginAction, "ServerRecast", "Execute ServerRecast action", EUserInterfaceActionType::Button, FInputGesture()); 10 | } 11 | 12 | #undef LOCTEXT_NAMESPACE 13 | -------------------------------------------------------------------------------- /Source/ServerRecast/Private/ServerRecastStyle.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "ServerRecastStyle.h" 4 | #include "ServerRecast.h" 5 | #include "Framework/Application/SlateApplication.h" 6 | #include "Styling/SlateStyleRegistry.h" 7 | #include "SlateGameResources.h" 8 | #include "IPluginManager.h" 9 | 10 | TSharedPtr< FSlateStyleSet > FServerRecastStyle::StyleInstance = NULL; 11 | 12 | void FServerRecastStyle::Initialize() 13 | { 14 | if (!StyleInstance.IsValid()) 15 | { 16 | StyleInstance = Create(); 17 | FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance); 18 | } 19 | } 20 | 21 | void FServerRecastStyle::Shutdown() 22 | { 23 | FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance); 24 | ensure(StyleInstance.IsUnique()); 25 | StyleInstance.Reset(); 26 | } 27 | 28 | FName FServerRecastStyle::GetStyleSetName() 29 | { 30 | static FName StyleSetName(TEXT("ServerRecastStyle")); 31 | return StyleSetName; 32 | } 33 | 34 | #define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) 35 | #define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) 36 | #define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) 37 | #define TTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".ttf") ), __VA_ARGS__ ) 38 | #define OTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".otf") ), __VA_ARGS__ ) 39 | 40 | const FVector2D Icon16x16(16.0f, 16.0f); 41 | const FVector2D Icon20x20(20.0f, 20.0f); 42 | const FVector2D Icon40x40(40.0f, 40.0f); 43 | 44 | TSharedRef< FSlateStyleSet > FServerRecastStyle::Create() 45 | { 46 | TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("ServerRecastStyle")); 47 | Style->SetContentRoot(IPluginManager::Get().FindPlugin("ServerRecast")->GetBaseDir() / TEXT("Resources")); 48 | 49 | Style->Set("ServerRecast.PluginAction", new IMAGE_BRUSH(TEXT("ButtonIcon_40x"), Icon40x40)); 50 | 51 | return Style; 52 | } 53 | 54 | #undef IMAGE_BRUSH 55 | #undef BOX_BRUSH 56 | #undef BORDER_BRUSH 57 | #undef TTF_FONT 58 | #undef OTF_FONT 59 | 60 | void FServerRecastStyle::ReloadTextures() 61 | { 62 | if (FSlateApplication::IsInitialized()) 63 | { 64 | FSlateApplication::Get().GetRenderer()->ReloadTextureResources(); 65 | } 66 | } 67 | 68 | const ISlateStyle& FServerRecastStyle::Get() 69 | { 70 | return *StyleInstance; 71 | } 72 | -------------------------------------------------------------------------------- /Source/ServerRecast/Public/ExportNavMesh.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "ModuleManager.h" 7 | #include "Navmesh/RecastNavMeshGenerator.h" 8 | //#include "ExportNavMesh.generated.h" 9 | /** 10 | * 11 | */ 12 | 13 | struct FServerRecastGeometryCache 14 | { 15 | 16 | struct FHeader 17 | { 18 | FNavigationRelevantData::FCollisionDataHeader Validation; 19 | 20 | int32 NumVerts; 21 | int32 NumFaces; 22 | struct FWalkableSlopeOverride SlopeOverride; 23 | 24 | static uint32 StaticMagicNumber; 25 | }; 26 | 27 | FHeader Header; 28 | 29 | /** recast coords of vertices (size: NumVerts * 3) */ 30 | float* Verts; 31 | 32 | /** vert indices for triangles (size: NumFaces * 3) */ 33 | int32* Indices; 34 | 35 | FServerRecastGeometryCache() {} 36 | FServerRecastGeometryCache(const uint8* Memory); 37 | 38 | static bool IsValid(const uint8* Memory, int32 MemorySize); 39 | }; 40 | 41 | class SERVERRECAST_API FExportNavMesh : public FRecastNavMeshGenerator 42 | { 43 | 44 | public: 45 | void MyExportNavigationData(const FString& FileName); 46 | 47 | void GrowConvexHull(const float ExpandBy, const TArray& Verts, TArray& OutResult); 48 | 49 | void TransformVertexSoupToRecast(const TArray& VertexSoup, TNavStatArray& Verts, TNavStatArray& Faces); 50 | 51 | void ExportGeomToOBJFile(const FString& InFileName, const TNavStatArray& GeomCoords, const TNavStatArray& GeomFaces, const FString& AdditionalData); 52 | 53 | static FVector ChangeDirectionOfPoint(FVector Coord); 54 | }; 55 | -------------------------------------------------------------------------------- /Source/ServerRecast/Public/ServerRecast.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EngineMinimal.h" 7 | #include "ModuleManager.h" 8 | 9 | #include "AllowWindowsPlatformTypes.h" 10 | 11 | //The external headers and defines goes here 12 | 13 | #include "HideWindowsPlatformTypes.h" 14 | 15 | class FToolBarBuilder; 16 | class FMenuBuilder; 17 | 18 | 19 | class FServerRecastModule : public IModuleInterface 20 | { 21 | public: 22 | 23 | /** IModuleInterface implementation */ 24 | virtual void StartupModule() override; 25 | virtual void ShutdownModule() override; 26 | 27 | /** This function will be bound to Command. */ 28 | void PluginButtonClicked(); 29 | 30 | 31 | private: 32 | 33 | void AddToolbarExtension(FToolBarBuilder& Builder); 34 | void AddMenuExtension(FMenuBuilder& Builder); 35 | 36 | private: 37 | TSharedPtr PluginCommands; 38 | }; -------------------------------------------------------------------------------- /Source/ServerRecast/Public/ServerRecastCommands.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Framework/Commands/Commands.h" 7 | #include "ServerRecastStyle.h" 8 | 9 | class FServerRecastCommands : public TCommands 10 | { 11 | public: 12 | 13 | FServerRecastCommands() 14 | : TCommands(TEXT("ServerRecast"), NSLOCTEXT("Contexts", "ServerRecast", "ServerRecast Plugin"), NAME_None, FServerRecastStyle::GetStyleSetName()) 15 | { 16 | } 17 | 18 | // TCommands<> interface 19 | virtual void RegisterCommands() override; 20 | 21 | public: 22 | TSharedPtr< FUICommandInfo > PluginAction; 23 | }; 24 | -------------------------------------------------------------------------------- /Source/ServerRecast/Public/ServerRecastStyle.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Styling/SlateStyle.h" 7 | 8 | class FServerRecastStyle 9 | { 10 | public: 11 | 12 | static void Initialize(); 13 | 14 | static void Shutdown(); 15 | 16 | /** reloads textures used by slate renderer */ 17 | static void ReloadTextures(); 18 | 19 | /** @return The Slate style set for the Shooter game */ 20 | static const ISlateStyle& Get(); 21 | 22 | static FName GetStyleSetName(); 23 | 24 | private: 25 | 26 | static TSharedRef< class FSlateStyleSet > Create(); 27 | 28 | private: 29 | 30 | static TSharedPtr< class FSlateStyleSet > StyleInstance; 31 | }; -------------------------------------------------------------------------------- /Source/ServerRecast/ServerRecast.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class ServerRecast : ModuleRules 6 | { 7 | public ServerRecast(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | PublicDependencyModuleNames.AddRange( 18 | new string[] { 19 | "Core", 20 | "CoreUObject", 21 | "Engine", 22 | "InputCore", 23 | "HeadMountedDisplay", 24 | "UMG", 25 | "Navmesh", 26 | "NavigationSystem", 27 | "PhysX", 28 | "APEX" 29 | } 30 | ); 31 | 32 | PrivateIncludePaths.AddRange( 33 | new string[] { 34 | "ServerRecast/Public", 35 | "ServerRecast/Private", 36 | // ... add other private include paths required here ... 37 | } 38 | ); 39 | 40 | 41 | PrivateDependencyModuleNames.AddRange( 42 | new string[] 43 | { 44 | "Projects", 45 | "InputCore", 46 | "UnrealEd", 47 | "LevelEditor", 48 | "CoreUObject", 49 | "Engine", 50 | "Slate", 51 | "SlateCore", 52 | "NavigationSystem" 53 | // ... add private dependencies that you statically link with here ... 54 | } 55 | ); 56 | 57 | 58 | DynamicallyLoadedModuleNames.AddRange( 59 | new string[] 60 | { 61 | // ... add any modules that your module loads dynamically here ... 62 | } 63 | ); 64 | } 65 | } 66 | --------------------------------------------------------------------------------