diff --git a/cspell.json b/cspell.json index 89eaa0cb..b6fe149e 100644 --- a/cspell.json +++ b/cspell.json @@ -38,6 +38,7 @@ "FACTORYGAME", "favorited", "Feyko", + "fgcheck", "fgrecipe", "FGUnlock", "ficsit", @@ -130,6 +131,7 @@ "hte", "reccomend", "outselves", - "favortied" + "favortied", + "destory" ] } diff --git a/lychee.toml b/lychee.toml index ac879067..201d4225 100644 --- a/lychee.toml +++ b/lychee.toml @@ -24,8 +24,10 @@ exclude = [ "https://www.audiokinetic.com/en/download/", # unable to get local issuer certificate "https://questions.satisfactorygame.com/", - # 403s despite being valid pages - "https://stackoverflow.com/questions/" + # 403s despite being valid page + "https://stackoverflow.com/questions/", + # 403s despite being valid page + "https://www.unrealengine.com/en-US/ue-on-github" ] # Exclude these filesystem paths from getting checked. diff --git a/modules/ROOT/images/DedicatedServers/SMM2_vs_SMM3.png b/modules/ROOT/images/DedicatedServers/SMM2_vs_SMM3.png new file mode 100644 index 00000000..9e5f898f Binary files /dev/null and b/modules/ROOT/images/DedicatedServers/SMM2_vs_SMM3.png differ diff --git a/modules/ROOT/images/DedicatedServers/SMM_FTP.png b/modules/ROOT/images/DedicatedServers/SMM_FTP.png index 618f84dc..b133eea5 100644 Binary files a/modules/ROOT/images/DedicatedServers/SMM_FTP.png and b/modules/ROOT/images/DedicatedServers/SMM_FTP.png differ diff --git a/modules/ROOT/images/DedicatedServers/SMM_SFTP.png b/modules/ROOT/images/DedicatedServers/SMM_SFTP.png index 7d6ce0fc..01fa4ded 100644 Binary files a/modules/ROOT/images/DedicatedServers/SMM_SFTP.png and b/modules/ROOT/images/DedicatedServers/SMM_SFTP.png differ diff --git a/modules/ROOT/images/DedicatedServers/SMM_SMB.png b/modules/ROOT/images/DedicatedServers/SMM_SMB.png new file mode 100644 index 00000000..a322716d Binary files /dev/null and b/modules/ROOT/images/DedicatedServers/SMM_SMB.png differ diff --git a/modules/ROOT/images/Development/UpdatingGuides/WwiseMigrationPopupScreenshot.png b/modules/ROOT/images/Development/UpdatingGuides/WwiseMigrationPopupScreenshot.png new file mode 100644 index 00000000..93acc3ab Binary files /dev/null and b/modules/ROOT/images/Development/UpdatingGuides/WwiseMigrationPopupScreenshot.png differ diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 6bff04dc..0c8aaa37 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -41,6 +41,7 @@ *** xref:Development/Cpp/setup.adoc[Setup] *** xref:Development/Cpp/debugging.adoc[Debugging] *** xref:Development/Cpp/hooking.adoc[Hooking] +// TODO *** xref:Development/Cpp/GettingBpData.adoc[Working with Assets and Blueprint-Defined Data from {cpp}] *** xref:Development/Cpp/thirdparty.adoc[Third Party Libraries] ** xref:Development/Modeling/index.adoc[3D Modeling] diff --git a/modules/ROOT/pages/CommunityResources/IconGenerator.adoc b/modules/ROOT/pages/CommunityResources/IconGenerator.adoc index 47284d72..6d22d2b8 100644 --- a/modules/ROOT/pages/CommunityResources/IconGenerator.adoc +++ b/modules/ROOT/pages/CommunityResources/IconGenerator.adoc @@ -17,7 +17,7 @@ https://github.com/DavidHGillen/Satisfactory_IconCapture[GitHub page]. Kyrium's tool captures images using a render target, allowing capture of materials with opacity. -You can learn more about how to download and use the plugin on its https://git.kyrium.space/sf-modding/publictools/kiconmaker[Gitlab page]. +You can learn more about how to download and use the plugin on its https://github.com/Satisfactory-KMods/KIconMaker[GitHub page]. == Nog's Icon Generator diff --git a/modules/ROOT/pages/Development/BeginnersGuide/CreateGitRepo.adoc b/modules/ROOT/pages/Development/BeginnersGuide/CreateGitRepo.adoc index 60d6420d..186ee9d8 100644 --- a/modules/ROOT/pages/Development/BeginnersGuide/CreateGitRepo.adoc +++ b/modules/ROOT/pages/Development/BeginnersGuide/CreateGitRepo.adoc @@ -261,13 +261,16 @@ This section assumes that you already know about the repository creating, commit Use the git tool you are comfortable with. -It is suggested that you not enable Unreal's version control integration because it works at the project level and not the plugin level. - -Be extra careful with merge conflicts and branches in the context of Unreal Engine. -Most Unreal Engine asset files are raw binary files, which means git diffing them is difficult. -Panakotta has directions on using UE as diff tool -https://gist.github.com/Panakotta00/c90d1017b89b4853e8b97d13501b2e62[here], -but it's best to totally avoid merge conflicts wherever possible. +Be mindful of merge conflicts and branches in the context of Unreal Engine. +Most Unreal Engine asset files are raw binary files, which means git diffing them must be done inside the editor. +The editor has a pretty decent built-in merge resolver, +but you must be able to open the editor to use it. +You'll have to resolve conflicts and compile errors on the {cpp} side first +to build a working Development Editor copy to open, +and the editor could get confused if information from {cpp} parent classes change. + +Panakotta has directions on setting up UE to launch in diff mode as a git diff/merge tool +https://gist.github.com/Panakotta00/c90d1017b89b4853e8b97d13501b2e62[here]. ## UE4GitDiff diff --git a/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/buildable.adoc b/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/buildable.adoc index 7cf858a7..30a40eb1 100644 --- a/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/buildable.adoc +++ b/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/buildable.adoc @@ -34,12 +34,14 @@ Later on, you can write your own to allow upgrading buildings or to have snappin You can learn more about how holograms work on the xref:Development/Satisfactory/BuildableHolograms.adoc[Buildable Holograms] page. ==== -As you can see in the `Components` pane in the top left, the actor already contains a few components. But not any visuals, so, now add a new static mesh component in the center of the viewport. The build gun uses the origin when targeting the mesh to be built or snapped. +As you can see in the `Components` pane in the top left, the actor already contains a few components. +But not any visuals, so, now add a new instanced static mesh component in the center of the viewport. +The build gun uses the origin when targeting the mesh to be built or snapped. You can use link:{attachmentsdir}/BeginnersGuide/simpleMod/Mesh_DocBuild.fbx[this example Mesh], the Plantpot of Knowledge, for your buildable. This Actor is also where you can define the snapping area and the clearance area, but we won't do that for now. Look to other machines and examples for inspiration as there are several relevant settings to make those behaviors work correctly. -== Make it paintable +== Make it Paintable We want to make our buildable xref:Development/Satisfactory/Paintable.adoc[paintable], meaning, able to be painted it with the paint gun. Because the `FGBuildable`-class already provides a basic implementation for that, we just need our buildable's mesh to use the `MI_Factory_Base_01` material. The provided example mesh already provides a proper UV map for said material, so you will not need to edit the UVs of the provided mesh. You will need to do so for your own models. More info on the materials already in the game can be found at xref:Development/Modeling/MainMaterials.adoc[Main Materials] documentation page. @@ -76,6 +78,8 @@ then add Ingredients entries to define the cost of constructing the building. The Product field should contain exactly one entry - the FGBuildingDescriptor asset you just created for your buildable. +Don't forget to list your newly created recipe in the unlocks of a Schematic otherwise it won't be registered. + That's it! You don't need to register anything else. When the recipe gets loaded, everything else also gets loaded and the buildable in the save file has soft references to the classes, and if they get loaded also the classes like our newly created buildable get loaded. == Trying it Out diff --git a/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/recipe.adoc b/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/recipe.adoc index 2b032934..ade6766b 100644 --- a/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/recipe.adoc +++ b/modules/ROOT/pages/Development/BeginnersGuide/SimpleMod/recipe.adoc @@ -98,7 +98,7 @@ M Overridden Category:: Categories control what subsection a recipe appears under in the recipe list. By default, recipes take on the category of their first product item. {blank} + - We'll leave this at `None` so that it sticks with the default category of the Leaves item. + We'll leave this at `None` so that it sticks with the default category of the Wood item. * {blank} + M Manufacturing Menu Priority:: diff --git a/modules/ROOT/pages/Development/BeginnersGuide/dependencies.adoc b/modules/ROOT/pages/Development/BeginnersGuide/dependencies.adoc index 3281eb33..ed92cdda 100644 --- a/modules/ROOT/pages/Development/BeginnersGuide/dependencies.adoc +++ b/modules/ROOT/pages/Development/BeginnersGuide/dependencies.adoc @@ -138,14 +138,6 @@ as well as making sure you're logged into your linked GitHub account when you fo [id="UnrealLinker"] === Link Your GitHub Account to Our Repository -[WARNING] -==== -**Update 8/SML3.5 Special Note**: -If you have trouble getting the linker to work, -please contact us on the Discord. -It's a very recent addition to the setup process and we're still ironing out the bugs. -==== - In addition to the changes Coffee Stain has made to Unreal Engine, the modding community has also applied some engine changes of our own. @@ -335,10 +327,7 @@ This is the *latest* version of the docs. Early Access and Experimental are currently both the same version - Update 8. -You should download a zip either of the **`dev` branch`**, -which will have the latest changes and fixes, -or the **`master` branch** . - +You should download a zip either of the **`dev` branch** or the **`master` branch**. Of those two, you probably want whichever branch was pushed to most recently, which you can see https://github.com/satisfactorymodding/SatisfactoryModLoader/branches[on the GitHub repository]. diff --git a/modules/ROOT/pages/Development/BeginnersGuide/project_setup.adoc b/modules/ROOT/pages/Development/BeginnersGuide/project_setup.adoc index a6643707..641f607c 100644 --- a/modules/ROOT/pages/Development/BeginnersGuide/project_setup.adoc +++ b/modules/ROOT/pages/Development/BeginnersGuide/project_setup.adoc @@ -64,20 +64,18 @@ or you will have to repeat some of the setup process again. ==== This is the *latest* version of the docs. -If you want to develop mods for Update 8, -you should clone either the **`dev` branch**, -which will have the latest changes and fixes, -or the **`master` branch** . +Early Access and Experimental are currently both the same version - Update 8. +You should clone either the **`dev` branch** or the **`master` branch**. Of those two, you probably want whichever branch was pushed to most recently, which you can see https://github.com/satisfactorymodding/SatisfactoryModLoader/branches[on the GitHub repository]. -==== -If you're still uncertain which to download, ask us on the Discord. +If you're still uncertain which to clone, ask us on the Discord. +==== https://github.com/satisfactorymodding/SatisfactoryModLoader/[Here] is a link to the repository to clone. Again, make sure to clone the correct branch - it will probably start you on the `master` branch by default -and you may have to switch branches to the correct one. +and you may have to switch branches to the branch you actually intend to clone. The directory is ready for use as soon as the clone is complete. Move on to the link:#_setting_up_wwise[next heading]. @@ -348,7 +346,7 @@ you need to go back and re-do the link:#_setting_up_wwise[Wwise integration step Make sure that your project folder is not stored in a folder path that contains unicode characters. Review the directions in the link:#_starter_project[Starter Project] section. -===== Entire computer locks up while compiling +==== Entire computer locks up while compiling The fix for this rare but troublesome issue seems to vary for each person that encounters it. Try the following: diff --git a/modules/ROOT/pages/Development/Cpp/GettingBpData.adoc b/modules/ROOT/pages/Development/Cpp/GettingBpData.adoc new file mode 100644 index 00000000..85d171c9 --- /dev/null +++ b/modules/ROOT/pages/Development/Cpp/GettingBpData.adoc @@ -0,0 +1,117 @@ += Working with Assets and Blueprint-Defined Data from {cpp} + +[NOTE] +==== +You have found a hidden docs page! + +This page is still a work in progress. + +If you have any feedback, please let us know in the Discord. +==== + +When working with {cpp} code and hybrid mods, you may encounter situations where you need to reference and operate on assets. +This poses a complication, as assets and their fields don't 'exist' yet when writing {cpp} code, only in the blueprint code. + +Generally, if you need to access a class/field in {cpp}, +have the parent class defined on the {cpp} side that define the fields you want to work with in {cpp}, +then populate them in a blueprint child version of the class. +TODO example, TODO move this to a section? + +There are many solutions to this problem, each with their own tradeoffs. +We have listed them in order of what we suggest below: + +[id="HybridMod"] +== Approach 0: Hybrid Mod + +Does the operation you're performing need to happen on the {cpp} side? +If you can work with the data on the blueprint code side instead, +you can avoid this problem. + +Consider if the performance gains from doing the operation in {cpp} are worth the added complexity of this problem. + +TODO example + +[id="DataAsset"] +== Approach 1: Data Asset + +Create a subclass of `UDataAsset` on the cpp side + +Define fields for values you want to pass across to the {cpp} side. +Add `UPROPERTY(EditAnywhere, BlueprintReadWrite)` or BlueprintReadOnly to the properties you want to access + +Create a field on your Game Instance Module that holds a reference to your Data Asset +Create the data asset on the BP side + populate its fields there + populate the field in your game instance module with it + +To access the data, get your instance module, get data class, get field. + +TODO mircea mentioned static getter? + +TODO example + +[source,h] +---- +#pragma once +#include "CoreMinimal.h" +#include "Resources/FGItemDescriptor.h" +#include "Buildables/FGBuildablePowerStorage.h" +#include "ApBlueprintDataBridge.generated.h" + +/** + * Data asset definition to allow passing assets from blueprint to the C++ side without having to LoadObject hard code them + */ +UCLASS(NotBlueprintable, BlueprintType) +class UApBlueprintDataBridge : public UDataAsset { + GENERATED_BODY() +public: + + // Power Storage building asset for UI modifications + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TSubclassOf PowerStorageBuilding; + + // Item to use as the Archipelago Blocker + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TSubclassOf BlockerItem; + + // Item to use as the replacement for Somersloops + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TSubclassOf ExplorationPickupItem_Somersloop; + + // Item to use as the replacement for Mercer Spheres + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TSubclassOf ExplorationPickupItem_Mercer; +}; +---- + +[id="GameInstanceField"] +== Approach 2: Field on Game Instance Module + +Similar to Approach 1, putting + +This can get messy pretty fast because you're adding a lot of fields to your game instance module. + +It also causes stuff to preload sooner than it probably needs to -> hitches? + +TODO example + +[id="FindObject"] +== Approach 3: Find Object and Load Object + +Generally don't use this with hardcoded strings because it's very brittle, +if you move the asset it will no longer point to something and Unreal can't notice to auto-fix it up for you. + +The only approach that can find assets with a location determined at runtime. + +Okayish for base-game stuff that Should™ never move. + +Example from ContentLib: + +[source,h] +---- +UClass* Class = FindObject(FindPackage(nullptr, TEXT("/Game/")), TEXT("BP_UnlockInfoOnly_C"), false); +if (!Class) { + Class = LoadObject(nullptr, TEXT("/Game/FactoryGame/Unlocks/BP_UnlockInfoOnly.BP_UnlockInfoOnly_C")); + if (!Class) { + UE_LOG(LogContentLib, Fatal, TEXT("CL: Couldn't find BP_UnlockInfoOnly_C wanting to Add to %s"), *Schematic->GetName()) + } +} +---- diff --git a/modules/ROOT/pages/Development/Cpp/debugging.adoc b/modules/ROOT/pages/Development/Cpp/debugging.adoc index 658f44e4..fcbd3e77 100644 --- a/modules/ROOT/pages/Development/Cpp/debugging.adoc +++ b/modules/ROOT/pages/Development/Cpp/debugging.adoc @@ -80,9 +80,11 @@ When used correctly, they can help catch bugs early and make debugging easier by pinpointing the exact location where an assumption was violated. You can read more about these utilities (and see usage examples) on the relevant -https://docs.unrealengine.com/4.26/en-US/ProgrammingAndScripting/ProgrammingWithCPP/Assertions/[Unreal Engine documentation page]. +https://dev.epicgames.com/documentation/en-us/unreal-engine/asserts-in-unreal-engine?application_version=5.2[Unreal Engine documentation page]. Note that Assert and Check statements will crash the game if their conditions are not met, however, Ensure statements will allow the game to keep running. +You should generally use `fgcheck()`, a custom assert implemented by Coffee Stain, instead of Unreal's standard `check()` because fgcheck is enabled in Shipping builds. + When SML is installed and a debugger is attached, Checks and Ensures will be caught by the debugger. This is not normally the case in Shipping builds of Unreal Engine games; this behavior is enabled by SML. diff --git a/modules/ROOT/pages/Development/ModLoader/AccessTransformers.adoc b/modules/ROOT/pages/Development/ModLoader/AccessTransformers.adoc index 90fef7df..a5c05d8d 100644 --- a/modules/ROOT/pages/Development/ModLoader/AccessTransformers.adoc +++ b/modules/ROOT/pages/Development/ModLoader/AccessTransformers.adoc @@ -49,16 +49,15 @@ Creates the public methods `FORCEINLINE PropertyType GetSomeProperty() { return This is beneficial when you are trying to access a field and you are not in a class to use Friend for. Below is an example from PowerSuit for the FEquipmentStats struct. +// cspell:ignore Getm [source,cpp] ---- // Instead of this ... SuitCostToUse = Parent->EquipmentParent->mCostToUse; // ... use this -SuitCostToUse = Parent->EquipmentParent.GetCostToUse(); +SuitCostToUse = Parent->EquipmentParent.GetmCostToUse(); ---- -Note that the generated methods lack the `m` from the original property name. - === BlueprintReadWrite Adds `BlueprintReadWrite` to the specified UPROPERTY, allowing you to access that property from blueprints (it cannot be added to a non-UPROPERTY field). It also bypasses the private BPRW conflict check (which is compile time only, it does not affect the editor, or the game), so that no changes to the game headers are required. diff --git a/modules/ROOT/pages/Development/Modeling/index.adoc b/modules/ROOT/pages/Development/Modeling/index.adoc index 916c294a..e181e2d1 100644 --- a/modules/ROOT/pages/Development/Modeling/index.adoc +++ b/modules/ROOT/pages/Development/Modeling/index.adoc @@ -28,7 +28,7 @@ PBR Materials:: + Texture Atlases:: Helps understand the painting system (which allows you to change factory colours) and allows you to use decals on your models. - https://blog.immersed.team/texture-atlasing-an-inside-look-at-optimizing-3d-worlds-8a07145856d7[Tutorial Article] + https://web.archive.org/web/20200101133356/https://blog.immersed.team/texture-atlasing-an-inside-look-at-optimizing-3d-worlds-8a07145856d7?gi=9b479f256ecc[Tutorial Article] * {blank} + Normal Map Decals:: diff --git a/modules/ROOT/pages/Development/Satisfactory/AbstractInstance.adoc b/modules/ROOT/pages/Development/Satisfactory/AbstractInstance.adoc index 2ed71650..d9f70f67 100644 --- a/modules/ROOT/pages/Development/Satisfactory/AbstractInstance.adoc +++ b/modules/ROOT/pages/Development/Satisfactory/AbstractInstance.adoc @@ -42,3 +42,72 @@ You may also find the following properties useful: * Use Relative Transform to apply a transform this specific mesh relative to the overall building. * If the building has no components set `mContainsComponents` on the buildable to false * The "apply random offset" properties can be used to mitigate z-fighting issues when multiple copies of the building overlap. + +[id="Examples"] +== Examples for Custom Implementations + +You may find the below examples useful +if you're planning to implement Abstract Instances on things that don't inherit from `AFGBuildable`. + +=== Storing Instance Handles + +Custom implementations should define a field to hold instance handles. +Consider `TArray< struct FInstanceHandle* > mInstanceHandles` used by `AFGBuildable`. + +=== Resolve Hits on Abstract Instances + +[NOTE] +==== +Hits in Holograms are already resolved and don't need this implementation. +==== + +To resolve the hit, we have two options: + +- Hit result `bool ResolveHit( const FHitResult& Result, FInstanceHandle& OutHandle )` +- Overlap Result `bool ResolveOverlap( const FOverlapResult& Result, FInstanceHandle& OutHandle )` + +```cpp +AMyModActor::ResolveHitResult(const FHitResult& Hit) { + AAbstractInstanceManager* Manager = AAbstractInstanceManager::Get(GetWorld()); + fgcheck(Manager); + + FInstanceHandle OutHandle; + if(Manager->ResolveHit(Hit, OutHandle)) { + // We hit a abstract instance, so we can get information, like the owner, from that handle + OutHandle.GetOwner() // AActor* who owns the Instance + } + // We don't hit a abstract instance so we can continue with the Hit +} +``` + +=== Create Abstract Instances at Runtime + +```cpp +static void SetInstanceFromDataStatic( AActor* OwnerActor, const FTransform& ActorTransform, const FInstanceData& InstanceData, FInstanceHandle* &OutHandle, bool bInitializeHidden = false ); + +AMyModActor::CreateInstanceFromMesh(UStaticMesh* Mesh) { + // Prepare the InstanceData with a given Mesh at the relative Transform 0. + FInstanceData InstanceData; + InstanceData.StaticMesh = Mesh; + InstanceData.Mobility = EComponentMobility::Static; + InstanceData.RelativeTransform = FTransform(); + InstanceData.NumCustomDataFloats= 20; + + FInstanceHandle* Handle; + AAbstractInstanceManager::SetInstanceFromDataStatic(this, GetActorTransform(), InstanceData, Handle); + + // You should add this Handle to the array so we can destroy them if the actor is destroyed (for example, dismantled). + mInstanceHandles.Add(Handle); +} +``` + +=== Destroy Abstract Instances at Runtime + +```cpp +static void RemoveInstances( UObject* WorldContext, TArray& Handles, bool bEmptyHandleArray = true ); + +AMyModActor::ClearInstances(UStaticMesh* Mesh) { + // Will remove/destroy all instances and empty mInstanceHandles. + AAbstractInstanceManager::RemoveInstances( GetWorld( ), mInstanceHandles ); +} +``` diff --git a/modules/ROOT/pages/Development/Satisfactory/Multiplayer.adoc b/modules/ROOT/pages/Development/Satisfactory/Multiplayer.adoc index fc5de4ed..ad63fc51 100644 --- a/modules/ROOT/pages/Development/Satisfactory/Multiplayer.adoc +++ b/modules/ROOT/pages/Development/Satisfactory/Multiplayer.adoc @@ -51,6 +51,24 @@ contains some examples of correctly adding multiplayer functionality to mods. The examples are not exhaustive, but they should help you get started. +== Checking for Authority + +The video explains the concept of network authority. + +To check if your code has authority, use Actor 'Has Authority'. +If you don't have an actor to check against, +consider using the return of GameplayStatics 'Get Game State' as the actor. + +=== Avoid Using Player Controller Index 0 + +Keep in mind that dedicated servers have no player controller, +so you should generally avoid using GameplayStatics 'Get Player Controller' with index 0 in your code. +For example, don't use its returned controller as an input for Has Authority, +and don't get its pawn to check Is Locally Human Controlled. + +It's fine to use player controller index 0 for user interface related tasks +since that code should only be running on sides that have a valid player controller index 0. + [id="RPCs"] == Remote Procedure Calls (RPCs) @@ -234,6 +252,25 @@ which Arch has informed us is planned to be phased out soon. If you have questions about this system, please ask about it on the discord, as it's not worth documenting something that will be removed so soon. +== Replicated Maps + +For unknown reasons, Unreal does not provide systems that allow TMaps to be replicated. +There are multiple approaches you can implement yourself to work around this: + +* Replicating an array of custom structs which have properties for key and value. + The host can use a regular map, updating this array in response to map changes. + On the client, implement the OnRep callback and construct a map from the array. +* If your keys can be computed from your values, such as a map containing FGBuildables by name, + replicate just an array of values and construct a map from them in the OnRep callback. +* A more performant approach would involve creating a custom (replicating) struct to hold the map, + then writing custom NetSerialize and NetDeltaSerialize overrides to efficiently handle replication of partial updates. + Such an approach is most certainly not for the faint of heart, though. + If your map is updating so often that the overhead of converting it to/from an array is important, + reconsider if you really need to replicate all that data, and if you would encounter network problems first. + +Note that replicating one array of keys and one array of values is not suggested +because changes to each array are not guaranteed to arrive at the same time. + == Appendix Additional information on various topics. diff --git a/modules/ROOT/pages/Development/TestingResources.adoc b/modules/ROOT/pages/Development/TestingResources.adoc index 01e7b3b6..dfe003f8 100644 --- a/modules/ROOT/pages/Development/TestingResources.adoc +++ b/modules/ROOT/pages/Development/TestingResources.adoc @@ -166,6 +166,8 @@ You must load with the `-offline` flag and use a Map Travel URL with the `?liste For example, `open Persistent_Level?loadgame=NameOfYourSaveGame?listen`. Remember that Session Settings are stored in the Map Travel URL as well so the defaults will be used if you don't specify them directly in the travel URL here. + +Consider locally hosting your own dedicated server for multiplayer testing instead. ==== Locally testing multiplayer functionality requires running two copies of the game at once. @@ -191,29 +193,19 @@ The link:#LaunchScript[launch script] demonstrates how to make the game to autom as opposed to the main menu, cutting down on load time and clicks when testing your mod. However, you will need to tweak it slightly if the level you want to load is a custom level. -To do this, you'll need to either need to modify the powershell script, -create a file with some configuration settings -or add them to the default game configuration. - -To get started, create a `.ini` file in a convenient location -(such as your Satisfactory game install directory) -that contains the following: +Notice that the powershell script's loadLatestSave option creates an ini file on the fly +containing instructions to load into a specific save file and GameDefaultMap. +You'll either need to modify the powershell script to point to your custom level +or create your own ini file for it to use instead. -``` -[/Script/EngineSettings.GameMapsSettings] -LocalMapOptions=??skipOnboarding?loadgame=LastLight_autosave_0 -GameDefaultMap=/Game/FactoryGame/Map/GameLevel01/Persistent_Level.Persistent_Level -GameInstanceClass=/Script/FactoryGame.FGGameInstance -``` +First, you'll need to find the path to use for your custom level. +It's based on the level's asset path. +For example, https://github.com/Nogg-aholic/NogsLevel/blob/master/Content/NogsLevel.umap[Nog's Level's level asset is at the content root], +so its path is `/NogsLevel/NogsLevel.NogsLevel`. +https://github.com/satisfactorymodding/SatisfactoryModLoader/blob/master/Mods/ExampleMod/Content/Maps/ExampleLevel/ExampleLevel.umap[Example Level's is a few layers of folder deep], +it's path is `/ExampleMod/Maps/ExampleLevel/ExampleLevel.ExampleLevel`. -In place of `LastLight_autosave_0` you should put the name of your desired save file. -Note that loading last autosaves of a map works as well if you format it correctly. -The example will load the latest autosave of a save called `LastLight`. - -Note that doing this will prevent you from returning to the main menu in that game session - -when you try to do so, you will instead re-load your selected game save. - -There are a few other flags you can use as well: +While you're at it, there are a few other flags you can use to customize the loading process: +++
+++ FG Map Options Switches from Archengius: @@ -246,13 +238,18 @@ Apparently it disables EOS sockets and makes the game fall back to normal IPv4 s .... +++
+++ -You can launch the game with these settings in one of two ways. +=== Option 1: Modify Powershell Script's Automatic ini Generation + +Alter the `Add-Content` instruction that adds a `GameDefaultMap` to point to the asset path of your custom level. +Note that this requires you to use the loadLatestSave flag (since that's what causes the script to generate the ini file) +or modify the script to use the ini file under other conditions. + +=== Option 2: Use Your Own ini File -=== Option 1 - Custom Configuration with Startup Script +Note how the powershell script uses the EngineINI option to point to an Engine.ini file to use when launching the game. -You can launch the game from command line -with the path to your configuration file -specified in the `EngineINI` command flag. +You can manually write an ini file and modify the powershell script to always launch the game with it, +or, launch separate from the powershell script by writing your own command. For example, if your file was called `LoadMapEngineConfiguration.ini`, your launch command could look like this: @@ -261,12 +258,12 @@ your launch command could look like this: "D:\SatisfactoryExperimental\FactoryGame\Binaries\Win64\FactoryGame-Win64-Shipping.exe" -EpicPortal -NoMultiplayer -Username=Player1 EngineINI="D:\SatisfactoryExperimental\LoadMapEngineConfiguration.ini" ``` -Note that you will have to modify this example command +Note that you will have to modify this example command so that it points to where you have the game installed. You might want to save it in a batch file or powershell script for easy execution later. -=== Option 2 - Add to Default Game Configuration +=== Option 3 - Add to Default Game Configuration Instead of creating a new file for your configuration, you can edit your default game configuration, found at diff --git a/modules/ROOT/pages/Development/UpdatingFromSml34.adoc b/modules/ROOT/pages/Development/UpdatingFromSml34.adoc index 75d63af6..26ea5038 100644 --- a/modules/ROOT/pages/Development/UpdatingFromSml34.adoc +++ b/modules/ROOT/pages/Development/UpdatingFromSml34.adoc @@ -295,7 +295,7 @@ If your project contains any Wwise stubs or assets, you may be greeted with a popup upon opening the project or opening an asset that references the Wwise asset. -image:https://media.discordapp.net/attachments/1036634533077979146/1131263355089322054/image.png[Drejn screenshot of Wwise popup] +image:Development/UpdatingGuides/WwiseMigrationPopupScreenshot.png[Screenshot of Wwise popup] You can safely cancel or close the prompt to take no action. However, you may need to delete any Wwise assets you have in your mod, diff --git a/modules/ROOT/pages/Development/UpdatingFromSml36.adoc b/modules/ROOT/pages/Development/UpdatingFromSml36.adoc index d9edba9c..2eb7a470 100644 --- a/modules/ROOT/pages/Development/UpdatingFromSml36.adoc +++ b/modules/ROOT/pages/Development/UpdatingFromSml36.adoc @@ -27,7 +27,7 @@ If you are updating your mod **directly from Update 7 (SML 3.4.x) to Update 8**, there are more steps to follow and more changes you should be aware of. Make sure to read the xref:Development/UpdatingFromSml34.adoc[Updating from SML 3.4.1] guide -and xref:Development/UpdatingFromSml34.adoc[Updating from SML 3.5.1] guide +and xref:Development/UpdatingFromSml35.adoc[Updating from SML 3.5.1] guide first! [IMPORTANT] diff --git a/modules/ROOT/pages/ForUsers/DedicatedServerSetup.adoc b/modules/ROOT/pages/ForUsers/DedicatedServerSetup.adoc index bbc1c52b..6bada078 100644 --- a/modules/ROOT/pages/ForUsers/DedicatedServerSetup.adoc +++ b/modules/ROOT/pages/ForUsers/DedicatedServerSetup.adoc @@ -51,22 +51,29 @@ the Mod Manager and ficsit-cli _should_ be able to interact with them normally. With this in mind, continue to the link:#GetModManager[next section]. [id="GetModManager"] -== Install a Mod Manager +== Use a Mod Manager to Connect to the Server Both Satisfactory Mod Manager (version 3.0.0 and up) and ficsit-cli can be used to manage mods on a remote server installation as long as you have network filesystem or (s)ftp access to the server. + You could also install ficsit-cli on the server and interact with its file system directly via its terminal user interface. [id="GetModManager_SMM"] === Satisfactory Mod Manager -// cspell:ignore CIFS -[NOTE] +[IMPORTANT] ==== -SMM cannot currently connect to servers by filesystem path. -This includes **local servers** (on your computer) and SMB/CIFS or network mounts. -Use ficsit-cli for this in the mean time. +Since dedicated Server support is still a work in progress, +there are TWO different versions of Satisfactory Mod Manager available! + +- SMM2 is the one automatically downloaded when you visit https://smm.ficsit.app/. It doesn't support dedicated servers. +- SMM3 is a pre-release you must manually download from https://github.com/satisfactorymodding/SatisfactoryModManager/releases. + +You must download SMM3 to manage dedicated servers via SMM. +If you don't want to use SMM3 yet, use ficsit-cli instead. + +image:DedicatedServers/SMM2_vs_SMM3.png[Satisfactory Mod Manager 2 vs 3 comparison] ==== If using the Mod Manager to manage your server: @@ -74,8 +81,8 @@ If using the Mod Manager to manage your server: . xref:ForUsers/SatisfactoryModManager.adoc[Download and install the Satisfactory Mod Manager]. . Open the Mod Manager. . In the left panel, under Other, select "Manage Servers". - * If you don't see this option, ensure that you have installed the latest version of the Mod Manager, - as only versions 3.0.0 and up support this feature. + * Don't see this option? Follow the steps in the "Important" box above to get the right version of Satisfactory Mod Manager. + * Note that if your server is locally installed through Steam or Epic, the mod manager may automatically detect it, allowing you to skip the below step of manually adding it. . Enter server connection details in the popup window. * Decide what method to select and what to enter by reading the link:#FileTransferMethods[File Transfer Methods] section, @@ -101,16 +108,7 @@ If using ficsit-cli to manage your server: b. If ficsit-cli is installed on the server, enter the file system path, for example `D:\SatisfactoryDS` or `/opt/SatisfactoryDedicatedServer`. . The server will now appear as an install you can select and manage as usual. -. Read the below, then continue reading the link:#ServerClientConsistency[next setup step]. - -ficsit-cli will probably see your local Satisfactory Mod Manager profiles and may have one selected by default. -Consider creating a new profile to use for your server. -Make sure to apply changes after installing mods or loading a profile, -otherwise all changes will be discarded on exit. - -Note that applying changes in ficsit-cli is a global action - -all installations the program is aware of will have any staged changes they may have applied in parallel. -This does _not_ mean that all installs must be on the same profile. +. Continue to the link:#ServerClientConsistency[next setup step]. [id="FileTransferMethods"] == File Transfer Methods @@ -118,6 +116,12 @@ This does _not_ mean that all installs must be on the same profile. The Mod Manager and ficsit-cli support multiple methods of connecting to servers remotely to manage mod files. Select a method below based on what your server (or 3rd party server host) provides. +For 3rd-party server hosts, refer to their documentation on how to connect to the server using a (S)FTP client. +The mod manager uses the same username, password, IP and port. The path depends on how the server host has set +things up (check their documentation), but it's relatively easy to figure it out: in the server's files, find a +folder that contains a file named `FactoryServer.sh` or `FactoryServer.exe`. The mod manager will make sure the +path points to an installation, so it will show an error if the path is not correct (no installations found). + [id="FileTransferMethods_SFTP"] === SFTP @@ -158,6 +162,7 @@ image::DedicatedServers/SMM_FTP.png[Satisfactory Mod Manager Example] .Ficsit-CLI FTP Example image::DedicatedServers/CLI_FTP.png[Ficsit-CLI Example] +//cspell:ignore CIFS [id="FileTransferMethods_SMB"] === Filepath or SMB/CIFS @@ -169,21 +174,56 @@ The examples below are for a self-hosted dedicated server. * The authenticating user requires Read/Write/Delete or Read/Modify permissions. * The path should follow this format: -** If using a Windows ficsit-cli install: -*** If the server is installed on your local computer, use the file path, for example `C:\EpicGamesGames\SatisfactoryDSExperiment` +** If running your chosen mod management tool on a Windows computer: +*** If the server is installed on the same computer, use the file path, for example `C:\EpicGamesGames\SatisfactoryDSExperiment` *** If the server is on a network location: `\\ServerNameOrIP\ShareName\Path` or `//ServerNameOrIP/ShareName/Path` -** If using a Linux ficsit-cli install: -+ -link:https://github.com/satisfactorymodding/ficsit-cli/issues/57[(A bug is currently preventing this from working)] +** If running your chosen mod management tool on a Linux computer: +*** If the server is installed on the same computer: use the file path. +*** If the server is on a network location, you first need to mount it to a local path, +then you can treat it as a local installation. +Mounting varies significantly depending on your setup; +a good starting point is to check `linux mount cifs to path` on your favorite search engine. +* Note that locally installed dedicated servers set up through Steam or Epic +will likely be automatically detected by Satisfactory Mod Manager and appear with the "DS" note in the dropdown. + +.Windows Satisfactory Mod Manager Example +image::DedicatedServers/SMM_SMB.png[Satisfactory Mod Manager Example] + +.Windows Ficsit-CLI Example +image::DedicatedServers/CLI_SMB.png[Ficsit-CLI Example] -** Satisfactory Mod Manager does not currently support SMB connections. - A future release (soon(TM)) will add support for this. +[id="Troubleshooting"] +== Troubleshooting -.Ficsit-CLI Example -image::DedicatedServers/CLI_SMB.png[Ficsit-CLI Example] +Remember, we can only provided limited support for third-party hosted servers +as we do not know or control their systems. +Contact your server host's support lines if you encounter problems. + +Contact us on the https://discord.gg/xkVJ73E[Discord Server] if something is confusing or goes wrong. + +[id="InstallingMods"] +== Installing Mods + +Once you have set up the mod manager of choice you can start installing mods on the server. +Read the below warning, then check out the set of directions specific to the mod manager you chose. + +[NOTE] +==== +As dedicated server support is still a work in progress, +there is not currently a conveneint way to filter mods for dedicated server support on the ficsit.app website. +When viewing the webpage for a mod, check the "Latest Version" section - +if you see a table with a "Server" column, and a checkmark is present on your server type, +the mod is compatible with dedicated servers. +If you see an X or the table is absent, the mod does not yet support dedicated servers. + +Satisfactory Mod Manager offers a "compatible" filtering mode which, +while managing a server install, causes only server-compatible mods to be displayed. + +Ficsit-cli does not currently have a way to filter mods for dedicated server support. +==== [id="ServerClientConsistency"] -== Server-Client Consistency +=== Important: Server-Client Mod Consistency Although it is possible to use ficsit-cli or the Mod Manager to install mods one-by-one on the server, this is not recommended as you could easily end up with a mismatch between client and server mod versions, @@ -202,19 +242,43 @@ and send file to your server members so they can configure their own installs ac If you encounter any one-side-only mods you will have to switch to using separate profiles for the server and client until the Modpacks feature is released. +[id="InstallingMods_SMM"] +=== Using Satisfactory Mod Manager + +The process of using Satisfactory Mod Manager from this point on is the same as managing a local install. +If you need a refresher, check out the xref:ForUsers/SatisfactoryModManager.adoc[Installing and Using the Mod Manager] guide. + +[id="InstallingMods_CLI"] +=== Using ficsit-cli + +There is not currently documentation for using ficsit-cli to install mods, +but as long as you heed the below advice, it will be pretty straightforward. +As always, ask on the Discord if you get stuck. + +ficsit-cli will probably see your local Satisfactory Mod Manager profiles and may have one selected by default. +Consider creating a new profile to use for your server. +Make sure to apply changes after installing mods or loading a profile, +otherwise all changes will be discarded on exit. + +Note that applying changes in ficsit-cli is a global action - +all installations the program is aware of will have any staged changes they may have applied in parallel. +This does _not_ mean that all installs must be on the same profile. + == Configuring Mods on Servers -Although xref:ForUsers/ConfiguringMods.adoc#_mod_savegame_settings[Mod Savegame Settings] -can be configured using their usual interface, -there is not currently an interface for adjusting +There is not currently an interface for adjusting xref:ForUsers/ConfiguringMods.adoc#_mod_configuration_options[Mod Configurations] remotely on dedicated servers. -As a result, you should configure mods client side and copy the config files over to the server. - -Note that some mods could stop working correctly or behave unexpectedly if client and server configs don't match. - +As such, you should configure mods client side and copy the config files over to the server. +Note that some mods could stop working correctly or behave unexpectedly if client and server configs don't match! Check the xref:faq.adoc#Files_ModConfig[FAQ on where game files are located] to see where config files are stored. +Although xref:ForUsers/ConfiguringMods.adoc#_mod_savegame_settings[Mod Savegame Settings] +can be configured mid-game using their usual interface, +the Server Manager's save creation screen does not support setting Mod Savegame Settings that must be decided at save file creation. +To work around this, create your save file with the desired settings on your client, +then upload the save to the server using the normal save file upload process. + == (Not supported) Manual Mod Installation [WARNING]