[UE4] FastBuild 4.26的一些實驗數據

posted in: 未分類 | 0

關於怎麼將FastBuild設置起來,可以參考這篇文章: [UE4] 如何使用FASTBuild來做分散式編譯 – 地平線上的多貢地平線上的多貢 (horizon-studio.net) 由於4.26內建了FastBuild的功能,因此找了一點時間做了一下實驗 手邊有二台機器,其實驗環境規格如下:Local: AMD 5950xRemote:MacMini 2018版 6 Core i7 with windows 10 (VMWare Fusion) 在沒用FastBuild,建置手邊一個遊戲專案,共422個cpp所需耗時如下: 1>Total time in Parallel executor: 97.03 seconds1>Total execution time: 106.11 seconds 初始使用FastBuild建置時間如下: 1>— Summary —————————————————–1> /—– Cache —–\1>Build: Seen Built … Continued

[UE4]如何使用Profile-Guided Optimization (PGO)

posted in: 未分類 | 0

只要有寫過 C++ 程式的人,大都可以理解不同的構建配置(BuildConfiguration)編譯器會幫助我們進行不同程度的優化── Debug 與 Development主要是為了除錯,Test用來偵測效能表現,最後Shipping則做出最好的優化配置。──但是除了那些各式各樣的編譯參數調整之外,我們其實還可以利用事先產生「profile」的方式讓編譯器利用運行時期的資訊來做出各種更激進的優化手段,例如:縮減整個code size、 降低 if-then-else branch 的預測失誤來減少 cpu指令的執行數量, 或者是重新組織整個 code layout 以增進 cpu 指令的 cache效率。詳細可以參考Intel的線上文檔。 UE4當然也有提供這項優化功能,但目前(4.25)也只支援 PS4、 XboxOne 與Switch 這三個平台。   就我自身的經驗而言,在啟用 PGO 之後整體的 FPS 大約提升了3左右, 其中屬於CPU 部份的 Game 跟 Draw 這二條 Thread 各別降低了1.xx ms的運行成本。這效能的提升雖然不算多,但卻是在一些常規的優化手段都採取之後能夠再額外得到的效能突破。除了缺點是開發者需要多花一些時間在建置流程的設計上與編譯的等待時間之外,但帶來的卻是能夠讓我們將省下的效能預算投入在更好的遊戲表現上,何樂而不為呢?   首先讓我們先來看一下整體運行流程: 整個流程的第一步,我們必須要產生PGI build,這邊我們可以選擇使用Development 或者是 Test 組態都行, 重點是我們必須要籍助RunUAT指令(UnrealAutomation Tool),並傳入以下參數來產生正確的版本: -UbtArgs=’-LTCG-PGOProfile’  接著在C++進行linking之前出現以下訊息的話就代表指令成功: EnablingProfile Guided Instrumentation (PGI). Linking will take a while.   以下是完整的PGI Build指令: 接著我們必須利用Gauntlet(4.21推出的自動化測試框架)將剛才Local PGIBuild跑起來,但在這之前,我們必須要先設計專案所使用到的PGONode並放進/Path/To/YourProject/Build/Script/YourProject.Automation/YourProject.PGONode.cs,如下: 接著我們必須先編譯這個C#專案,並把dll的輸出路徑設定到Engine/Binaries/DotNET/AutomationScripts/下面,這樣Gauntlet才有辦法找到 YourProjectPGONode並運行起版本。C#專案編譯指令如下:   然後我們就可以運行 Gauntlet 將版本跑起來,其中參數-test=”YourProjectPGONode” 會去找到我們剛剛撰寫的 C# Script起來運行: 這邊我們可以選擇手動跑過整個遊戲流程或者是撰寫自動化 Script ,等到收集完足夠的 profile data 之後, 再手動輸入UE4的quit consolecommand讓引擎跑完正常結束遊戲的流程, Gauntlet 便會自動的將profile.profdata 放在 /Path/To/MyPorject/Build/${YourPlatform}/PGO/ 下面。   到此為止我們已經收集到建構PGO版本所需要的全部資訊,上面介紹的建置PGI版本與收集profile.profdata不需要每次做版本都執行,我們只需要定期的人工檢視C++程式碼有足夠的變動再跑這個流程即可。   接下來,我們就可以利用profile.profdata做出優化過後的PGO版本,只要在RunUAT 做 build 時,代入以下參數:-UbtArgs=’-LTCG -PGOOptimize’,他就會自動的找到 /Path/To/MyPorject/Build/${YourPlatform}/PGO/ 下的profile.profdata 進行建置,接著在C++進行linking之前出現以下訊息的話就代表指令成功: EnablingProfile Guided Optimization (PGO). Linking will take a while.   以下是完整的PGO Build指令:

[UE4] 怎麼設定tortoisegit來diff uasset

posted in: 未分類 | 0

基本上做法很簡單,就是利用UE4 Editor傳入-diff參數後,藉由tortoise git的external diff viewer來達成目的。這樣的話,我們就不需要開editor就可以呼叫ue4的diff window了。實際指令如下: ${UE4_ENGINE_ROOT}\Engine\Binaries\Win64\UE4Editor.exe -diff %base %mine 可參考下面程式碼的實作: Engine\Source\Editor\UnrealEd\Private\EditorCommandLineUtils.cpp Usage: \n\ -diff [options] left right \n\ -diff [options] remote local base result \n\ 要做 merge的話,可以使用這個指令: ${UE4_ENGINE_ROOT}\ \Engine\Binaries\Win64\UE4Editor.exe -diff %theirs %mine %base %merged

[UE4][開發日誌]使用nuget來發佈遊戲專案中的UE4Editor dll

posted in: UnrealEngine, 開發日誌 | 0

這幾天花了一此時間研究了nuget的佈署方式,主要的目的,便是要讓大家在還真的購買plugin之前,有個機會先能夠在editor中進行試用。 雖然perforce使用者有[UGS](https://docs.unrealengine.com/en-us/Programming/Deployment/Unreal-Game-Sync/Unreal-Game-Sync-Overview)可以用,但由於跟perforce綁定,對於習慣於用git的自己而言還是要去思考別的替代方案。 另外,nuget好處是,開放給大家的部份可以發到nuget.org上,如果公司內部要私用的話,也是可以自己架一個nuget server或者是直接弄一個local feed在NAS上,就使用彈性而言,我個人覺得比UGS來得高。 目前我正在開發的幾個plugin都也已經發佈到nuget.org開發大家下載了,有興趣的人可以試試看,使用方法跟步驟已經記錄在對應的Github頁面中了。 plugin marketplace: https://www.unrealengine.com/marketplace/profile/horizon-studioGithub專案連結:https://github.com/dorgonman/HorizonUIPluginDemohttps://github.com/dorgonman/HorizonTweenDemohttps://github.com/dorgonman/HorizonFrameworkDemohttps://github.com/dorgonman/HorizonVRDemohttps://github.com/dorgonman/HorizonDialogueDemo 另外由於我這幾個專案都有進Azure Devops的build pipeline了,理論上只要我這邊有任何更新,都會自動發佈到nuget.org上。

[UE4]UE4靈異現象之不管怎麼算都多出了一個人……

posted in: UnrealEngine | 0

(本文中的故事情節純屬虛構,如有雷同……的話?) UE4用久了,遇過的怪事不會少只會多。 只是,這次的事件卻令我感到毛骨悚然。 事情該從哪邊開始講起呢?對了,就從功能面的設計面開始吧。 首先,由於我正在製作一個網路對戰型的遊戲,因此希望在其他玩家以「Spectator(觀眾)」的身份進到遊戲的時候,能夠即時讓對戰中的玩家知道目前場上有多少觀眾正在觀賽。 而要決定Client端要不要以「Spectator」的方式登入的方法非常簡單,基本上就是以下二種方法: 在OpenLevel的時候帶入參數?SpectatorOnly=1。 覆寫AGameModeBase::MustSpectate這個方法,並根據我們遊戲設計的邏輯決定是否回傳true。(例如比賽正在進行中的話,後面就都只能以spectator的方式加入) 這個階段我只是想要確spectator的計數功能是否正常,因此我的想法非常單純: 當Client上的SpectatorPawn成功進到遊戲的時候(觸發PossessedBy)的時候送一個RPC給Server。 由於我已經知道SpectatorPawn本身只存在於Client端,所以他本身是沒有連線功能的。 為了成功將RPC送出,因此必須要藉由PlayerController的連線通道: https://gist.github.com/dorgonman/9b62afabd399b7fbc855b64ee3e08757   然後在PlayerController上的實作如下: https://gist.github.com/dorgonman/f9b41c58339b2ffa68773a13ab2d966e   在Server收到SpectatorReady通知之後,馬上去增加AMyGameModeBase::NumReadySpectator的數量並印出來 在編譯完成按下Play之後,可以在Log上發現這段訊息: LogTemp: NumReadySpectator: 1 嗯,很好!SpectatorPawn的登入通知很順利的傳送給Server了!   正當我滿足於現在的實作,準備進行下一階段功能的設計時,我突然看到了現在MyGameModeBase::MustSpectate中的實作: https://gist.github.com/dorgonman/bdd1380a8acd64615e6ee913ad2c0669 「有一個觀眾?」眉頭一皺,我感覺到那邊似乎不太對勁。 理論上的MustSpectate回傳都是false的話,那麼NumReadySpectator應該都會是0才是, 而且,pPC->Server_SpectatorReady()應該是完全不會被呼叫到才是。 於是,我馬上把視線移向了editor中的WorldOutliner,想看看計數器中的Spectator到底哪來的:   一看了之後我嚇出了一身冷汗──這個世界中並沒有任何「SpectatorPawn」存在。 就我的理解,World Outliner應該會顯示目前世界上所有存活著的Actor才是, 難不成這個世界還存在著一個看不見的Spectator默默的觀察著玩家? 為了查證SpectatorPawn到底是被誰生出來的,於是我便在Constructor下了斷點──果然, 世界就這麼停留在Spectator被生成的那個瞬間,循著callstack往上追蹤,我發現了一個線索: 當Client端從Server那邊收到SpectatorClass之後,便會觸發PlayerController中的ReceivedSpectatorClass()把SpectatorPawn生成出來。 我感覺更加困惑了:每個PlayerController在收到Server的通知之後都會生成SpectatorPawn出來? 這不是我所認識的UE4阿!證據是,World … Continued

[UE4]網路同步之Character謀殺事件

posted in: UnrealEngine | 0

事情是這樣的。 本來我是想要測一下network做replication變數相關的功能,因此建了一個空白的level(全黑色那張),並做了一個Character後加了幾個變數與寫了幾個function來進行實驗。在按下play之後……嗯,一開始變數成功的從server傳過去給client了(開了二個player,一個listen server,一個client)。很好!就在我滿足於事情正如想像中進展的時候,突然間,變數卻完全送不過去給Client了! 到底發生了什麼事?就我的理解上,我用的是COND_None,只要server有任何變動的話,變數應該會送給client阿?難不然變數是unreliable的?不對阿,replication變數肯定都是reliable,頂多就只有因為頻寬的問題而延遲送達而已。經過我的反覆實驗,最後發現了一件驚人的事實: 我listen server上的character居然被砍掉了! 在得知這項資訊後,我決定馬上到AMyCharacter::EndPlay這個function中下斷點──我想想看看到底是那個混蛋砍了我的character。可惜的是,我依然沒有抓到兇手。──AMyCharacter::EndPlay是被呼叫了沒錯,可是EndPlayReason只寫了一行Destroyed。這資訊完全沒有幫助,因此我決定循著call stack往上層追,最後看到了這段程式碼: https://gist.github.com/dorgonman/00c3c173f3a70fc040d88d00915e3323 WTF!?網路收到了斷線通知之後,就馬上把我的角色砍了!?為什麼listen server上所擁有的Character會被斷線?我並沒有加入任何砍Actor的邏輯阿?難道是因為自動觸發GC的緣故?也不對阿,Actor的生命週期應該是跟著world才是,要砍Actor的話只能手動呼叫Destroy(K2_DestroyActor)才行。我完全被眼前的事實驚呆了,這跟我過去對於UE4相關的知識完全不相符。 「這樣不行,一定要找出原因。」──雖然感受到了挫折,但我才不會因為這點小事就被擊敗。為了找出被斷線的原因,我決定利用手邊僅剩唯一的蛛絲馬跡「Bunch.bClose」來找出殺死Character的兇手是誰。事出必有因,既然Bunch.bClose這個flag是true,那必然是有那段邏輯使然。在搜遍了整個引擎之後,總算發現下面這段非常可疑的程式碼: https://gist.github.com/dorgonman/5f021b9eac330493d3f012bfda9a8d99 當Channel->Close();被呼叫之後,就會送出一個CloseBunch出來並把我的Character殺死。而為什麼會進到這段邏輯的根本原因,在於bIsRecentlyRelevant是false,意即,listen server認為這個Character已經跟自己沒有任何瓜葛了,所以就殺了他。 到這裡,似乎就已經破案了,原來人是Server自己殺掉的阿…… 但李組長眉頭一皺,事情似乎並不是這麼樣的單純。為什麼listen server會無緣無殺的去殺掉自己的親生兒子?難不成二兒子就那麼該死嗎(PlayerController2)?大兒子(PlayerController1,listen server)不是還活蹦亂跳的好好的在那邊嗎?為什麼就只有二兒子!?而且是非常固定,每次在世界被建構起來約10秒鐘之後,這件兇殺案就會必然的發生。不管是我模擬了幾十次還是幾百次,都無法逃離二兒子死亡的結局。 這世界上肯定是哪裡有Bug了!──我的心底對著Epic大神這麼叫囂著。 這麼顯而易見的Bug,不可能只有我才會遇到。於是我轉而求向古歌大神的協助……然而,卻還是一無所獲。沒辦法,只好靠著新發現的事實,繼續的往上追蹤。目前我們知道,當Listen Server決定要跟二兒子斷絕關係的時候,bIsRecentlyRelevant就會被設成false,那麼我們只要找到設置bIsRecentlyRelevant這個flag的源頭,就必然有辦法找出這件兇殺案背後發生的原因。 殺人兇手,是身為父親的Listen Server。──這點已經不容質疑。 但事實的背後往往有著更令人訝異的真實。只要努力不懈的話,真理永遠就只會有一個。是的,最後我終於到達了,那扇真理之門的面前: https://gist.github.com/dorgonman/baba67405e381f52f35f7112c7b610a7 看到這段程式碼之後,我馬上理解了整個案情的來龍去脈。為了證明事實真的如同我所想像的,我馬上再次開啟了最後一次世界的模擬: 「阿阿阿阿阿阿阿──────!」我彷彿聽到了慘叫聲。 二兒子Z軸的數字正以著不可思議的速度往下遞減──在重力加速度的加成下,二兒子快速的離大兒子遠去,然後在到達一定的臨界值(NetCullDistanceSquared)之後,就這麼消失在世界的盡頭。 什麼嘛,原來是摔死的。 至此,一切的謎題都已經解開了。 想要避免這件慘絕人寰的兇殺案,大致上有以下幾個解決方案: 將CharacterMovement中的Default Land Movement Mode 設成Flying:這樣你的角色就不會掉下去了。 將Character中的Always Relevant這個選項打勾:但是你的Character還是會無限的往下進行自由落體的動作,只是,這個flag是有其必要性,它在多人連線遊戲下可以減少不少網路頻寬,在調整這個設置前,最好對這個flag有正確的認識。 下面放個Cube:這樣Character就有地方可以站。

[UE4] 如何使用FASTBuild來做分散式編譯

posted in: UnrealEngine | 0

首先這套工具只適用於從Github上抓引擎源碼下來編譯的情境,Launcher版本目前(4.19)並不支援 下面這個repository是我調整過後並整合進UE4的版本,可以直接clone下來使用: https://github.com/dorgonman/UnrealEngine/tree/dorgon/develop-4.19 原作者的版本:https://github.com/liamkf/Unreal_FASTBuild  (用這個版本的話,照著他的說明做整合就行了) 要使用這個工具必須要注意以下幾個點:  在安裝Visual Studio 2017的時候,要記得把vc++2017 version 15.5 v14.12勾起來 設定以下幾個環境變數: FASTBUILD_BROKERAGE_PATH \\192.168.100.2\workspace\fastbuild.brokerage  (讓所有的電腦知道那邊有build worker可以用) FASTBUILD_CACHE_PATH     \\192.168.100.2\workspace\UE_FASTBuild_Cache (用來做cache路徑) 要注意的是上面二個路徑要讓所有參與編譯的電腦都有讀寫的權限(我自己是在NAS上開公用資料夾) 在所有要參與分散式編譯的電腦上執行Extras\ThirdPartyNotUE\FASTBuild\Win64\FBuildWorker.exe 打開之後,在做build的時候就可以發現遠端已經有同伴在幫我們編譯了! 我們可以在visual studio的build log看到以下的訊息: 接著將Extras\ThirdPartyNotUE\FASTBuild\Win64\FBuildWorker.exe建立一個捷徑,貼到${UserName}\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup之後, 每次電腦開機的時候就會自動執行了。 這套軟體對於沒經費購買Incredibuild的團隊算是一個不錯的解決方案~

[UE4] 使用FileOrder加速遊戲的載入時間

posted in: 未分類 | 0

剛剛看到官方文件中有Ordering your .pak file的這個技巧:https://docs.unrealengine.com/en-US/Engine/Basics/Projects/Packaging 看起來可以節省不少Loading asset的時間 剛剛試了一下,這裡就做個簡單的記錄。 基本上就是在package完之後,在跑game的時候新增以下參數:-fileopenlog,然後就會產生GameOpenOrder.log這個檔案,如下圖: 產生的這個GameOpenOrder.log,把他複制到專案下的Build\WindowsNoEditor\FileOpenOrder,再打包一次就行了 記得GameOpenOrder.log要上到版控中,然後在做shipping build之前產最後一次的GameOpenOrder.log之後再打包。

[UE4] 如何測試marketplace plugin的打包流程

posted in: UnrealEngine | 0

主要是靠RunUAT.bat中的BuildPlugin指令,如下: 用法,把所有的.uplugin檔案找出來餵進去: #export PLUGIN_BUILD_TARGET=”Android+HTML5+IOS+Mac+TVOS+Win32+Win64″ export PLUGIN_BUILD_TARGET=”Win32+Win64″ export PLUGIN_PACKAGE_ARCHIVE_DIR=”/your/plugin/temp/path/” for f in $( find . -type f -name ‘*.uplugin’); do export PLUGIN_FILE=”${PROJECT_ROOT}/${f}” UEBuildPlugin done 要注意IOS、Mac跟TVOS要在MacOS系統上做建置 相關引擎中souce code在這裡: Engine\Source\Programs\AutomationTool\Scripts\BuildPluginCommand.Automation.cs 我目前是把這段code整合進vsts中的CI建置流程中。  

[UE4開發日誌]VSTS CI Build與UE4 Automation Test整合

posted in: 開發日誌 | 0

剛剛成功將UE4的Test Automation的功能跟VSTS的CI build整合在一起了。總算能夠處理Test失敗的狀況並回報建置錯誤。雖然D3D Device抓不到只能用server mode跑,但基本上要做funtional test跟unit test看起來沒什麼問題。之後測試好好寫的話,看起來可以省掉不少做回歸測試的功夫。