{"id":16870227,"url":"https://github.com/jmgomez/nimforue","last_synced_at":"2025-03-19T15:37:36.395Z","repository":{"id":37579460,"uuid":"493737294","full_name":"jmgomez/NimForUE","owner":"jmgomez","description":"Nim plugin for UE5 with native performance, hot reloading and full interop that sits between C++ and Blueprints. This allows you to do common UE workflows like for example to extend any UE class in Nim and extending it again in Blueprint if you wish so without restarting the editor. The final aim is to be able to do in Nim what you can do in C++","archived":false,"fork":false,"pushed_at":"2024-10-29T17:46:31.000Z","size":20720,"stargazers_count":488,"open_issues_count":4,"forks_count":29,"subscribers_count":13,"default_branch":"devel","last_synced_at":"2024-10-29T19:01:57.106Z","etag":null,"topics":["gamedev","nim","unreal"],"latest_commit_sha":null,"homepage":"","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jmgomez.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"License.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-18T16:14:53.000Z","updated_at":"2024-10-29T17:46:35.000Z","dependencies_parsed_at":"2024-03-28T17:55:19.475Z","dependency_job_id":"745166bf-05bc-467e-994f-88925cf53f76","html_url":"https://github.com/jmgomez/NimForUE","commit_stats":{"total_commits":1421,"total_committers":10,"mean_commits":142.1,"dds":"0.34342012667135824","last_synced_commit":"8c62b045ea0546879b9e8d13b7f85b540dab5ff0"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgomez%2FNimForUE","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgomez%2FNimForUE/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgomez%2FNimForUE/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgomez%2FNimForUE/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jmgomez","download_url":"https://codeload.github.com/jmgomez/NimForUE/tar.gz/refs/heads/devel","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244290487,"owners_count":20429367,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gamedev","nim","unreal"],"created_at":"2024-10-13T15:03:17.229Z","updated_at":"2025-03-19T15:37:36.375Z","avatar_url":"https://github.com/jmgomez.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"./logo.png\" width=\"360\"  align=\"right\"\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://nimforue.pages.dev\"\u003eDocs\u003c/a\u003e - \u003ca href=\"https://discord.gg/smD8vZxzHh\"\u003eDiscord\u003c/a\u003e - \u003ca href=\"https://github.com/jmgomez/NimForUE/wiki/Roadmap\"\u003eRoadmap\u003c/a\u003e - \u003ca href=\"https://github.com/jmgomez/NimTemplate\"\u003eTemplate\u003c/a\u003e \n\u003c/p\u003e\n\n### DISCLAIMER ###\n\nThe plugin is being used to develop a Game but it isn't feature complete yet. \nTo get started there is a Third Person Template implementation in NimForUE: https://github.com/jmgomez/NimTemplate\n\n### Why NimForUE?\n\nThe core idea is to have a short feedback loop while having native performance and a modern language that can access all features Unreal provides. \n\nThe plugin outputs native dynamic libraries (DLLs) that are hooked into UnrealEngine for development. When releasing the code is statically linked as published as an Unreal native plugin. This approach make the plugin portable and fast. It can run on any platform that Unreal supports (not all tested). \n\nThe design philosophy is to not change any unreal conventions on the API side of things, so anyone that knows Unreal can reuse its knowledge. The code guidelines follow (for the most part) the Nim conventions when not in contradiction with the Unreal ones. \n\nIf you have any question or wants to know more and follow the updates:\n \n[Join us on the Discord group](https://discord.gg/smD8vZxzHh)\n\nIf you dont have Discord, you can also reach out at:\n\n[Twitter](https://twitter.com/_jmgomez_)\n\n\n### Why Nim?\n\n\nNim is fast and easy to read with a good type system and a fantastic macro system, and it also has the best C++ interop in the industry. \n\nThe compiler is incredibly fast, and it's about to get faster with incremental compilation on the works.\n\nThe performance is the same as with C++ because you are outputting optimized C++ with zero overhead.\n\nFully control the memory if you so desire (including move semantics). \n\nNim Type System has everything (and probably more) that you can expect from a typed lang: generics, sum types, constraints on those, and it even has C++-like concepts (my personal favorite feature from C++) it even has hints of dependent types.\n\nThe macro system is outstanding. Just to give you an idea, await/async are implemented as a library. The same applies to Pattern Matching. This means (as you will see below) that you can create *typed* DSLs for your Unreal Projects that use the semantics that better fit your project.\n\nNim compile time capabilities are so good that we were able to rebuild UHT (Unreal Header Tool) at Nim's compile time. \n\nThe C++ interoperability makes this plugin stand out from the rest as you can consume any native API and implement virtual functions which is the way that Unreal extends most engine APIs.\n\n\n\n\n### NimForUE 101 Playlist:\n[![NimForUE 101 Playlist](https://img.youtube.com/vi/j6N6WGt2lO0/0.jpg)](https://www.youtube.com/watch?v=NuB_PjxVisw\u0026list=PL_l806S1qgBLfGDn9khLMPFLE0k03ARoF)\n\n\n\n### Showcase at NimConf 2022:\n[![Showcase at NimConf 2022](https://img.youtube.com/vi/0b3ixaz2uOg/0.jpg)](https://youtu.be/0b3ixaz2uOg)\n\n\n\n### Showcase GameFromScratch\n[![Showcase GameFromScratch](https://img.youtube.com/vi/Cdr4-cOsAWA/0.jpg)](https://youtu.be/Cdr4-cOsAWA)\n\n\n\n## Examples\nThe whole Cpp ThirdPersonTemplate in Nim would be like this:\n\n```nim\n\n\nuClass ANimCharacter of ACharacter:\n  (Reinstance)\n  (config=Game)\n  uprops(EditAnywhere, BlueprintReadOnly, DefaultComponent, Category = Camera):\n    cameraBoom : USpringArmComponentPtr \n  uprops(EditAnywhere, BlueprintReadOnly, DefaultComponent, Attach=(cameraBoom, SpringEndpoint), Category = Camera):\n    followCamera : UCameraComponentPtr\n  uprops(EditAnywhere, BlueprintReadOnly, Category = Input):\n    defaultMappingContext : UInputMappingContextPtr\n    (jumpAction, moveAction, lookAction) : UInputActionPtr\n\n  defaults: # default values for properties on the cdo\n    capsuleComponent.capsuleRadius = 40\n    capsuleComponent.capsuleHalfHeight = 96\n    bUseControllerRotationYaw = false\n    characterMovement.jumpZVelocity = 700\n    characterMovement.airControl = 0.35\n    characterMovement.maxWalkSpeed = 500\n    characterMovement.minAnalogWalkSpeed = 20\n    characterMovement.brakingDecelerationWalking = 2000\n    characterMovement.bOrientRotationToMovement = true\n    cameraBoom.targetArmLength = 400\n    cameraBoom.busePawnControlRotation = true\n    followCamera.bUsePawnControlRotation = true\n\n  #Notice this override an actual C++ function that exists in the base type. \n  proc setupPlayerInputComponent(playerInputComponent : UInputComponentPtr) {.virtual, override.}  =    \n    let pc = ueCast[APlayerController](self.getController())\n    if pc.isNotNil():\n      let inputComponent = ueCast[UEnhancedInputComponent](playerInputComponent)\n      let subsystem = tryGetSubsystem[UEnhancedInputLocalPlayerSubsystem](pc).get()\n      subsystem.addMappingContext(self.defaultMappingContext, 0)\n      inputComponent.bindAction(self.jumpAction, ETriggerEvent.Triggered, self, n\"jump\")\n      inputComponent.bindAction(self.jumpAction, ETriggerEvent.Completed, self, n\"stopJumping\")\n      inputComponent.bindAction(self.moveAction, ETriggerEvent.Triggered, self, n\"move\")\n      inputComponent.bindAction(self.lookAction, ETriggerEvent.Triggered, self, n\"look\")\n      \n  ufuncs:\n    proc move(value: FInputActionValue) = \n      let \n        movementVector = value.axis2D()\n        rot = self.getControlRotation()\n        rightDir = FRotator(roll: rot.roll, yaw: rot.yaw).getRightVector()\n        forwardDir = FRotator(yaw: rot.yaw).getForwardVector()\n      self.addMovementInput(rightDir, movementVector.x, false) \n      self.addMovementInput(forwardDir, movementVector.y, false) \n\n    proc look(value: FInputActionValue) =\n      let lookAxis = value.axis2D()\n      self.addControllerYawInput(lookAxis.x)\n      self.addControllerPitchInput(lookAxis.y)\n\nuClass ANimGameMode of AGameModeBase:\n  proc constructor(initializer: FObjectInitializer) = #Similar to default but allows you to write full nim code\n    let classFinder = makeClassFinder[ACharacter](\"/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter\")\n    self.defaultPawnClass = classFinder.class\n\n```\n\n\n\nThis code can be found at src/examples/actorexample. There are more examples inside that folder. You can do `import examples/example` in from `game.nim` (see the NimTemplate) to play with it. \n```nim\n#Nim UClasses can derive from the same classes that blueprints can derive from.\n\nuClass AExampleActor of AActor:\n    (BlueprintType, Blueprintable) #Class specifiers follow the C++ convention. \n    uprops(EditAnywhere, BlueprintReadWrite): #you can declare multiple UPROPERTIES in one block\n        exampleValue : FString #They are declare as nim properties. \n        anotherVale : int #notice int in nim is int64. while in c++ it is int32.\n        anotherValueInt32 : int32 #this would be equivalent to int32\n        predValue : FString = \"Hello\" #you can assign a default value to a property.\n        predValueInt : int =  20 + 10 #you can even use functions (the execution is deferred)\n        nameTest : FString = self.getName() #you can even use functions within the actor itself. It is accessible via this or self.\n\n#In general when using the equal symbol in a uClass declaration, a default constructor will be generated.\n#you can specify a custom constructor if you want to by defining a regular nim function and adding the pragma uconstructor\n\nproc myExampleActorCostructor(self: AExampleActorPtr, initializer: FObjectInitializer) {.uConstructor.} =\n    UE_Log \"The constructor is called for the actor\"\n    self.anotherVale = 5\n    #you can override the values set by the default constructor too since they are added adhoc before this constructor is called.\n    self.predValue = \"Hello World\"\n\n#Notice that you rarelly will need to define a custom constructor for your class. Since the CDO can be set within the DSL. \n\n#UFunctions\n\n#UFunctions can be added by adding the pragma uFunc, and for each meata, another pragma:\n#Since in nim functions are separated from the type they are declared in, you need to specify the type as the first argument.\n\nproc myUFunction(self: AExampleActorPtr, param : FString) : int32 {. ufunc, BlueprintCallable .} = \n    UE_Log \"UFunction called\"\n    5\n\n#You can also use the uFunctions macro to declare multiple uFunctions at once. The preferred way is still to use them in an uClass block like shown above.\nuFunctions:\n    (BlueprintCallable, self:AExampleActorPtr) #you must specify the type and any shared meta like this.\n\n    proc anotherUFunction(param : FString) : int32 = 10 #now you can define the function as you normally would.\n    proc yetAnotherUFunction(param : FString) : FString = \n        self.getName() #you can access to the actor itself by the name you specify in the uFunctions macro.\n    \n    proc customPragma(param : FString) : int32 {. BlueprintPure .} = 10 #you can also specify custom pragmas per functions rather than creating a new block\n\n    proc callFromTheEditor() {. CallInEditor .} = \n        UE_Log \"Call from the editor\"\n        \n```\nWhich produces:\n![Blueprint](https://media.discordapp.net/attachments/844939530913054752/1004338096160120913/unknown.png)\n\n## Install\n\n1. Clone the repo inside `YourGame/Plugins`\n2. Run `nimble nuesetup` from `YourGame/Plugins/NimForUE`\n\nA video showcasing the installation process in more detail:\n\n[![Installing NimForUE video](https://img.youtube.com/vi/sT8-Oz7k-VU/0.jpg)](https://youtu.be/sT8-Oz7k-VU)\n\n\n## VSCode setup\n\nFor Intellisense from nimsuggest, install the `nim-lang.org` extension.\n\nWhen setting up a project:\n  - Create a new workspace (it can be in the UE project folder).\n  - File\u003e`Add Folder to Workspace`:\n    * The `NimForUE` directory that contains `game.nim`\n    * The `NimForUE` plugin directory.\n    * The `imported` directory in NimForUE plugin directory i.e `.\\src\\nimforue\\unreal\\bindings\\imported`\n\n## Debugging in Visual Studio\n\nCompile your game with the debug flag, `nue game --debug`.\nThen you can debug the game with nim source maps in Visual Studio. \n\nTo switch the project's target configuration use the `targetconfig` task.\n\nTo debug the engine along with your project, use `nue targetconfig --debug` and `nue targetconfig --dev` to switch back to Development. \nThis will modify the NimForUE json config file and recompile the plugin and game dll.\n\n## Troubleshooting\n\n### Windows\n- The project path must not be too long, the default location `C:/Users/\u003cUSER\u003e/Unreal Projects` is too long for instance.\n\nYou can move the \"Unreal Projects\" folder to the root of a drive and symlink it back to the user document directory if needed by other process / applications.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmgomez%2Fnimforue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmgomez%2Fnimforue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmgomez%2Fnimforue/lists"}