Users browsing this thread: 8 Guest(s)
[Mobile] Sky; Children of the Light
#1
Howdy yall!

Here's what your after; how to rip models from Sky; Children of The Light.

Please bear in mind this is still a work in progress so not everything works 100% just yet.
Big shout out to users longbyte1 and cobrakyle for cracking the issue.

You'll need:
  • Blender 3.2.2 or later.
  • (Windows Only) LZ4


Also, nearly all the images in the game are stored as .ktx so you'll need the PVRTextTool linked below. TO export as an .png image go to file >>save Image
https://developer.imaginationtech.com/downloads/

(09-06-2022, 09:53 PM)longbyte1 Wrote:
Code:
import ctypes
import struct
import io
from ctypes import *

f = open('/tmp/UnitCube.mesh', 'rb')

lz4 = CDLL('liblz4.so.1')

# read uncompressed size
f.seek(0x52)
uncompressed_size = struct.unpack('i', f.read(4))[0]

# read compressed size
f.seek(0x4e)
compressed_size = struct.unpack('i', f.read(4))[0]

# read num lods
f.seek(0x44)
num_lods = struct.unpack('i', f.read(4))[0]

print('compressed_size', compressed_size)
print('uncompressed_size', uncompressed_size)
print('num_lods', num_lods)

# get compressed content
f.seek(0x56)
src = f.read(compressed_size)

# get decompressed content
dest = ctypes.create_string_buffer(uncompressed_size)
ret = lz4.LZ4_decompress_safe(src, dest, compressed_size, uncompressed_size)
if ret <= 0:
    raise IOError('error decompressing mesh - file may not be valid')

buf = io.BytesIO(dest.raw)
buf.seek(0x74)
shared_vertex_count = struct.unpack('i', buf.read1(4))[0]
buf.seek(0x78)
total_vertex_count = struct.unpack('i', buf.read1(4))[0]
buf.seek(0x80)
point_count = struct.unpack('i', buf.read1(4))[0]
buf.seek(0x74)
uv_count = struct.unpack('i', buf.read1(4))[0]

print('shared_vertex_count', shared_vertex_count)
print('total_vertex_count', total_vertex_count)
print('point_count', point_count)
print('uv_count', uv_count)

# build vertex buffer
vertex_buffer = []
vertex_buffer_start = 0xb3
buf.seek(vertex_buffer_start)

for i in range(shared_vertex_count):
    # 3 floats
    x, y, z = struct.unpack('<fff4x', buf.read(16))
    vertex_buffer.append((x, y, z))

# build uv buffer
uv_buffer = []
uv_header_size = uv_count * 4 - 4
buf.read1(uv_header_size) # move caret to uv start
for i in range(uv_count):
    # 2 half-precision floats
    u, v = struct.unpack('<4xee8x', buf.read(16))
    uv_buffer.append((u, v))

# build index buffer
index_buffer = []
face_count = total_vertex_count // 3
buf.read1(4) # advance 4 bytes of padding
for i in range(face_count):
    # 3 shorts (each indexing into the vertex buffer)
    v1, v2, v3 = struct.unpack('<HHH', buf.read(6))
    index_buffer.append((v1, v2, v3))

f.close()
buf.close()

print(vertex_buffer)
print(index_buffer)

# build geometry from buffers
vertices = []
edges = []
faces = []
for face in index_buffer:
    v1i, v2i, v3i = face
    edges += [(v1i, v2i), (v2i, v3i), (v3i, v1i)]
    faces.append(face)

import bpy
mesh = bpy.data.meshes.new('created_mesh')
mesh.from_pydata(vertex_buffer, edges, faces)
mesh.update()

uvl = mesh.uv_layers.new()
uvl.data.foreach_set('uv', [uv for pair in [uv_buffer[l.vertex_index] for l in mesh.loops] for uv in pair])
mesh.uv_layers.active = uvl

obj = bpy.data.objects.new('created_object', mesh)
collection = bpy.data.collections.new('created_collection')
bpy.context.scene.collection.children.link(collection)
collection.objects.link(obj)

Just change the open() line to load the file you want. Note that this is only going to read the first LOD it finds, which should be the highest quality one.
For Windows users, you need to change the path in the CDLL() line to a path to a 64-bit LZ4 DLL (or 32-bit, depending on whether your Blender is 64- or 32-bit). You can find a working copy of LZ4 for Windows here, and you're looking for a DLL called either "msys-lz4-1.dll" or "liblz4.dll".


How to do start:

Open Blender and navigate to the Scripting tab along the top. On the right hand side a new window will appear, click the '+ New' button and paste in the code from the above quote.
You can save this file somewhere if you like.

On Windows
Open the LZ4 file you should have downloaded and unzipped/decompressed. In there navigate to the dll folder and make sure the file msys-lz4-1.dll is there.

The two most important lines in this code that we need to worry about are

line 6:
Code:
f = open('/tmp/UnitCube.mesh', 'rb')

This line states what mesh we want to extract. You'll find all the meshes available in side the APK (link further down). In this example we'll use the AcestorShrine_06.mesh file. Below I've pointed the code to it's location on my computer, making sure to replace any backslash characters (\) with forward slashes instead (/)

Code:
f = open('D:/Android/Test Meshses/AncestorShrine_06.mesh', 'rb')


line 8 (windows):
Code:
lz4 = CDLL('liblz4.so.1')

The code uses this file to do it's magic, but sadly Windows wont have this which is why we have to download it from the link above. Oce you've downloaded it and located the msys-lz4-1.dll alter the code like so. Again, making sure any backslash characters (\) are changed to forward slash (/)

Code:
lz4 = CDLL('C:/{path to my desktop}/Desktop/lz4_win64_v1_9_4/dll/msys-lz4-1.dll')

All thats left is to run the code! CLick that little play button at the top of the window and BAM! THe code will put the extracted mesh into a new collection in the outliner named 'created_object'.



Issues and drawbacks
As mentioned above, this is still a work in progress so there are still a few issues with files containing the following in their name which is still being investigated.
  • StripGeo (strip geometry)
  • StripAnim (strip animations)
  • UncompAnim (uncompressed animation)
  • CompOcc (compute occlusions)
  • CompEdges (compute edges)
  • CompAdj (compute adjacency)
  • ZipPos (packed positions?)
  • ZipUvs (packed UVs?)
  • StripUv13 (?)
  • StripNorm (strip normals)
  • ForceIdx32 (use 32-bit indexes instead of 16-bit indexes)

We're also facing the following issues,
  • Missing textures on all meshes -> Still being investigated but looks to be the textures are stored elsewhere that we just havent found yet.
  • (will be added as found)


                                                                                                 

Original post and some links to various resources you might need or want.

I've been trying to rip the models from the mobile game Sky; Children of the light by That Game Company, for about a week or so now with moderate success having grabbed the textures, sprites, and sound, from the .apk

APK here

I'm now stuck trying to get hold of the actual models.

The current theory is that the models are stored in these .bin files as there is one for each level in the game which the code refers too along with .fbx files. There is a full version of the code snippet in the resources.lua files

Code:
-- THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY THIS FILE!

-- Level objects
resource "LevelObjects" "DawnCave" { level = "DawnCave", source = "Levels/DawnCave/Objects.level", sourcesCount = 16, sources = { "Levels/DawnCave/Objects.level", "Levels/DawnCave/AP8_Intro.level", "Levels/DawnCave/AP8_Outro.level", "Levels/DawnCave/Art_Foreground.level", "Levels/DawnCave/Audio.level", "Levels/DawnCave/Candles.level", "Levels/DawnCave/MemoryCutscenesA.level", "Levels/DawnCave/MemoryCutscenesB.level", "Levels/DawnCave/NPC_Party.level", "Levels/DawnCave/Quest1.level", "Levels/DawnCave/Quest2.level", "Levels/DawnCave/Quest3.level", "Levels/DawnCave/Quest4.level", "Levels/DawnCave/Scripting.level", "Levels/DawnCave/TrailElementalChanges.level", "Levels/DawnCave/TrialLogic.level" }, stripDebug = true }

-- Prefabs

-- Meshes
resource "Mesh" "CharSkyNPC_Prop_Rock" { source = "CharSkyNPC_Prop_Rock.fbx", computeOcclusions = false, computeEdges = false, computeAdjacency = false, compressPositions = false, compressUvs = false, stripUv13 = false, stripNormals = false, forceIndex32 = false, registerCollision = true, stripAnimation = false }
resource "Mesh" "Cube" { source = "Cube.fbx", computeOcclusions = false, computeEdges = false, computeAdjacency = false, compressPositions = false, compressUvs = false, stripUv13 = false, stripNormals = false, forceIndex32 = false, registerCollision = true, stripAnimation = false }
resource "Mesh" "DawnCaveMask_01" { source = "DawnCaveMask_01.fbx", computeOcclusions = false, computeEdges = false, computeAdjacency = false, compressPositions = false, compressUvs = false, stripUv13 = false, stripNormals = false, forceIndex32 = false, registerCollision = true, stripAnimation = false }

I've tried using tools like winrar, poweriso, and a few others but all of them say the .bin files are in the wrong format. Same for when I rename the files to remove the '.level' bit.

Additionally, I'm able to access .mesh files but I have no idea how to open them. I think they're openGL but so far no luck in converting, even tried using Ogre3D.

The minimum requirements of Sky are (copied from the wiki)
  • Android 8.1 Oreo or higher
  • ARM 64bit with Neon (32 bit devices will never run Sky)
  • At least 1.5GB RAM
  • OpenGLES 3.1 Extension Pack
  • Vulkan Version 1.0.3 or higher
  • Vulkan Level 0 or higher

  • 3GB storage to download and install all areas

From what I can tell the app itself is built using

Any advice is greatly appreciated Smile


  I have included a selection of files but if you need or want any more just give us a shout!

Included are:

AncestorShrine_06.mesh

BstBaked.meshes

Objects.level.bin

resources.lua
Reply
Thanked by: Miss
#2
If you ever figure out how to get these please let me know! I've been dying to see the models for myself :')
Reply
Thanked by:
#3
Hey man, if you have any success ripping meshes let me know, I've been trying to get those for some time now
Reply
Thanked by:
#4
Howdy howdy!

Bit of an update; unfortunately no luck yet getting the models but I think I getting closer.

The release of the switch version does give us another Avenue to look into but sadly it looks to be a straight port; all the files and folders are pretty much one to one, at least with the switch file I got my hands on.

But, I did find that .mesh is the file type godot uses when models (like the .fbx ones we can see referenced in the resources.lua) are compiled. And the file structure also looks to line up as well, plus, godot renders using OpenGLES 3.1!

As if that wasnt enough, Gkdot packages everything up into a object.level.bin file!

Unfortunately I havent been able to crack into them just yet so if anyone has any experience with them please let us know!
Reply
Thanked by:
#5
Hi Everyone!

Another small update, sadly still no luck with models just yet, and trying to use GoDot on the files didn't result in anything either.

But I have been looking into trying to figure out what TGC use them selves to make the software.
I've managed to get the textures and images using PVRText tool so my thoughts are they have either used or are using the PowerVR software; job listings specify being able to work with a proprietary software so this is the only thing I can think of.

https://thatgamecompany.com/generalist-s...nd-engine/
https://developer.imaginationtech.com/downloads/

Does anyone have any ideas or suggestions??

Cheers! Big Grin
Reply
Thanked by:
#6
(07-14-2021, 10:15 AM)DancingTwix Wrote: Howdy howdy!

Bit of an update; unfortunately no luck yet getting the models but I think I getting closer.

The release of the switch version does give us another Avenue to look into but sadly it looks to be a straight port; all the files and folders are pretty much one to one, at least with the switch file I got my hands on.

But, I did find that .mesh is the file type godot uses when models (like the .fbx ones we can see referenced in the resources.lua) are compiled. And the file structure also looks to line up as well, plus, godot renders using OpenGLES 3.1!

As if that wasnt enough, Gkdot packages everything up into a object.level.bin file!

Unfortunately I havent been able to crack into them just yet so if anyone has any experience with them please let us know!

Hiiiii! Can you share where did you get the switch file? I'm also working on this but I don't have a switch
Big Grin
Reply
Thanked by:
#7
(01-15-2022, 09:31 PM)Chara.0 Wrote: Hiiiii! Can you share where did you get the switch file? I'm also working on this but I don't have a switch
Big Grin

Hello! Wonderful to have you on the crew Big Grin

There's quite a few sites you can get the switch files from like this site here.

Afraid to say I've put my investigations into the switch version on hold for now and just focusing on android.
I'd also recommend this site here to get an idea of how Vulkan works and how it saves data and such; I've been working slowly through it hoping to get an idea of how to get into the .bin files mentioned above.

Give us a shout if you need a hand at all Smile

EDIT:

Regarding the tutorial website I mentioned, it's this chapter on asset management which looks promising!
https://vkguide.dev/docs/extra-chapter/asset_system/

Also, nearly all the images in the game are stored as .ktx so you'll need the PVRTextTool linked below. TO export as an .png image go to file >>save Image
https://developer.imaginationtech.com/downloads/
Reply
Thanked by:
#8
(01-16-2022, 04:30 PM)DancingTwix Wrote:
(01-15-2022, 09:31 PM)Chara.0 Wrote: Hiiiii! Can you share where did you get the switch file? I'm also working on this but I don't have a switch
Big Grin

Hello! Wonderful to have you on the crew Big Grin

There's quite a few sites you can get the switch files from like this site here.

Afraid to say I've put my investigations into the switch version on hold for now and just focusing on android.
I'd also recommend this site here to get an idea of how Vulkan works and how it saves data and such; I've been working slowly through it hoping to get an idea of how to get into the .bin files mentioned above.

Give us a shout if you need a hand at all Smile

EDIT:

Regarding the tutorial website I mentioned, it's this chapter on asset management which looks promising!
https://vkguide.dev/docs/extra-chapter/asset_system/

Also, nearly all the images in the game are stored as .ktx so you'll need the PVRTextTool linked below. TO export as an .png image go to file >>save Image
https://developer.imaginationtech.com/downloads/

Hiiii! Thank you very much!
I already have the PVRTextTool, and I have the switch file. However, I can't unlock the switch file(prods.key)......


I'll try to read the tutorial and try to working on this...

Thank you very much!

Extra:
I did some research and found out the old version map and it can sucessfully load in the 0.15.5 and below(after replacing BlobPrefabs and adding old meshes). However, every map packaged below 0.16.0 can't load in 0.16.0. I think maybe(after loading different meshes file inside Level) they updated the system. 
Before 4c 56 4c 30 33 (LVL06) --> After 4c 56 4c 30 37 (LVL07) 
This is likely their own engine...
Reply
Thanked by:
#9
No worries!!
Yeah the issue with getting product keys and the like are why I put looking into the switch one hold, and afraid to say I think I deleted it from my pc. Sorry!

Getting into the android files it's a lot easier.

Could I ask what are you loading the meshes into the level with??

Are you actually able to see and render things on the screen or something??

I must admit I'm a tad loat, more of web dev then anything so this is still all pretty new to me haha
Reply
Thanked by:
#10
Big Grin 
(01-17-2022, 02:24 PM)DancingTwix Wrote: No worries!!
Yeah the issue with getting product keys and the like are why I put looking into the switch one hold, and afraid to say I think I deleted it from my pc. Sorry!

Getting into the android files it's a lot easier.

Could I ask what are you loading the meshes into the level with??

Are you actually able to see and render things on the screen or something??

I must admit I'm a tad loat, more of web dev then anything so this is still all pretty new to me haha

I load the meshes just by change the level file, and yes, it can render things on the screen.

I'm also more familiar with the web develop, but I also do some iOS reverse...

I have some video file, I'm not sure how to upload here. If you want to see it, you can add my discord [Image: biggrin.png] --> Chara#9030
Reply
Thanked by:
#11
(01-17-2022, 02:24 PM)DancingTwix Wrote: No worries!!
Yeah the issue with getting product keys and the like are why I put looking into the switch one hold, and afraid to say I think I deleted it from my pc. Sorry!

Getting into the android files it's a lot easier.

Could I ask what are you loading the meshes into the level with??

Are you actually able to see and render things on the screen or something??

I must admit I'm a tad loat, more of web dev then anything so this is still all pretty new to me haha

Mesh files are compiled Ogre meshes. Sky runs on the ogre2 (ogre-next) engine, and the level.object.bins are their own format.
They have tgcl magic headers and are most likely ports from Journey with slight modifications.  Due to the fact that the meshes are compiled it is quite tricky to load them into any modelling software or edit them in any ways. What is possible however is designing your own meshes and then compiling them into ogre2 meshes to get the game to load them. This is my discord tag: Lukas#8962. Hit me up if you feel like it.


Attached Files Thumbnail(s)
   
Reply
Thanked by:
#12
(04-04-2022, 03:23 AM)ether0x1 Wrote:
(01-17-2022, 02:24 PM)DancingTwix Wrote: No worries!!
Yeah the issue with getting product keys and the like are why I put looking into the switch one hold, and afraid to say I think I deleted it from my pc. Sorry!

Getting into the android files it's a lot easier.

Could I ask what are you loading the meshes into the level with??

Are you actually able to see and render things on the screen or something??

I must admit I'm a tad loat, more of web dev then anything so this is still all pretty new to me haha

Mesh files are compiled Ogre meshes. Sky runs on the ogre2 (ogre-next) engine, and the level.object.bins are their own format.
They have tgcl magic headers and are most likely ports from Journey with slight modifications.  Due to the fact that the meshes are compiled it is quite tricky to load them into any modelling software or edit them in any ways. What is possible however is designing your own meshes and then compiling them into ogre2 meshes to get the game to load them. This is my discord tag: Lukas#8962. Hit me up if you feel like it.

how did you get that mesh to load in blender?
i've tried using the blender2ogre plugin, but it doesn't work for me.
Reply
Thanked by:
#13
(04-18-2022, 02:06 AM)aeropteryx Wrote:
(04-04-2022, 03:23 AM)ether0x1 Wrote:
(01-17-2022, 02:24 PM)DancingTwix Wrote: No worries!!
Yeah the issue with getting product keys and the like are why I put looking into the switch one hold, and afraid to say I think I deleted it from my pc. Sorry!

Getting into the android files it's a lot easier.

Could I ask what are you loading the meshes into the level with??

Are you actually able to see and render things on the screen or something??

I must admit I'm a tad loat, more of web dev then anything so this is still all pretty new to me haha

Mesh files are compiled Ogre meshes. Sky runs on the ogre2 (ogre-next) engine, and the level.object.bins are their own format.
They have tgcl magic headers and are most likely ports from Journey with slight modifications.  Due to the fact that the meshes are compiled it is quite tricky to load them into any modelling software or edit them in any ways. What is possible however is designing your own meshes and then compiling them into ogre2 meshes to get the game to load them. This is my discord tag: Lukas#8962. Hit me up if you feel like it.

how did you get that mesh to load in blender?
i've tried using the blender2ogre plugin, but it doesn't work for me.

Same here, any updates on this? I'd love to be able to load these meshes.
Reply
Thanked by:
#14
Still no updates on this, huh?
Reply
Thanked by:
#15
Hi,

I independently worked on reverse engineering Sky on Android since June 2020, though by October 2020 I had put the project off due to lack of time. I discovered a number of details, but I had stopped short of publishing anything as I did not want TGC to begin obfuscating the builds while they still had their core Android developers on it. I think it's fair to say that three years on, the core team has likely moved on to other projects (and so have I), so I would be happy to share anything I have to help you renew the endeavor. Sky's highly immersive artistry was emotionally moving for me, and my aspiration was to create a map of my own and to publish videos on it.

As you know, Sky uses an in-house engine written in C++ targeting ARM64. The music uses FMOD; there are about 6 hours of music present in the game, encoded in Ogg Vorbis at 64 kbps. In the sound banks, you'll see a number of tracks that appear to have been unused in the game.

I performed about 16 hours' worth of analysis under Ghidra on version 0.10.0 (build 151406). A number of findings:
  • Device compatibility is hardcoded into a table. Every device has a predefined "rating" that determines the max graphics preset that the game can run at. Only devices with a rating of >=10,000 can run Sky at 60 fps. I constructed a CSV for this and even joined it at some point with the Google Play official device table, but I'll paste a link later as posting a link on my first post would probably get my account autoflagged for spam.
    At the time, the highest-rated devices were the iPhone 11, the 2018 iPad Pro, the OnePlus 7T, the Meizu 6s Pro, the Samsung Galaxy Flip (which is actually my phone today), and the ZTE Axon 10 Pro.
  • There is some DRM present. Sky uses the Google Play License Verification Library (LVL) to ensure that players didn't download the APK from somewhere else. There are some other rudimentary DRM schemes as well.
  • Lootboxes were once in development, as their classes were present in the code.
  • The game was originally intended to have throne guards and turrets with projectiles, as their classes were also present in the code.
  • Game functions are heavily integrated with the Lua runtime for fast prototyping. You can dump pretty much any game object and call most native functions from Lua.

With some work, I was able to intercept some, but not all, of the network traffic. It's part HTTP, part WebSockets, and a lot peer-to-peer ENet UDP.

Textures use ETC2 with RGBA, but I couldn't find tooling for it. Seems like you found it Smile

Levels seem to use a novel format that is based on the concept of metaballs. Apparently, designers used an in-house Maya plugin to create the levels - refer to "Gnomon - Art of Sky: Children of the Light" on YouTube, which describes the game's art pipeline in great detail (start at 46:20 for details on map design). Like everything, the lighting has to be baked into the level data, which produces the "BstBaked.meshes" file that you see. I once speculated that "BST" refers to "Blue Sky Thinking" which was referred to by one of the Lua files, but it probably refers to a binary search tree/BSP. It's not an important detail. There's a level compiler intact in the game binary.

The renderer was also created in-house due to the desire at the time to accommodate for as many devices as possible and minimize memory footprint. More info is available in the video above.

Meshes also seemed to use a novel format, which I concentrated most of my time on but didn't make much progress. There were a number of branches in the decompilation output due to support for older mesh versions. There was also a lot of optimized NEON math that Ghidra refused to display in an intelligible format. Thankfully things only get better with Ghidra.

(04-04-2022, 03:23 AM)ether0x1 Wrote:
(01-17-2022, 02:24 PM)DancingTwix Wrote: No worries!!
Yeah the issue with getting product keys and the like are why I put looking into the switch one hold, and afraid to say I think I deleted it from my pc. Sorry!

Getting into the android files it's a lot easier.

Could I ask what are you loading the meshes into the level with??

Are you actually able to see and render things on the screen or something??

I must admit I'm a tad loat, more of web dev then anything so this is still all pretty new to me haha

Mesh files are compiled Ogre meshes. Sky runs on the ogre2 (ogre-next) engine, and the level.object.bins are their own format.
They have tgcl magic headers and are most likely ports from Journey with slight modifications.  Due to the fact that the meshes are compiled it is quite tricky to load them into any modelling software or edit them in any ways. What is possible however is designing your own meshes and then compiling them into ogre2 meshes to get the game to load them. This is my discord tag: Lukas#8962. Hit me up if you feel like it.

This is an interesting (and potentially helpful) finding, considering that I had never encountered any indication that any part of the engine was actually based on Ogre3d. Since Ogre3d is MIT-licensed, I wonder why they haven't posted any open-source licenses anywhere. Not sure why I didn't ask them earlier, considering they use some other basic OSS libraries as well (like ENet and OpenSSL).

Still, I've been looking for strings and symbols present in ogre-next and can't find any in Sky. They must have written an Ogre-compatible mesh loader, but it's hard to tell because the Ogre binary spec is undocumented. The Ogre format also assumes that each file is comprised of a stream of chunks, much like PNG. But I see in Sky that the mesh loader goes straight to iterating through a predefined number of LODs and loading mesh and occlusion data for each one.

I hope Cunningham's law works in our favor if I posted something wrong. Feel free to PM me for my Discord username if you're interested in even more details. Hope this helps.
Reply
Thanked by:


Forum Jump: