Introduction
I didn't see an easily guide anywhere outside of Discord for setting up Tower of Fantasy on macOS, so I'm putting one together here.
This guide will address the issues with logging in, and weird texture rendering.
Playcover
Tower of Fantasy is a cross-platform game, with versions for iOS, Android, Windows, and PlayStation, but no Mac version.
Usually the most straightforward way to run the game would be via CrossOver, but since the Windows port uses highly invasive kernel anti-cheat, it cannot be run under Wine. Parallels or VMWare isn't an option either because of that reason.
This leaves us with Playcover as the only remaining option. Download the latest version (3.0.0-beta2 at time of writing) from their website: https://playcover.io/download/
Install and run Playcover for the first time. Disabling SIP is not required.
Then grab the Tower of Fantasy IPA and import it into Playcover: https://decrypt.day/app/id1601586278
Installation
This is the part is slightly more involved than the previous steps.
First, launch the game from the Playcover window. It should open and start downloading the game files.
Once the download is complete, it should load up title screen that's rather broken looking. Quit the game.
Open the Terminal (located in /Applications/Utilities) and run the following command:
bash <(curl -s https://gist.githubusercontent.com/ohaiibuzzle/7bc8a8f93f82c6692120d732eef59810/raw/6a99a0af71d63a499ab068ef6e3f3a2e71d56529/tof_pc_login.sh)
If that does not work, try replacing the URL with a forked copy: https://gist.github.com/FleetAdmiralButter/ea27da7336e00b733b1d345113615998/raw/6a99a0af71d63a499ab068ef6e3f3a2e71d56529/tof_pc_login.sh
The script should run and prompt you for a region. Enter "1" for Global. Then, it should pause and prompt you to open the game.
Now, go back to Playcover and open Tower of Fantasy again. The login panel should appear now, allowing you to sign in.
Sign in with Apple will not work. If your account is tied to your Apple ID, log into the game on an iOS device and associate it with another login method.
Once you have signed in, close the game again and hit Return on the Terminal window. Launch the game once again from Playcover and check that you're able to enter the game.
The script may fail with an error about failing to rename a directory - if this is the case, manually copy the files in "~/Library/Containers/com.levelinfinite.hotta.ios/Data/PatchPaks/" to "~/Library/Containers/com.levelinfinite.hotta.ios/Data/Documents/Hotta/Content/PatchPaks".
Graphics Fixes
Once the game is running using the steps above, it will likely have a number of graphical artefacts and glitches. For example, textures will not load and draw distance will be very low.
To fix this, open "~/Library/Containers/com.levelinfinite.hotta.ios/Data/Documents/Hotta/Saved/Config/IOS/Engine.ini" using a text editor.
At the bottom of the file, enter the following lines:
[SystemSettings]
r.ViewDistanceScale=2000
foliage.LODDistanceScale=4
r.SkeletalMeshLODBias=-1
r.MipMapLODBias=-1
r.StaticMeshLODDistanceScale=0.25
r.LandscapeLODBias=-1
r.LandscapeLODDistributionScale=3
r.LandscapeLOD0DistributionScale=3
r.LODFadeTime=2
r.UITextureLODBias=-1
r.LevelStreamingDistanceScale=10
r.Shadow.DistanceScale=10
r.Shadow.DistanceScale=3
r.LightMaxDrawDistanceScale=2
r.LightMaxDrawDistanceScale=5
r.ShadowQuality=5
r.Shadow.MaxResolution=8192
r.Shadow.RadiusThreshold=0.03
r.AllowLandscapeShadows=1
r.ContactShadows=1
r.Streaming.FullyLoadUsedTextures=1
r.Streaming.DropMips=0
r.Streaming.HiddenPrimitiveScale=0.5
r.Streaming.HLODStrategy=0
r.Streaming.MipBias=0.4
r.Streaming.UseAllMips=0
r.MaxAnisotropy=8
r.Streaming.LimitPoolSizeToVRAM=0
r.Streaming.PoolSize=8000
r.Streaming.MaxTempMemoryAllowed=4096
r.RenderTargetPoolMin=2048
r.MaterialQualityLevel=3
r.TextureStreaming=1
r.LODDistanceScale=0
Restart the game once you've added the lines above and the game should run without any texture or LOD issues!
The specific setting that corrects the problem with texture loading is "r.TextureStreaming=1" and "r.Streaming.FullyLoadUsedTextures=1".