2017-10-07 23:13:42 +00:00
|
|
|
# Infos
|
2020-01-03 02:22:09 +00:00
|
|
|
|
2017-10-07 23:13:42 +00:00
|
|
|
- Engine: ScrapEngine
|
|
|
|
- Ingame Scripting Language: Python 1.5.2
|
|
|
|
|
2019-09-03 19:24:00 +00:00
|
|
|
# Launch options:
|
|
|
|
|
|
|
|
- `-console`: open external console window on start
|
|
|
|
- `-wideWindow`: start game in widescreen mode
|
|
|
|
|
2019-03-03 22:38:12 +00:00
|
|
|
# Functions identified:
|
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
## Ingame-Console (Ctrl+\^ or right click on titlebar and select "switch console") (Handler@`0x402190`):
|
|
|
|
|
2018-12-22 03:24:34 +00:00
|
|
|
* `<Command>`: Try to evaluate Command as Python expression
|
|
|
|
* `:<Var>`: Get Game Engine Global Variable
|
|
|
|
* `:<Var> <Val>`: Set Game Engine Global Variable
|
|
|
|
* `?`: Show all Global Variable
|
2019-03-12 22:43:26 +00:00
|
|
|
* `?<String>`: Show all Global Variable matching `<String>`
|
|
|
|
* `/<command>`: Run Command defined in `QuickConsole.py`: `import quickconsole;quickconsole.%s()`
|
|
|
|
* `/<command> <arg>,<arg>`: Run function in `QuickConsole.py` with argument(s) `import quickconsole;quickconsole.%s(%s)`
|
2017-10-07 23:13:42 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
## External Console (Scenegraph Debugging?) (Handler @ `0x5f9520`):
|
|
|
|
|
2018-12-22 03:24:34 +00:00
|
|
|
* `listar luces`
|
|
|
|
* `listar`
|
2019-03-12 22:43:26 +00:00
|
|
|
* `arbol` (Patch Scrap.exe@offset 0x314bc9 replace 0x20 with 0x00 (or just type `arbol ` with a space at the end))
|
2018-12-22 03:24:34 +00:00
|
|
|
* `mem`
|
|
|
|
* `ver uniones`
|
2017-10-07 23:13:42 +00:00
|
|
|
* Easter Eggs:
|
2019-03-03 22:38:12 +00:00
|
|
|
* `imbecil`
|
|
|
|
* `idiota`
|
|
|
|
* `capullo`
|
2018-12-22 03:24:34 +00:00
|
|
|
|
2019-03-03 22:38:12 +00:00
|
|
|
## Python Stuff
|
2020-01-03 02:22:09 +00:00
|
|
|
|
|
|
|
- `0x79C698`: Modules List (Module Name as `char*` followed by Pointer to Init Function)
|
|
|
|
- `0x5A8FB0`: InitPyMod
|
|
|
|
- `0x5A8390`: PyExec
|
|
|
|
|
|
|
|
## Other interesting Memory Addresses
|
|
|
|
|
|
|
|
- `0x852914`: D3D8-Device pointer
|
|
|
|
- `0x7FCC00`: number of opened `.packed` files
|
|
|
|
- `0x84cb64`: pointer to console command handler
|
|
|
|
- `0x7fac84`: pointer to C++ callback list structure
|
|
|
|
- `0x80b2cc`: pointer to ActionClassList (???)
|
|
|
|
- `0x807a20`: pointer to SScorer (ingame GUI/Menu/Text system) structure (???)
|
|
|
|
- `0x80a398`: pointer to SoundSystem (???)
|
|
|
|
- `0x8b18f0`: pointer to Models Data (can be dumped using scenegraph debugging console)
|
|
|
|
- `0x8b18f4`: pointer to Scenes Data (can be dumped using scenegraph debugging console)
|
|
|
|
- `0x8b18f8`: pointer to active Models Data (can be dumped using scenegraph debugging console)
|
|
|
|
|
|
|
|
## Hash-function used in Hash-Tables
|
|
|
|
|
|
|
|
```c
|
|
|
|
unsigned long hash(const unsigned char *s)
|
|
|
|
{
|
|
|
|
unsigned long h = 0, high;
|
|
|
|
while ( *s )
|
|
|
|
{
|
|
|
|
h = ( h << 4 ) + *s++;
|
|
|
|
if ( high = h & 0xF0000000 )
|
|
|
|
h ^= high >> 24;
|
|
|
|
h &= ~high;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-10-07 23:13:42 +00:00
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
## Other Functions:
|
2019-03-03 22:38:12 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
Check `r2_analyze.py` for full list
|
|
|
|
|
|
|
|
## File Index struct @ `0x7fcbec`
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
|
|
|
struct FileEntry {
|
|
|
|
uint32_t offset;
|
|
|
|
uint32_t size;
|
|
|
|
uint32_t unk; // seems to always be 0xBADFOO1
|
|
|
|
unsigned char* path;
|
|
|
|
FileEntry* next; // next entry in hashtable chain
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FileIDX {
|
|
|
|
uint32_t size;
|
|
|
|
FileEntry** entries;
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
## Packed Index struct (array @ `0x7fc1b0`)
|
|
|
|
```cpp
|
|
|
|
struct PackedIDX {
|
|
|
|
void** VMT;
|
|
|
|
unsigned char* filename;
|
|
|
|
uint32_t locked; // not sure
|
|
|
|
void* data;
|
|
|
|
uint32_t seek;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## C(++)-Callbacks @ `0x7fac84`
|
|
|
|
|
|
|
|
Structure:
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
struct CPP_Callback {
|
|
|
|
const char* name;
|
|
|
|
void* func;
|
|
|
|
CPP_Callback* left;
|
|
|
|
CPP_Callback* right;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Game engine Variables Pointer @ `0x7FBE4C`
|
|
|
|
|
|
|
|
Structure:
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
struct GameVar {
|
|
|
|
GameVar* next;
|
|
|
|
const char* name;
|
|
|
|
const char* desc;
|
|
|
|
uint8_t subtype;
|
|
|
|
uint8_t type;
|
|
|
|
uint16_t unk;
|
|
|
|
void* value;
|
|
|
|
void* def_value;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Types
|
|
|
|
|
|
|
|
| Value | Type |
|
|
|
|
| ------ | ----------------------- |
|
|
|
|
| `0x10` | const char* |
|
|
|
|
| `0x20` | int32_t |
|
|
|
|
| `0x30` | User Control Definition |
|
|
|
|
| `0x40` | float |
|
|
|
|
| `0x60` | Callback function |
|
2019-12-03 23:28:36 +00:00
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
## Game World/State Pointer @ `0x7fe944`
|
|
|
|
|
|
|
|
Points to World struct
|
|
|
|
|
2019-09-01 20:45:07 +00:00
|
|
|
| Offset | Type | Description |
|
|
|
|
| ------ | ------------------------ | -------------------------------------- |
|
|
|
|
| 0x0000 | `void**` | Virtual Method Table |
|
|
|
|
| 0x0004 | `uint32_t` | Size of Entity Hashtable |
|
|
|
|
| 0x0008 | `void**` | Pointer to Entity Hashtable |
|
2020-01-03 02:22:09 +00:00
|
|
|
| 0x0288 | `pyEntity*` | UsrEntity[0] |
|
|
|
|
| 0x028C | `pyEntity*` | UsrEntity[1] |
|
|
|
|
| 0x0290 | `pyEntity*` | UsrEntity[2] |
|
|
|
|
| 0x0294 | `pyEntity*` | UsrEntity[3] |
|
2019-09-01 20:45:07 +00:00
|
|
|
| 0x02B8 | `uint32_t` | Number of entity lists |
|
|
|
|
| 0x02BC | `void**` | Pointer to entity list Hashtable |
|
|
|
|
| 0x0330 | `float[3]` | Time (why 3 times?) |
|
|
|
|
| 0x1C6C | `float` | Alarm level |
|
|
|
|
| 0x1C68 | `float` | Alarm Grow Level |
|
|
|
|
| 0x2158 | `float` | Used in `World_Init` |
|
|
|
|
| 0x2170 | `???` | Used in `World_Init` |
|
|
|
|
| 0x2180 | `float` | Used in `World_Init` |
|
|
|
|
| 0x2188 | `void*` | Used in `World_Init` |
|
|
|
|
| 0x218C | `void*` | Used in `World_Init` |
|
|
|
|
| 0x2190 | `float` | Used in `World_Init` |
|
|
|
|
| 0x2198 | `void*` | Used in `World_Init` |
|
|
|
|
| 0x219C | `void*` | Used in `World_Init` |
|
|
|
|
| 0x21A0 | `void**` | Used in `World_Init` (VTable pointer?) |
|
|
|
|
| 0x21B4 | `void**` | Used in `World_Init` (VTable pointer?) |
|
|
|
|
| 0x21C8 | `???` | Used in `World_Init` |
|
|
|
|
| 0x2204 | `uint32_t` or `uint16_t` | Used in `World_Init` |
|
|
|
|
| 0x2230 | `float` | Used in `World_Init` |
|
|
|
|
| 0x2238 | `???` | Used in `World_Init` |
|
|
|
|
| 0x2254 | `float` | Used in `World_Init` |
|
2019-03-03 22:38:12 +00:00
|
|
|
|
|
|
|
## Entity Hash Table
|
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
Hash-function used: [PJW](https://en.wikipedia.org/wiki/PJW_hash_function) (Same parameters as the example implementation)
|
2019-03-03 22:38:12 +00:00
|
|
|
|
|
|
|
Entry format:
|
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
```cpp
|
|
|
|
struct HT_Entry {
|
|
|
|
void* data;
|
|
|
|
const char* key;
|
|
|
|
HT_Entry* next;
|
|
|
|
}
|
|
|
|
```
|
2019-03-03 22:38:12 +00:00
|
|
|
|
|
|
|
Data format:
|
2017-10-07 23:13:42 +00:00
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
| Offset | Type | Description |
|
2019-09-01 20:45:07 +00:00
|
|
|
| ------ | ------------- | ------------------------ |
|
2019-03-12 22:43:26 +00:00
|
|
|
| 0x0 | `void**` | Virtual Method Table (?) |
|
|
|
|
| 0x4 | `const char*` | name as string |
|
|
|
|
| 0x14 | `void*` | pointer to self (why?) |
|
|
|
|
| 0x28 | `float[3]` | Position in Game World |
|
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
## EntityList Hash Table
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
- `Near`
|
|
|
|
- `First`
|
|
|
|
- `Num`
|
|
|
|
- `OnDeath`
|
|
|
|
- `OnDamage`
|
2019-09-01 20:45:07 +00:00
|
|
|
|
2019-03-03 22:38:12 +00:00
|
|
|
# File Formats
|
2017-10-09 19:11:08 +00:00
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
## .packed File Format:
|
2020-01-03 02:22:09 +00:00
|
|
|
|
2019-02-28 16:50:52 +00:00
|
|
|
```
|
|
|
|
Header:
|
|
|
|
"BFPK\0\0\0\0"
|
|
|
|
Int32ul: number of files
|
|
|
|
for each file:
|
|
|
|
Int32ul: path length
|
|
|
|
String: path
|
|
|
|
Int32ul: size
|
|
|
|
Int32ul: offset in file
|
|
|
|
```
|
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
# Virtual Method Tables:
|
2019-03-12 22:43:26 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
check `r2_analyze.py` for full list
|
2019-03-12 22:43:26 +00:00
|
|
|
|
2019-02-28 16:50:52 +00:00
|
|
|
## Loading Custom Content (not really working)
|
2020-01-03 02:22:09 +00:00
|
|
|
|
2018-12-22 03:24:34 +00:00
|
|
|
1. Create a folder `mods`
|
|
|
|
2. Drop a `*.packed` file into it
|
2019-03-12 22:43:26 +00:00
|
|
|
3. Change `Scrap.cfg` as follows
|
|
|
|
1. Add `ModPathName = mods`
|
|
|
|
2. Add `ModFileName = <filename>`
|
2018-12-22 03:24:34 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
## Interesting file inside `Data.packed`
|
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
* `m3d.ini`: Rendering Engine Configuration
|
|
|
|
* `scripts/`: Game Engine Scripts
|
2017-10-09 19:11:08 +00:00
|
|
|
|
2017-10-07 23:13:42 +00:00
|
|
|
|
|
|
|
# How to enable External Console:
|
2019-03-01 20:07:46 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
1. Right click on the title bar (in windowed mode) and click "Switch Console"
|
|
|
|
2. or Use a custom Content Pack (**untested!**)
|
2019-03-01 20:07:46 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
# How to enable Scenegraph debugging console
|
|
|
|
|
|
|
|
1. extract `Data.packed`
|
|
|
|
2. in m3d.ini uncomment (remove `;`) `ConsolaWnd` (GUI Console) and/or `ConsolaTxt` (Text Console) and set the value to `SI`
|
|
|
|
3. repack `Data.packed`
|
2017-10-07 23:13:42 +00:00
|
|
|
|
2017-10-09 19:11:08 +00:00
|
|
|
# Misc. Interesting things
|
2020-01-03 02:22:09 +00:00
|
|
|
|
|
|
|
- `sys.path` contains "./lib" so you can import your own Python Modules
|
|
|
|
- Games crashes when starting a multiplayer server and feeding it random UDP data
|
2019-03-12 22:43:26 +00:00
|
|
|
|
|
|
|
# Code Snippets
|
|
|
|
|
|
|
|
## [Kaitai Struct](http://kaitai.io/) Parser for .packed files
|
2020-01-03 02:22:09 +00:00
|
|
|
|
2019-03-12 22:43:26 +00:00
|
|
|
```yaml
|
|
|
|
meta:
|
|
|
|
id: packed
|
|
|
|
application: Scrapland
|
|
|
|
file-extension: packed
|
|
|
|
endian: le
|
|
|
|
xref: http://wiki.xentax.com/index.php/Scrapland_PACKED
|
|
|
|
license: MIT
|
|
|
|
encoding: UTF-8
|
|
|
|
seq:
|
|
|
|
- id: magic
|
|
|
|
contents: BFPK
|
|
|
|
doc: File Magic
|
2020-01-03 02:22:09 +00:00
|
|
|
- id: version
|
2019-03-12 22:43:26 +00:00
|
|
|
contents: [0,0,0,0]
|
2020-01-03 02:22:09 +00:00
|
|
|
doc: File Version
|
2019-03-12 22:43:26 +00:00
|
|
|
- id: num_files
|
|
|
|
type: u4
|
|
|
|
doc: Number of files
|
|
|
|
- id: files
|
|
|
|
type: file_entry
|
|
|
|
repeat: expr
|
|
|
|
repeat-expr: num_files
|
2020-01-03 02:22:09 +00:00
|
|
|
doc: Entry for each file
|
2019-03-12 22:43:26 +00:00
|
|
|
types:
|
|
|
|
file_entry:
|
|
|
|
seq:
|
|
|
|
- id: path_len
|
|
|
|
type: u4
|
|
|
|
doc: Length of file path
|
|
|
|
- id: path
|
|
|
|
type: str
|
|
|
|
size: path_len
|
|
|
|
doc: File path
|
|
|
|
- id: size
|
|
|
|
type: u4
|
|
|
|
doc: File size
|
|
|
|
- id: offset
|
|
|
|
type: u4
|
|
|
|
doc: Absoulte File offset
|
|
|
|
instances:
|
|
|
|
data:
|
|
|
|
pos: offset
|
|
|
|
size: size
|
|
|
|
```
|
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
# TODO:
|
2019-03-12 22:43:26 +00:00
|
|
|
|
2020-01-03 02:22:09 +00:00
|
|
|
- Figure out how C++ Callbacks work
|
|
|
|
- Figure out SM3 (Models), CM3 (Animations) file formats
|
|
|
|
- Figure out rest of World structure
|
|
|
|
- Figure out rest of Entity structure
|