forked from ReScrap/ScrapHacks
Lots of changes, expand to read
- Add notes folder with MDBook documentation (the NOTES.md file was getting kind of large) - Add rz_analyze.py, does the same a r2_analyze.py just with Rizin instead of radare2 so the project can be loaded in Cutter (*and* it's faster) - Add Scrap.rzdb, Rizin database for the Scrap.exe executable - Add Scrapper_rs, Rust version of .packed extractor and repacker - replace helplib.txt with helplib.md - add Py_Docs folder which contains generated documentation for the binary python modules built into Scrap.exe
This commit is contained in:
parent
43c01e81d2
commit
7afdfb5869
|
@ -261,9 +261,13 @@ __pycache__/
|
|||
*.pyc
|
||||
|
||||
.history
|
||||
**/.history
|
||||
|
||||
ScrapHacks/build/*
|
||||
ScrapHacks/src/D3D8_VMT.hpp
|
||||
.vscode/c_cpp_properties.json
|
||||
tools/*.log
|
||||
frida/*.mp
|
||||
frida/dump.mp.xz
|
||||
terms.py
|
||||
hist_restore.py
|
||||
|
|
121
NOTES.md
121
NOTES.md
|
@ -11,7 +11,6 @@
|
|||
- `-dedicated`: start in mutliplayer dedicated server mode (needs to be used with `-server`)
|
||||
- `-server`: start in multiplayer server mode
|
||||
|
||||
# Functions identified:
|
||||
|
||||
## Ingame-Console (Ctrl+\^ or right click on titlebar and select "switch console") (Handler@`0x402190`):
|
||||
|
||||
|
@ -134,56 +133,57 @@ struct GameVar {
|
|||
|
||||
Types
|
||||
|
||||
| Value | Type |
|
||||
|-------|-----------------|
|
||||
| `0x1` | const char* |
|
||||
| `0x2` | int32_t |
|
||||
| `0x3` | List of Defines |
|
||||
| `0x4` | float |
|
||||
| `0x5` | function |
|
||||
| `0x6` | Script function |
|
||||
Value | Type
|
||||
----- | ---------------
|
||||
`0x1` | const char*
|
||||
`0x2` | int32_t
|
||||
`0x3` | List of Defines
|
||||
`0x4` | float
|
||||
`0x5` | function
|
||||
`0x6` | Script function
|
||||
|
||||
## Game World/State Pointer @ `0x7fe944`
|
||||
|
||||
Points to World struct
|
||||
|
||||
| Offset | Type | Description |
|
||||
|--------|--------------------------|----------------------------------------|
|
||||
| 0x0000 | `void**` | Virtual Method Table |
|
||||
| 0x0004 | `uint32_t` | Size of Entity Hashtable |
|
||||
| 0x0008 | `void**` | Pointer to Entity Hashtable |
|
||||
| 0x0288 | `pyEntity*` | UsrEntity[0] |
|
||||
| 0x028C | `pyEntity*` | UsrEntity[1] |
|
||||
| 0x0290 | `pyEntity*` | UsrEntity[2] |
|
||||
| 0x0294 | `pyEntity*` | UsrEntity[3] |
|
||||
| 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` |
|
||||
Offset | Type | Description
|
||||
------ | ------------------------ | --------------------------------------
|
||||
0x0000 | `void**` | Virtual Method Table
|
||||
0x0004 | `uint32_t` | Size of Entity Hashtable
|
||||
0x0008 | `void**` | Pointer to Entity Hashtable
|
||||
0x00B0 | `??` | Pointer to Ground Object (?)
|
||||
0x0288 | `pyEntity*` | UsrEntity[0]
|
||||
0x028C | `pyEntity*` | UsrEntity[1]
|
||||
0x0290 | `pyEntity*` | UsrEntity[2]
|
||||
0x0294 | `pyEntity*` | UsrEntity[3]
|
||||
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`
|
||||
|
||||
## cPyEntity structure
|
||||
|
||||
| Offset | Type | Description |
|
||||
|--------|----------|----------------------|
|
||||
| 0x0000 | `void**` | Virtual Method Table |
|
||||
| 0x0004 | `char*` | Name |
|
||||
| 0x0008 | `void*` | ??? |
|
||||
Offset | Type | Description
|
||||
------ | -------- | --------------------
|
||||
0x0000 | `void**` | Virtual Method Table
|
||||
0x0004 | `char*` | Name
|
||||
0x0008 | `void*` | ???
|
||||
|
||||
|
||||
## Entity Hash Table
|
||||
|
@ -202,12 +202,12 @@ struct HT_Entry {
|
|||
|
||||
Data format:
|
||||
|
||||
| Offset | Type | Description |
|
||||
|--------|---------------|--------------------------|
|
||||
| 0x0 | `void**` | Virtual Method Table (?) |
|
||||
| 0x4 | `const char*` | name as string |
|
||||
| 0x14 | `void*` | pointer to self (why?) |
|
||||
| 0x28 | `float[3]` | Position in Game World |
|
||||
Offset | Type | Description
|
||||
------ | ------------- | ------------------------
|
||||
0x0 | `void**` | Virtual Method Table (?)
|
||||
0x4 | `const char*` | name as string
|
||||
0x14 | `void*` | pointer to self (why?)
|
||||
0x28 | `float[3]` | Position in Game World
|
||||
|
||||
## EntityList Hash Table
|
||||
|
||||
|
@ -254,16 +254,28 @@ Player Join Packet
|
|||
09c9e028 35 2c 31 35 2c 31 02 00 00 00 5,15,1....
|
||||
```
|
||||
|
||||
| Message | Description |
|
||||
|------------------------------------------|-------------------------------------------------------------------|
|
||||
| `5c68625c32383230395c73637261706c616e64` | "Scrapland Server" announcement broadcast (`\hb\28209\scrapland`) |
|
||||
| `7f01000007` | Retrieve Game info |
|
||||
| `48423d35323932322c3235363a323830383600` | Connection Information (`HB=52922,256:28086`) |
|
||||
Message | Description
|
||||
---------------------------------------- | -----------------------------------------------------------------
|
||||
`5c68625c32383230395c73637261706c616e64` | "Scrapland Server" announcement broadcast (`\hb\28209\scrapland`)
|
||||
`7f01000007` | Retrieve Game info
|
||||
`48423d35323932322c3235363a323830383600` | Connection Information (`HB=52922,256:28086`)
|
||||
|
||||
# [Notes](NOTES.md)
|
||||
|
||||
## File Formats
|
||||
|
||||
File Extension | Description | Chunked
|
||||
-------------- | ------------------------ | -------
|
||||
.packed | Game Data Archive | n
|
||||
.cm3 | Animation file | y
|
||||
.sm3 | 3d model file | y
|
||||
.dum | Dummy (map object) file | y
|
||||
.pth | AI Path | n
|
||||
.emi | Emission maps/Materials? | y
|
||||
.amc | Collision Data | y
|
||||
.ini | Configuration | n
|
||||
.txa | Texture Animation Config | n
|
||||
|
||||
- [Chunked](file_formats/chunked.md)
|
||||
- [Packed](file_formats/packed.md)
|
||||
- [AI Pathfinding Graph](file_formats/ai_path.md)
|
||||
|
@ -290,7 +302,6 @@ check `r2_analyze.py` for full list
|
|||
# How to enable External Console:
|
||||
|
||||
1. Right click on the title bar (in windowed mode) and click "Switch Console"
|
||||
2. or Use a custom Content Pack (**untested!**)
|
||||
|
||||
# How to enable Scenegraph debugging console
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# SAI
|
||||
|
||||
- *GetStateChar*: `<built-in function GetStateChar>`
|
||||
```
|
||||
GetStateChar(string nameEntity) : Devuelve el estado de la IA del personaje.
|
||||
|
||||
```
|
||||
- *AddVehicleRace*: `<built-in function AddVehicleRace>`
|
||||
```
|
||||
bool AddVehicleRace(cWithLifeEntity *entidad) : Asigna entidad como perteneciente a carrera.
|
||||
```
|
||||
- *SetStateVehicle*: `<built-in function SetStateVehicle>`
|
||||
```
|
||||
SetStateVehicle(0, string nameAgent) : Estado sin movimiento ni disparo.
|
||||
SetStateVehicle(1, float posObjX, float posObjY, float posObjZ, radiusObj, string nameAgent) : Estado alcanzar posición.
|
||||
SetStateVehicle(2, string nameObjectiveDin, string nameAgent) : Estado persecución enemigo.
|
||||
SetStateVehicle(3, string nameAgent) : Estado en ruta.
|
||||
SetStateVehicle(4, string nameAgent) : Estado tráfico.
|
||||
SetStateVehicle(5, string nameAgent, float distStop) : Estado huída con parada.
|
||||
SetStateVehicle(6, float posObjX, float posObjY, float posObjZ, radiusObj, string nameAgent) : Estado alcanzar meta en carrera.
|
||||
SetStateVehicle(7, string nameObjectiveDin, string nameAgent) : Estado persecución.
|
||||
SetStateVehicle(8, string nameObjectiveDin, string nameAgent) : Estado persecución enemigo con uso de hook.
|
||||
|
||||
```
|
||||
- *EnableAIChar*: `<built-in function EnableAIChar>`
|
||||
```
|
||||
EnableAIChar(string nameEntity, int enable, int stupidPathfinding) : Habilita la IA del personaje indicando características asociadas al movimiento).
|
||||
```
|
||||
- *BuildGraph*: `<built-in function BuildGraph>`
|
||||
```
|
||||
BuildGraph(int numNodesRadius, float sizeNodeX, float sizeNodeY, float sizeNodeZ) : Crea el Grafo asociado al Pathfinding
|
||||
```
|
||||
- *AnalizeMap*: `<built-in function AnalizeMap>`
|
||||
```
|
||||
AnalizeMap(float sizeNode) : Analiza características mapa.
|
||||
```
|
||||
- *SetStateChar*: `<built-in function SetStateChar>`
|
||||
```
|
||||
SetStateChar(0, string nameAgent) : Estado sin movimiento ni disparo.
|
||||
SetStateChar(1, string nameAgent, float vel, int withStopTemp) : Estado en ruta.
|
||||
SetStateChar(2, string nameAgent, string nameObjective, float vel) : Estado en persecución objetivo con acción.
|
||||
SetStateChar(3, string nameAgent, string nameObjective, float vel) : Estado en persecución objetivo sin acción.
|
||||
SetStateChar(4, string nameAgent, float posObjX, float posObjY, float posObjZ, float orientX, float orientY, float orientZ, float radiusObj, float velObj) : Estado ir a un punto con orientación final.
|
||||
SetStateChar(5, string nameAgent, string nameObjective, float vel) : Estado huída de otro personaje.
|
||||
SetStateChar(6, string nameAgent, float centerPatrolZone.x, float centerPatrolZone.y, float centerPatrolZone.z, float radiusPatrolZone, float vel, int withStopTemp) : Estado patrulla de zona.
|
||||
SetStateChar(7, string nameAgent, string nameObjective, float vel) : Estado en persecución objetivo con acción.
|
||||
```
|
||||
- *AnalizeGraph2D*: `<built-in function AnalizeGraph2D>`
|
||||
```
|
||||
AnalizeGraph2D() : Analiza características grafo 2D.
|
||||
```
|
||||
- *GetNextRacePoint*: `<built-in function GetNextRacePoint>`
|
||||
```
|
||||
(point) GetNextRacePoint(initialPoint, minDist, maxDist) : A partir de un punto inicial 'initialPoint', una distancia mínima 'minDist' y una distancia máxima 'maxDist', devuelve un punto aleatorio a partir del grafo 3D de la IA en el interior actual.
|
||||
```
|
||||
- *GetOD*: `<built-in function GetOD>`
|
||||
- *SetRotStaticObj*: `<built-in function SetRotStaticObj>`
|
||||
```
|
||||
bool SetRotStaticObj(float maxVelRot, float limIncVelRot) : Asigna rotaciones para movimiento hacia objetivo estático.
|
||||
```
|
||||
- *IniAI*: `<built-in function IniAI>`
|
||||
```
|
||||
IniAI(levelPath) : Inicializa AI para un nivel.
|
||||
```
|
||||
- *GetStateVehicle*: `<built-in function GetStateVehicle>`
|
||||
```
|
||||
GetStateVehicle(string nameEntity) : Devuelve el estado de la IA del vehículo.
|
||||
0 : Estado sin movimiento ni disparo.
|
||||
1 : Estado alcanzar posición.
|
||||
2 : Estado persecución enemigo.
|
||||
3 : Estado en ruta.
|
||||
4 : Estado tráfico.
|
||||
5 : Estado huída con parada.
|
||||
6 : Estado alcanzar meta en carrera.
|
||||
7 : Estado persecución.
|
||||
8 : Estado persecución enemigo con uso de hook.
|
||||
9 : Estado sin movimiento ni disparo por estar objetivo en posición inválida.
|
||||
|
||||
```
|
||||
- *BuildGraph2D*: `<built-in function BuildGraph2D>`
|
||||
```
|
||||
BuildGraph2D(int numNodesRadius, float sizeNodeX, float sizeNodeY, float sizeNodeZ) : Crea el Grafo asociado al Pathfinding 2D
|
||||
```
|
||||
- *AnalizeTraffic*: `<built-in function AnalizeTraffic>`
|
||||
```
|
||||
AnalizeTraffic() : Analiza características tráfico.
|
||||
```
|
||||
- *SetInertia*: `<built-in function SetInertia>`
|
||||
```
|
||||
void SetInertia(bool inertia) : Indica si la nave tiene inercia.
|
||||
```
|
||||
- *InitVehicleRace*: `<built-in function InitVehicleRace>`
|
||||
```
|
||||
InitVehicleRace() : Inicializa carrera de vehículos.
|
||||
```
|
||||
- *GetNearestItemLife*: `<built-in function GetNearestItemLife>`
|
||||
```
|
||||
(itemName) GetNearestItemLife(vehicleName)) : Devuelve el item de vida más cercano a una nave dada.
|
||||
```
|
||||
- *EnableAIVehicle*: `<built-in function EnableAIVehicle>`
|
||||
```
|
||||
EnableAIVehicle(string nameEntity, int enable, int controlStrafe, int controlBrake, int stupidPathfinding) : Habilita la IA del vehículo indicando características asociadas al movimiento).
|
||||
```
|
||||
- *AnalizeGraph*: `<built-in function AnalizeGraph>`
|
||||
```
|
||||
AnalizeGraph() : Analiza características grafo.
|
||||
```
|
||||
- *GetRandomVisibilityPoint*: `<built-in function GetRandomVisibilityPoint>`
|
||||
```
|
||||
(point) GetRandomVisibilityPoint() : Devuelve un punto aleatorio del grafo de puntos de visibilidad.
|
||||
```
|
||||
- *GetReposCharPos*: `<built-in function GetReposCharPos>`
|
||||
```
|
||||
(x,y,z) GetReposCharPos((x,y,z) ,EntityClass,[,EntityName]) : Obtiene un punto de reposicion de personaje (si entidad, se asigna).
|
||||
Retorna (None) si falla
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# SAct
|
||||
|
||||
- *CreateClass*: `<built-in function CreateClass>`
|
||||
```
|
||||
CreateClass(classname) : Crea una clase de objeto animado
|
||||
```
|
||||
- *CreateAction*: `<built-in function CreateAction>`
|
||||
```
|
||||
CreateAction(varname) : Crea una accion en la clase actual.
|
||||
```
|
||||
- *DelClass*: `<built-in function DelClass>`
|
||||
```
|
||||
DelClass(classname) : Crea una clase de objeto animado
|
||||
```
|
||||
- *SetCls*: `<built-in function SetCls>`
|
||||
```
|
||||
SetCls(varname,value) : Modifica el valor de una variable de una clase objeto animado
|
||||
```
|
||||
- *GetCls*: `<built-in function GetCls>`
|
||||
```
|
||||
GetCls(varname) : Obtiene el valor de una variable de una clase objeto animado
|
||||
```
|
||||
- *GetClass*: `<built-in function GetClass>`
|
||||
```
|
||||
GetClass(classname) : Activa una clase de objeto animado
|
||||
```
|
||||
- *SetAct*: `<built-in function SetAct>`
|
||||
```
|
||||
SetAct(varname,value) : Modifica el valor de una variable de la accion de una clase objeto animado
|
||||
```
|
||||
- *GetAct*: `<built-in function GetAct>`
|
||||
```
|
||||
GetAct(varname) : Obtiene el valor de una variable de la accion de una clase objeto animado
|
||||
```
|
||||
- *GetAction*: `<built-in function GetAction>`
|
||||
```
|
||||
GetAction(varname) : Obtiene una accion de la clase actual.
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# SFX
|
||||
|
||||
- *CharacterConversor*: `<built-in function CharacterConversor>`
|
||||
```
|
||||
FXCharacterConversor(CharacterName, ConversorName, phase) : Conversor de Personajes.
|
||||
```
|
||||
- *BishopSellLife*: `<built-in function BishopSellLife>`
|
||||
```
|
||||
FXBishopSellLife(AttackerName, AttackedName) : Efecto de dar vida (de Attacker [Bishop ó NULL] a Attacked[Usuario]).
|
||||
```
|
||||
- *CharacterConversion*: `<built-in function CharacterConversion>`
|
||||
```
|
||||
FXCharacterConversion(AttackerName, AttackedName, time) : Conversión de Personajes.
|
||||
```
|
||||
- *EmbeddedSet*: `<built-in function EmbeddedSet>`
|
||||
```
|
||||
FXEmbeddedSet(EntityName, FXType) : Asigna el controlador de efectos embedidos.
|
||||
```
|
||||
- *ShipExplosion*: `<built-in function ShipExplosion>`
|
||||
```
|
||||
ShipExplosion(V3D Pos, V3D Vel, float scale, float time, float nflames, bool bcolision) : Explosión de la nave.
|
||||
```
|
||||
- *MoneyTransfer*: `<built-in function MoneyTransfer>`
|
||||
```
|
||||
FXMoneyTransfer(EntityFrom, EntityTo, Time) : Transferencia de dinero
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# SInput
|
||||
|
||||
- *Rumble*: `<built-in function Rumble>`
|
||||
```
|
||||
Rumble(iPlayer,Left,Right,Time) : Inicializa el rumble de un pad.
|
||||
```
|
||||
- *GetActionSet*: `<built-in function GetActionSet>`
|
||||
```
|
||||
string GetActionSet() : Obtiene el set de acciones Actual...
|
||||
```
|
||||
- *SetInputFunc*: `<built-in function SetInputFunc>`
|
||||
```
|
||||
SetInputFunc(iPlayer,modfunc) : agrega la funcion callback de entrada modfunc(iPlayer,string)
|
||||
```
|
||||
- *GetCursorChar*: `<built-in function GetCursorChar>`
|
||||
```
|
||||
GetCursorChar(iPlayer) : Obtiene el (x,y,caracter) que indican el estado del cursor.
|
||||
```
|
||||
- *GetDefinedEntry*: `<built-in function GetDefinedEntry>`
|
||||
```
|
||||
value GetDefinedEntry(iPlayer,ActionSet,Action,Device) : obtiene una cadena con la primera definicion del control que encuentre
|
||||
```
|
||||
- *AbortListenToDefine*: `<built-in function AbortListenToDefine>`
|
||||
```
|
||||
AbortListenToDefine() : Aborta la redefinicion en curso
|
||||
```
|
||||
- *ResetToDefault*: `<built-in function ResetToDefault>`
|
||||
```
|
||||
ResetToDefault(iPlayer,ActionSet,Action) : Pone todas las entradas de los controles a valores por defecto.
|
||||
```
|
||||
- *ResetToSplit*: `<built-in function ResetToSplit>`
|
||||
```
|
||||
ResetToSplit() : Resetea el sistema de entrada de datos para iniciar el modo split screen.
|
||||
```
|
||||
- *GetDefinedList*: `<built-in function GetDefinedList>`
|
||||
```
|
||||
GetDefinedList(iPlayer,ActionSet,Action) : obtiene una cadena con la definicion de controles
|
||||
```
|
||||
- *AssingEntry*: `<built-in function AssingEntry>`
|
||||
```
|
||||
int AssingEntry(Device,Entry,Player,ActionSet,Action) : Asigna una entrada... retorna 0 o el Nro de parametro erroneo
|
||||
```
|
||||
- *CheckPadButton*: `<built-in function CheckPadButton>`
|
||||
```
|
||||
CheckPadButton() : Chequea el estado de un determinado botón del pad.
|
||||
```
|
||||
- *ListenToDefine*: `<built-in function ListenToDefine>`
|
||||
```
|
||||
ListenToDefine(iPlayer,ActionSet,Action,LaFunction) : Espera a que el usuario mueva un control y lo redefine
|
||||
```
|
||||
- *SetString*: `<built-in function SetString>`
|
||||
```
|
||||
SetString(iPlayer,String) : Modifica la cadena de entrada de texto.
|
||||
```
|
||||
- *Bind*: `<built-in function Bind>`
|
||||
```
|
||||
Bind(iPlayer,ActionSet,Action) : obtiene una cadena con la definicion de controles
|
||||
```
|
||||
- *GetEntry*: `<built-in function GetEntry>`
|
||||
```
|
||||
(Player,Action) GetEntry(Device,Entry,ActionSet) : Obtiene una entrada, (0,) si vacia
|
||||
```
|
||||
- *GetVirtualKeyboard*: `<built-in function GetVirtualKeyboard>`
|
||||
```
|
||||
GetVirtualKeyboard() : Obtiene el (W,H,Board) que son datos del keyboard virtual.
|
||||
```
|
||||
- *GetString*: `<built-in function GetString>`
|
||||
```
|
||||
GetString(iPlayer) : Obtiene la cadena de entrada de texto.
|
||||
```
|
||||
- *SetVirtualKeyboard*: `<built-in function SetVirtualKeyboard>`
|
||||
```
|
||||
SetVirtualKeyboard(tipo de teclado) : Cambia el teclado virtual
|
||||
```
|
||||
- *SetActionSet*: `<built-in function SetActionSet>`
|
||||
```
|
||||
SetActionSet(string name) : Pone el set de acciones requerido...
|
||||
```
|
||||
- *ClearDefinedList*: `<built-in function ClearDefinedList>`
|
||||
```
|
||||
ClearDefinedList(iPlayer,ActionSet,Action) : Elimina todas las entradas de un control.
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# SLogic
|
||||
|
||||
- *IsEnemyActive*: `<built-in function IsEnemyActive>`
|
||||
```
|
||||
int IsEnemyActive() : Indica si hay un enemigo activo, mirando el contenido de la lista de enemigos y en el tráfico.
|
||||
```
|
||||
- *ChangeZoneState*: `<built-in function ChangeZoneState>`
|
||||
```
|
||||
void ChangeZoneState(zoneId, state): Pone el estado de una zona de dominación
|
||||
```
|
||||
- *SetOnFloor*: `<built-in function SetOnFloor>`
|
||||
```
|
||||
void SetOnFloor(Entity) : Pone una entidad en el suelo
|
||||
```
|
||||
- *ChangeBatonState*: `<built-in function ChangeBatonState>`
|
||||
```
|
||||
void ChangeBatonState(pos, state): Actualiza el estado del testigo en el modo dominación
|
||||
```
|
||||
- *SetShipToRegenerate*: `<built-in function SetShipToRegenerate>`
|
||||
```
|
||||
void SetShipToRegenerate(shipName, regSpeed,regEndSpeed): Pone una nave a regenerarse
|
||||
```
|
||||
- *SetDominationZones*: `<built-in function SetDominationZones>`
|
||||
```
|
||||
void SetDominationZones(zonesList): Establece la lista de posiciones de las zonas de dominación en la super apuesta de dominación
|
||||
```
|
||||
- *Flash*: `<built-in function Flash>`
|
||||
```
|
||||
void Flash((x,y,z),radius) : Pone una entidad en el suelo
|
||||
```
|
||||
- *GetNearestShip*: `<built-in function GetNearestShip>`
|
||||
```
|
||||
Name GetNearestShip(pos) : Cicla por varias listas y devuelve la nave más cercana a la posición indicada
|
||||
```
|
||||
- *SendSentinelToWatch*: `<built-in function SendSentinelToWatch>`
|
||||
```
|
||||
void SendSentinelToWatch(Pos) : Envia a un centinela a inspeccionar una posicion
|
||||
```
|
||||
- *UpdateTauntEndTime*: `<built-in function UpdateTauntEndTime>`
|
||||
```
|
||||
void UpdateTauntEndTime(time): Tiempo final del taunt
|
||||
```
|
||||
- *GearAttack*: `<built-in function GearAttack>`
|
||||
```
|
||||
void GearAttack(Entity) : Envia a un Gear a atacar a una entidad
|
||||
```
|
||||
- *SetCharState*: `<built-in function SetCharState>`
|
||||
```
|
||||
void SetCharState(entityName, state, entityTargetName) : Pone a una entidad en un estado de logica y un target determinados
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
# SNet
|
||||
|
||||
- *SendUsrString*: `<built-in function SendUsrString>`
|
||||
```
|
||||
SendUsrString(id,string) : -1 significa a todo el mundo en modo servidor, para cliente id se ignora
|
||||
```
|
||||
- *InitServer*: `<built-in function InitServer>`
|
||||
```
|
||||
InitServer(LevelPath,MaxPlayers,ipport) : Intenta inicializar el servidor.
|
||||
```
|
||||
- *GetBotName*: `<built-in function GetBotName>`
|
||||
```
|
||||
GetBotName() : Obtiene un nombre valido de entidad jugador manejada por el servidor (bot o jugador local)
|
||||
```
|
||||
- *CloseServer*: `<built-in function CloseServer>`
|
||||
```
|
||||
CloseServer(LevelPath) : Acaba el servidor y carga un nivel.
|
||||
```
|
||||
- *IsClient*: `<built-in function IsClient>`
|
||||
```
|
||||
IsClient() : 1 si esta activado el sistema cliente
|
||||
NOTA: Scrap.GetNetFlags() tiene el flag cliente activado
|
||||
si la coneccion se hizo efectiva
|
||||
```
|
||||
- *ServerChangeLevel*: `<built-in function ServerChangeLevel>`
|
||||
```
|
||||
ServerChangeLevel(resource name) : carga el siguiente nivel.
|
||||
```
|
||||
- *DoneBrowser*: `<built-in function DoneBrowser>`
|
||||
```
|
||||
DoneBrowser() : Cierra el browser de red local.
|
||||
```
|
||||
- *InitClient*: `<built-in function InitClient>`
|
||||
```
|
||||
InitClient(ipAddress,ipport) : Inicia el proceso de coneccion con el servidor.
|
||||
```
|
||||
- *CloseClient*: `<built-in function CloseClient>`
|
||||
```
|
||||
CloseClient(LevelPath) : Acaba el cliente y carga un nivel.
|
||||
```
|
||||
- *IsServer*: `<built-in function IsServer>`
|
||||
```
|
||||
IsServer() : 1 si esta activado el sistema servidor
|
||||
NOTA: es para depuracion, mejor use Scrap.GetNetFlags()
|
||||
```
|
||||
- *GetObjName*: `<built-in function GetObjName>`
|
||||
```
|
||||
GetObjName() : Obtiene un nombre valido de Objeto cualesquiera.
|
||||
```
|
||||
- *GetMyClientShip*: `<built-in function GetMyClientShip>`
|
||||
```
|
||||
GetMyClientShip() : retorna el nombre de su nave.
|
||||
```
|
||||
- *ModifyUsrData*: `<built-in function ModifyUsrData>`
|
||||
```
|
||||
ModifyUsrData(ClientId) :
|
||||
modifica desde el servidor los datos locales.
|
||||
```
|
||||
- *AddResource*: `<built-in function AddResource>`
|
||||
```
|
||||
resourceid AddResource(resource name) : intenta agregar un recurso si este no existe. -1 si el pool esta lleno
|
||||
```
|
||||
- *SendChatString*: `<built-in function SendChatString>`
|
||||
```
|
||||
SendChatString(id,string) : -1 significa a todo el mundo en modo servidor, para cliente id se ignora
|
||||
```
|
||||
- *GetClientData*: `<built-in function GetClientData>`
|
||||
```
|
||||
GetClientData() : Obtiene la tupla (ipaddress,ipport)
|
||||
```
|
||||
- *InitBrowser*: `<built-in function InitBrowser>`
|
||||
```
|
||||
InitBrowser(port) : Inicializa el browser de red local.
|
||||
```
|
||||
- *SendMasterString*: `<built-in function SendMasterString>`
|
||||
```
|
||||
SendMasterString(string) : envia una cadena al master. Si retorna cero no hay master.
|
||||
```
|
||||
- *PingInetSvrs*: `<built-in function PingInetSvrs>`
|
||||
```
|
||||
PingInetSvrs() : 1 exitoso. revisa el estado de los servidores en internet. Se realiza despues de browse.
|
||||
```
|
||||
- *IsMaster*: `<built-in function IsMaster>`
|
||||
```
|
||||
IsMaster() : 1 si esta activado el sistema cliente
|
||||
NOTA: Scrap.GetNetFlags() tiene el flag cliente activado
|
||||
si la coneccion se hizo efectiva
|
||||
```
|
||||
- *GetServerData*: `<built-in function GetServerData>`
|
||||
```
|
||||
GetServerData() : Obtiene la tupla (Hostname,ipaddress,ipport)
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
# SScorer
|
||||
|
||||
- *SetCursor*: `<built-in function SetCursor>`
|
||||
```
|
||||
SetCursor(playernumber,CursorName) : pone un item del scorer como cursor
|
||||
```
|
||||
- *Show*: `<built-in function Show>`
|
||||
```
|
||||
Show(playernumber) : Activa el scorer.
|
||||
```
|
||||
- *GetTextArea*: `<built-in function GetTextArea>`
|
||||
```
|
||||
(width, height) GetTextArea(fontType, text) : obtiene la anchura y la altura de un texto dado el texto y el tipo de fuente
|
||||
```
|
||||
- *AddModel*: `<built-in function AddModel>`
|
||||
```
|
||||
AddModel(playernumber,Name,ModelFile,numanim,Radius) : Pre carga un modelo para usarse en el scorer.
|
||||
```
|
||||
- *SetOnPrev*: `<built-in function SetOnPrev>`
|
||||
```
|
||||
SetOnPrev(playernumber,CancelEvent) : Define la funcion que se ejecutara en el caso del pagina abajo.
|
||||
```
|
||||
- *AddChatMsg*: `<built-in function AddChatMsg>`
|
||||
```
|
||||
AddChatMsg(string,red,gree,blue) : Agrega un mensaje a la lista de chat.
|
||||
```
|
||||
- *GetOnCancel*: `<built-in function GetOnCancel>`
|
||||
```
|
||||
(CancelEvent)GetOnCancel(playernumber) : Devuelve la funcion que se ejecutara en el caso del escape.
|
||||
```
|
||||
- *GetDefault*: `<built-in function GetDefault>`
|
||||
```
|
||||
DefaultItemName GetDefault(playernumber) Obtiene el nombre del item por defecto
|
||||
```
|
||||
- *SetOnSpecialHint*: `<built-in function SetOnSpecialHint>`
|
||||
```
|
||||
SetOnSpecialHint(playernumber,SpecialHintTestFunc,SpecialHint) : Define la funcion que decide si se muestra un hint especial
|
||||
```
|
||||
- *SetConsole*: `<built-in function SetConsole>`
|
||||
```
|
||||
SetConsole(show) : oculta/ muestra la consola de pantalla completa
|
||||
```
|
||||
- *Get2DPos*: `<built-in function Get2DPos>`
|
||||
```
|
||||
(x,y) Get2DPos(vector3d) : obtiene en cordenadas de pantalla una posicion del escenario
|
||||
```
|
||||
- *GetActual*: `<built-in function GetActual>`
|
||||
```
|
||||
ActualItem GetActual(playernumber) Obtiene el item actual
|
||||
```
|
||||
- *SetOnNext*: `<built-in function SetOnNext>`
|
||||
```
|
||||
SetOnNext(playernumber,CancelEvent) : Define la funcion que se ejecutara en el caso del pagina abajo.
|
||||
```
|
||||
- *SetMPFunc*: `<built-in function SetMPFunc>`
|
||||
```
|
||||
SetMPFunc(playernumber,Callback) : Callback(id,showmpscorer) (muestra oculta el scorer multiplayer)
|
||||
```
|
||||
- *Set*: `<built-in function Set>`
|
||||
```
|
||||
Set(playernumber,itemname,varname,value) : Modifica el valor de una variable de un item
|
||||
```
|
||||
- *SetSpeechCallback*: `<built-in function SetSpeechCallback>`
|
||||
```
|
||||
SetSpeechCallback(Callback) : Especifica la funcion callback que será llamada
|
||||
```
|
||||
- *Get*: `<built-in function Get>`
|
||||
```
|
||||
Get(playernumber,itemname,varname) : Obtiene el valor de una variable de un item
|
||||
```
|
||||
- *GetMenuAccept*: `<built-in function GetMenuAccept>`
|
||||
```
|
||||
GetMenuAccept(id) : Devuelve el estado de la acción de menu aceptar.
|
||||
```
|
||||
- *SetDefault*: `<built-in function SetDefault>`
|
||||
```
|
||||
SetDefault(playernumber,DefaultItemName) : pone un item del scorer 'por defecto'
|
||||
```
|
||||
- *CancelSpeech*: `<built-in function CancelSpeech>`
|
||||
```
|
||||
CancelSpeech(time) : cancela un mensaje remoto
|
||||
```
|
||||
- *SetHeadMonitor*: `<built-in function SetHeadMonitor>`
|
||||
```
|
||||
SetHeadMonitor(Head,Msg,anm) : Especifica la cabeza que será usada en el monitor y el mensaje.
|
||||
```
|
||||
- *Add*: `<built-in function Add>`
|
||||
```
|
||||
Add(playernumber,itemname,itemtype,AtEnd) : Agrega un item al scorer.
|
||||
```
|
||||
- *SetMarkerSprite*: `<built-in function SetMarkerSprite>`
|
||||
```
|
||||
SetMarkerSprite(id,SpriteName) : pone un sprite como marcador
|
||||
```
|
||||
- *PreloadTexture*: `<built-in function PreloadTexture>`
|
||||
```
|
||||
PreloadTexture(filename) : Precarga una textura
|
||||
```
|
||||
- *SetMsgText*: `<built-in function SetMsgText>`
|
||||
```
|
||||
SetMsgText(text,time) : Muestra un mensaje de sistema y lo desactiva en el tiempo de mundo time
|
||||
```
|
||||
- *Fade*: `<built-in function Fade>`
|
||||
```
|
||||
Fade(id,(r,g,b,a),(r,g,b,a),time) : Realiza un fade de rgba a rgba.
|
||||
```
|
||||
- *Clear*: `<built-in function Clear>`
|
||||
```
|
||||
Clear(playernumber) : Limpia el scorer completamente.
|
||||
```
|
||||
- *SetCinema*: `<built-in function SetCinema>`
|
||||
```
|
||||
SetCinema(id,status,time) : Activa el modo escena de cine.
|
||||
```
|
||||
- *SetSpeechText*: `<built-in function SetSpeechText>`
|
||||
```
|
||||
SetSpeechText(text,time,r,g,b) : activa el texto de una conversacion que durará un tiempo espeficico
|
||||
```
|
||||
- *SetOnCancel*: `<built-in function SetOnCancel>`
|
||||
```
|
||||
SetOnCancel(playernumber,CancelEvent) : Define la funcion que se ejecutara en el caso del escape.
|
||||
```
|
||||
- *Hide*: `<built-in function Hide>`
|
||||
```
|
||||
Hide(playernumber) : Desactiva el scorer.
|
||||
```
|
||||
- *SetLabelText*: `<built-in function SetLabelText>`
|
||||
```
|
||||
SetLabelText(text,time) : Muestra un rotulo de sistema y lo desactiva en el tiempo de mundo time
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
# SSound
|
||||
|
||||
- *StopVoice*: `<built-in function StopVoice>`
|
||||
```
|
||||
StopVoice(channel) : stop a voice on the specified channel.
|
||||
```
|
||||
- *Play*: `<built-in function Play>`
|
||||
```
|
||||
Play('soundname'[,vol,pan]) : ejecuta un sonido con el volumen deseado.
|
||||
```
|
||||
- *PlaySound*: `<built-in function PlaySound>`
|
||||
```
|
||||
PlaySound((x,y,z),'soundname',vol[,AttenIni,AttenEnd,Doppler]) : ejecuta un sonido en la posicion dada con el volumen deseado.
|
||||
```
|
||||
- *SetMusic*: `<built-in function SetMusic>`
|
||||
```
|
||||
SetMusic('soundname'[,vol]) : set the file of the background music.
|
||||
```
|
||||
- *LoadSound*: `<built-in function LoadSound>`
|
||||
```
|
||||
LoadSound(soundfile) : carga un sonido desde un archivo empaquetado.
|
||||
```
|
||||
- *OpenVoice*: `<built-in function OpenVoice>`
|
||||
```
|
||||
OpenVoice(name,channel) : Preload a voice on a channel.
|
||||
```
|
||||
- *StopAllSounds*: `<built-in function StopAllSounds>`
|
||||
```
|
||||
SCRAP_StopAllSounds() : para todos los sonidos.
|
||||
```
|
||||
- *SetMusicVolume*: `<built-in function SetMusicVolume>`
|
||||
```
|
||||
SetMusicVolume(vel) : set the volume of the background music.
|
||||
```
|
||||
- *UsePS*: `<built-in function UsePS>`
|
||||
```
|
||||
UsePS(Name) : Crea un nuevo sonido posicional
|
||||
```
|
||||
- *SetVoiceString*: `<built-in function SetVoiceString>`
|
||||
```
|
||||
SetVoiceString(channel,volume) : set string user data of a voice.
|
||||
```
|
||||
- *VoiceRemain*: `<built-in function VoiceRemain>`
|
||||
```
|
||||
VoiceRemain(channel,time) : return the remaining time of a voice.
|
||||
```
|
||||
- *CreatePS*: `<built-in function CreatePS>`
|
||||
```
|
||||
CreatePS(Name) : Crea un nuevo sonido posicional
|
||||
```
|
||||
- *SetPS*: `<built-in function SetPS>`
|
||||
```
|
||||
SetPS(name,varname,value) : Modifica el valor de una variable de un sonido posicional
|
||||
```
|
||||
- *PlayVoice*: `<built-in function PlayVoice>`
|
||||
```
|
||||
PlayVoice(channel) : play a voice loaded on the specified channel.
|
||||
```
|
||||
- *DeleteAllSounds*: `<built-in function DeleteAllSounds>`
|
||||
```
|
||||
SCRAP_DeleteAllSounds() : elimina todos los sonidos.
|
||||
```
|
||||
- *GetPS*: `<built-in function GetPS>`
|
||||
```
|
||||
GetPS(name,varname) : Obtiene el valor de una variable de un sonido posicional
|
||||
```
|
||||
- *SetVoiceVolume*: `<built-in function SetVoiceVolume>`
|
||||
```
|
||||
SetVoiceVolume(channel,volume) : set the volume of a voice.
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# SVec
|
||||
|
||||
- *Mod*: `<built-in function Mod>`
|
||||
```
|
||||
res Mod(v1) : Devuelve el modulo de un vector
|
||||
```
|
||||
- *Norm*: `<built-in function Norm>`
|
||||
```
|
||||
res Norm(v1) : Normaliza un vector
|
||||
```
|
||||
- *Prod*: `<built-in function Prod>`
|
||||
```
|
||||
res Prod(v1,f) : multiplica un vector por un numero
|
||||
```
|
||||
- *ModSqr*: `<built-in function ModSqr>`
|
||||
```
|
||||
res ModSqr(v1) : Devuelve el modulo (al cuadrado) de un vector
|
||||
```
|
||||
- *DProd*: `<built-in function DProd>`
|
||||
```
|
||||
res DProd(v1,v2) : Calcula el producto escalar de dos vectores
|
||||
```
|
||||
- *Add*: `<built-in function Add>`
|
||||
```
|
||||
res Add(v1,v2) : suma dos vectores 3D
|
||||
```
|
||||
- *CProd*: `<built-in function CProd>`
|
||||
```
|
||||
vRes CProd(v1,v2) : Calcula el producto vectorial de dos vectores
|
||||
```
|
||||
- *NormAng*: `<built-in function NormAng>`
|
||||
```
|
||||
rAng NormAng(Ang) : Normaliza un angulo
|
||||
```
|
||||
- *Sub*: `<built-in function Sub>`
|
||||
```
|
||||
res Sub(v1,v2) : Resta dos vectores 3D
|
||||
```
|
||||
- *GetRotAng*: `<built-in function GetRotAng>`
|
||||
```
|
||||
AngX,AngY GetRotAng(vec) : Obtiene la rotacion de un vector
|
||||
```
|
||||
- *Rotate3D*: `<built-in function Rotate3D>`
|
||||
```
|
||||
res Rotate3D(src,rot) : Rota un vector
|
||||
```
|
||||
- *GetAngle*: `<built-in function GetAngle>`
|
||||
```
|
||||
Ang GetAngle(vec) : Obtiene el ángulo entre dos vectores
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# SWeap
|
||||
|
||||
- *SetSWeap*: `<built-in function SetSWeap>`
|
||||
```
|
||||
SetSWeap(numammo,svar,svalue) : Pone un valor cadena de las municiones
|
||||
```
|
||||
- *FillPriority*: `<built-in function FillPriority>`
|
||||
```
|
||||
FillPriority() : Inizializa las prioridades de las armas
|
||||
```
|
||||
- *GetSAmmo*: `<built-in function GetSAmmo>`
|
||||
```
|
||||
GetSAmmo(numammo,svar) : Obtiene un valor cadena de las municiones
|
||||
```
|
||||
- *SetFAmmo*: `<built-in function SetFAmmo>`
|
||||
```
|
||||
GetFAmmo(numammo,svar,fvalue) : Pone un valor numerico de las municiones
|
||||
```
|
||||
- *InitWeap*: `<built-in function InitWeap>`
|
||||
```
|
||||
InitWeap(num) : Inicializa las armas num es el numero de armas
|
||||
```
|
||||
- *GetNWeap*: `<built-in function GetNWeap>`
|
||||
```
|
||||
GetNWeap() : Obtiene el numero de armas en el juego
|
||||
```
|
||||
- *GetFAmmo*: `<built-in function GetFAmmo>`
|
||||
```
|
||||
GetFAmmo(numammo,svar) : Obtiene un valor numerico de las municiones
|
||||
```
|
||||
- *GetFirstiWeap*: `<built-in function GetFirstiWeap>`
|
||||
```
|
||||
GetFirstiWeap() : Obtiene el arma primera y por defecto
|
||||
```
|
||||
- *GetSWeap*: `<built-in function GetSWeap>`
|
||||
```
|
||||
GetSWeap(numWeap,svar) : Obtiene un valor cadena de las municiones
|
||||
```
|
||||
- *GetFWeap*: `<built-in function GetFWeap>`
|
||||
```
|
||||
GetFWeap(numWeap,svar) : Obtiene un valor numerico de las municiones
|
||||
```
|
||||
- *GetNAmmo*: `<built-in function GetNAmmo>`
|
||||
```
|
||||
GetNAmmo() : Obtiene el numero de municiones en el juego
|
||||
```
|
||||
- *NetExec*: `<built-in function NetExec>`
|
||||
```
|
||||
NetExec() : Rutinas de red de los misiles
|
||||
```
|
||||
- *SetFWeap*: `<built-in function SetFWeap>`
|
||||
```
|
||||
GetFWeap(numWeap,svar,fvalue) : Pone un valor numerico de las municiones
|
||||
```
|
||||
- *InitAmmo*: `<built-in function InitAmmo>`
|
||||
```
|
||||
InitAmmo(num) : Inicializa las municiones del juego
|
||||
```
|
||||
- *SetSAmmo*: `<built-in function SetSAmmo>`
|
||||
```
|
||||
SetSAmmo(numammo,svar,svalue) : Pone un valor cadena de las municiones
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
# Scrap
|
||||
|
||||
- *DropDebris*: `<built-in function DropDebris>`
|
||||
```
|
||||
DropDebris(name,size) : Lanza un objeto que cae y rebota hasta que desaparece
|
||||
```
|
||||
- *ShowGVars*: `<built-in function ShowGVars>`
|
||||
```
|
||||
ShowGVars() : Muestra una lista de todas las variables globales
|
||||
```
|
||||
- *GetNewLevelPath*: `<built-in function GetNewLevelPath>`
|
||||
```
|
||||
levelpath GetNewLevelPath() : Obtiene el path del próximo nivel
|
||||
```
|
||||
- *SetTime*: `<built-in function SetTime>`
|
||||
```
|
||||
SetTime(Time) : Cambia el tiempo del mundo en segundos
|
||||
```
|
||||
- *SetCam*: `<built-in function SetCam>`
|
||||
```
|
||||
SetCam(i,name) : Activa una camara
|
||||
```
|
||||
- *PreloadAnm*: `<built-in function PreloadAnm>`
|
||||
```
|
||||
PreloadAnm(ObjFilename,AnmFilename) : Precarga una animacion
|
||||
```
|
||||
- *GetCam*: `<built-in function GetCam>`
|
||||
```
|
||||
name GetCam(i) : Obtiene el nombre de una entidad camara
|
||||
```
|
||||
- *GetLockAlarm*: `<built-in function GetLockAlarm>`
|
||||
```
|
||||
Scrap.GetLockAlarm() : verdadero si la alarma esta bloqueada
|
||||
```
|
||||
- *AddItem*: `<built-in function AddItem>`
|
||||
```
|
||||
Scrap.AddItem(Life, string name, int life) : Add Item Life.
|
||||
Scrap.AddItem(Ammo, string name, int typeAmmo, int ammo) : Add Item Ammo.
|
||||
```
|
||||
- *Verbose*: `<built-in function Verbose>`
|
||||
```
|
||||
Verbose(string name) : Muestra un mensaje de parloteo por la consola
|
||||
```
|
||||
- *StartDummySearch*: `<built-in function StartDummySearch>`
|
||||
```
|
||||
StartDummySearch(name,usewildcards) : Inicia la busqueda de dummies en el mapa
|
||||
```
|
||||
- *OpenPack*: `<built-in function OpenPack>`
|
||||
```
|
||||
OpenPack(string PackPath) : Abre un archivo *.packed
|
||||
```
|
||||
- *LaunchDashboard*: `<built-in function LaunchDashboard>`
|
||||
```
|
||||
int Scrap.LaunchDashboard() : sale del juego y ejecuta el dashboard.
|
||||
```
|
||||
- *SaveGameVars*: `<built-in function SaveGameVars>`
|
||||
```
|
||||
Scrap.SaveGameVars(str, str) : Salva un juego en un archivo, con un nombre opcional
|
||||
```
|
||||
- *SphereCall*: `<built-in function SphereCall>`
|
||||
```
|
||||
Scrap.SphereCall(x,y,z,radius,´strmask´,´callback´,[IgnoreGeometry=1]) : testea una esfera y llama a ´callback´ por cada entidad que colisiona
|
||||
```
|
||||
- *SetTimeSpeed*: `<built-in function SetTimeSpeed>`
|
||||
```
|
||||
SetTimeSpeed(TimeSpeed) : Cambia la velocidad del tiempo del mundo.
|
||||
```
|
||||
- *Preload3DObject*: `<built-in function Preload3DObject>`
|
||||
```
|
||||
Preload3DObject(filename,scalex,scaley,scalez) : Precarga un objeto 3D
|
||||
```
|
||||
- *TestLine*: `<built-in function TestLine>`
|
||||
```
|
||||
((x,y,z),s) TestLine((x,y,z),(fz,fy,fz),'strmask') : testea una linea y devuelve el nombre de la entidad y punto de colision o '' si es el mapa o None
|
||||
```
|
||||
- *GetFreeBlocks*: `<built-in function GetFreeBlocks>`
|
||||
```
|
||||
int Scrap.GetFreeBlocks() : obtiene los bloques libres en el disco duro.
|
||||
```
|
||||
- *IncSaveVar*: `<built-in function IncSaveVar>`
|
||||
```
|
||||
int Scrap.IncSaveVar(str[,value]) : incrementa un contador de estadisticas
|
||||
```
|
||||
- *DeselectProfile*: `<built-in function DeselectProfile>`
|
||||
```
|
||||
Scrap.DeselectProfile() : deselecciona el profile actual.
|
||||
```
|
||||
- *GetMoney*: `<built-in function GetMoney>`
|
||||
```
|
||||
money Scrap.GetMoney() : Devuelve el liquido disponible.
|
||||
```
|
||||
- *CreateElements*: `<built-in function CreateElements>`
|
||||
```
|
||||
CreateElements() : Crea una lista de elementos estaticos que pertenecen al mapa.
|
||||
```
|
||||
- *NextDummySearch*: `<built-in function NextDummySearch>`
|
||||
```
|
||||
(s(ddd)(dd)i) NextDummySearch() : Obtiene el proximo dummy, sino None
|
||||
```
|
||||
- *CreateEntity*: `<built-in function CreateEntity>`
|
||||
```
|
||||
CreateEntity(name,x,y,z,type) : Crea una una entidad
|
||||
```
|
||||
- *LoadLevel*: `<built-in function LoadLevel>`
|
||||
```
|
||||
LoadLevel(string name) : Carga un nivel en el siguiente frame
|
||||
```
|
||||
- *DebugInput*: `<built-in function DebugInput>`
|
||||
```
|
||||
string DebugInput() : Detiene todo para iniciar la depuracion
|
||||
```
|
||||
- *GetLangStr*: `<built-in function GetLangStr>`
|
||||
```
|
||||
str Scrap.GetLangStr(Name) : Obtiene una cadena de lenguaje. '' si no existe.
|
||||
```
|
||||
- *Get*: `<built-in function Get>`
|
||||
```
|
||||
Get('GlobalVar') : Obtiene el valor de una variable global
|
||||
```
|
||||
- *SetAlarmChar*: `<built-in function SetAlarmChar>`
|
||||
```
|
||||
Scrap.SetAlarmChar(El_que_se_busca) : Modifica el personaje que se busca.
|
||||
```
|
||||
- *GetEntity*: `<built-in function GetEntity>`
|
||||
```
|
||||
GetEntity(string name) : Retorna una entidad
|
||||
```
|
||||
- *GetLanguage*: `<built-in function GetLanguage>`
|
||||
```
|
||||
lang Scrap.GetLanguage() : Obtiene la lengua actual. None si no fue inicializada.
|
||||
```
|
||||
- *Print*: `<built-in function Print>`
|
||||
```
|
||||
Print(string name) : Muestra un mensaje por la consola siempre
|
||||
```
|
||||
- *SwitchMissionArrows*: `<built-in function SwitchMissionArrows>`
|
||||
```
|
||||
SwitchMissionArrows(MainMissionFile,TargetMissionFile) : Cambia las flechas de mision primaria y secundaria (Modelos)
|
||||
```
|
||||
- *GetFarestParked*: `<built-in function GetFarestParked>`
|
||||
```
|
||||
Entity,Pos = Scrap.GetFarestParked([isparked[,fromPos]]) : Obtiene la nave aparcada mas lejana.
|
||||
```
|
||||
- *CreateSaveProfile*: `<built-in function CreateSaveProfile>`
|
||||
```
|
||||
int Scrap.CreateSaveProfile(str) : Crea un Save profile para X-Box y pone como actual.
|
||||
```
|
||||
- *ExtractPack*: `<built-in function ExtractPack>`
|
||||
```
|
||||
ExtractPack(string PackPath) : Extrae un archivo *.packed
|
||||
```
|
||||
- *SetLockAlarm*: `<built-in function SetLockAlarm>`
|
||||
```
|
||||
Scrap.SetLockAlarm(1/0) : Bloquea/desbloquea la alarma
|
||||
```
|
||||
- *SetSaveVar*: `<built-in function SetSaveVar>`
|
||||
```
|
||||
bool Scrap.SetSaveVar(Name,DefValue) : Modifica una variable (si puede)
|
||||
```
|
||||
- *ListModels*: `<built-in function ListModels>`
|
||||
```
|
||||
ListModels() : Muestra una lista de modelos y escenas
|
||||
```
|
||||
- *ConsoleOut*: `<built-in function ConsoleOut>`
|
||||
```
|
||||
ConsoleOut(string name) : Muestra un mensaje pyton por la consola
|
||||
```
|
||||
- *ScreenShot*: `<built-in function ScreenShot>`
|
||||
```
|
||||
ScreenShot(filename) : Screenshot of the current frame
|
||||
```
|
||||
- *SetMoney*: `<built-in function SetMoney>`
|
||||
```
|
||||
Scrap.SetMoney(money) : Determina el liquido disponible
|
||||
```
|
||||
- *GetFirst*: `<built-in function GetFirst>`
|
||||
```
|
||||
GetFirst() : Retorna la primera entuidad de la lista o none
|
||||
```
|
||||
- *LoadGameVars*: `<built-in function LoadGameVars>`
|
||||
```
|
||||
Scrap.LoadGameVars(str) : Carga un juego en un archivo
|
||||
```
|
||||
- *GetTime*: `<built-in function GetTime>`
|
||||
```
|
||||
GetTime() : Obtiene el tiempo del mundo en segundos
|
||||
```
|
||||
- *GetAlarmChars*: `<built-in function GetAlarmChars>`
|
||||
```
|
||||
(Actual, El_que_se_busca) Scrap.GetAlarmChars() : Obtiene los tipos de personaje que se buscan.
|
||||
```
|
||||
- *SetVideoCurrentMode*: `<built-in function SetVideoCurrentMode>`
|
||||
```
|
||||
SetVideoCurrentMode() : Set Video Current Mode Index
|
||||
```
|
||||
- *AddScheduledFunc*: `<built-in function AddScheduledFunc>`
|
||||
```
|
||||
AddScheduledFunc(time,func,params[,name]) : Ejecuta un codigo en python en un instante de tiempo.
|
||||
```
|
||||
- *ClosePack*: `<built-in function ClosePack>`
|
||||
```
|
||||
ClosePack() : Abre un archivo *.packed
|
||||
```
|
||||
- *CreateEntityList*: `<built-in function CreateEntityList>`
|
||||
```
|
||||
CreateEntityList(listName) : Crea una lista de entidades
|
||||
```
|
||||
- *ProcessDVF*: `<built-in function ProcessDVF>`
|
||||
```
|
||||
ProcessDVF(filename,command) : send a dvf command
|
||||
```
|
||||
- *SetAlarm*: `<built-in function SetAlarm>`
|
||||
```
|
||||
Scrap.SetAlarm(dialpos) : pone la alarma en una posicion (0 desactiva, 1 activa).
|
||||
```
|
||||
- *GetNearestParked*: `<built-in function GetNearestParked>`
|
||||
```
|
||||
Entity,Pos = Scrap.GetNearestParked([isparked[,fromPos]]) : Obtiene la nave aparcada mas cercana.
|
||||
```
|
||||
- *Set*: `<built-in function Set>`
|
||||
```
|
||||
Set('GlobalVar',val) : Modifica el valor de una variable global
|
||||
```
|
||||
- *PythonCompileAll*: `<built-in function PythonCompileAll>`
|
||||
```
|
||||
PythonCompileAll() : compila recursivamente los archivos .py
|
||||
```
|
||||
- *Rand*: `<built-in function Rand>`
|
||||
```
|
||||
Rand(min,max) : Obtiene un numero seudo-aleatorio entre (min,max)
|
||||
```
|
||||
- *Def*: `<built-in function Def>`
|
||||
```
|
||||
Def('GlobalVar') : Obtiene el valor por defecto de una variable global
|
||||
```
|
||||
- *Round*: `<built-in function Round>`
|
||||
```
|
||||
Round(num) : Redondea un numero real al entero más cercano.
|
||||
```
|
||||
- *ModelInfo*: `<built-in function ModelInfo>`
|
||||
```
|
||||
ModelInfo(name) : Muestra información sobre la jerarquía de nodos del modelo
|
||||
```
|
||||
- *UsrEntity*: `<built-in function UsrEntity>`
|
||||
```
|
||||
UsrEntity(ictr) : Retorna una entidad controlada por usario (personaje o nave)
|
||||
```
|
||||
- *GetAlarm*: `<built-in function GetAlarm>`
|
||||
```
|
||||
(active,dialpos,growcode) Scrap.GetAlarm() : Obtiene informacion de la alarma.
|
||||
```
|
||||
- *SetDebrisValue*: `<built-in function SetDebrisValue>`
|
||||
```
|
||||
SetDebrisValue(id,x,y,z) : id = 0:Posicion, 1:Angulos, 2:Velocidad, 3:Velocidad de rotacion
|
||||
```
|
||||
- *MusicPlayer*: `<built-in function MusicPlayer>`
|
||||
```
|
||||
MusicPlayer(filename[,command,param1]) : play music file
|
||||
```
|
||||
- *Des*: `<built-in function Des>`
|
||||
```
|
||||
Des('GlobalVar') : Obtiene el descriptor de una variable global
|
||||
```
|
||||
- *SetCallFunc*: `<built-in function SetCallFunc>`
|
||||
```
|
||||
Scrap.SetCallFunc('!funcname') : Especifica la funcion callback (c++) a llamar. (1 si existe)
|
||||
```
|
||||
- *SetDebrisSys*: `<built-in function SetDebrisSys>`
|
||||
```
|
||||
SetDebrisSys(name,initialnumber,MaxDist,Friction,Scale,Grav,bounce) crea/modifica un sistema de debris
|
||||
```
|
||||
- *Execute*: `<built-in function Execute>`
|
||||
```
|
||||
Scrap.Execute() : Ejecuta una funcion callback (c++).
|
||||
```
|
||||
- *AddParamf*: `<built-in function AddParamf>`
|
||||
```
|
||||
Scrap.AddParamf(Float) : Incluye un parametro a una funcion callback (c++).
|
||||
```
|
||||
- *PreloadLibrary*: `<built-in function PreloadLibrary>`
|
||||
```
|
||||
PreloadLibrary(LibraryName,CompiledFile) : Precarga una libreria de un archivo empaquetado
|
||||
```
|
||||
- *GetVideoCurrentMode*: `<built-in function GetVideoCurrentMode>`
|
||||
```
|
||||
GetVideoCurrentMode() : Get Video Current Mode Index
|
||||
```
|
||||
- *InitLoading*: `<built-in function InitLoading>`
|
||||
```
|
||||
InitLoading() Inicia la pantalla de carga rapida.
|
||||
```
|
||||
- *CallElements*: `<built-in function CallElements>`
|
||||
```
|
||||
CallElements('Function') : llama una funcion Function(Name,x,y,z,angx,angy)
|
||||
```
|
||||
- *GetTimeSpeed*: `<built-in function GetTimeSpeed>`
|
||||
```
|
||||
GetTimeSpeed() : Obtiene la velocidad del tiempo del mundo.
|
||||
```
|
||||
- *CreateSaveVar*: `<built-in function CreateSaveVar>`
|
||||
```
|
||||
bool Scrap.CreateSaveVar(Name,DefValue) : Crea una nueva variable (si puede)
|
||||
```
|
||||
- *EntityListGet*: `<built-in function EntityListGet>`
|
||||
```
|
||||
(value)Scrap.EntityListGet(listName, varName) : Obtiene el valor de una variable de una lista de entidades
|
||||
```
|
||||
- *DeleteProfile*: `<built-in function DeleteProfile>`
|
||||
```
|
||||
int Scrap.DeleteProfile(str) : Borra un profile de X-Box.
|
||||
```
|
||||
- *AddParami*: `<built-in function AddParami>`
|
||||
```
|
||||
Scrap.AddParami(int) : Incluye un parametro a una funcion callback (c++).
|
||||
```
|
||||
- *VideoPlayer*: `<built-in function VideoPlayer>`
|
||||
```
|
||||
VideoPlayer(filename[,command]) : play video file
|
||||
```
|
||||
- *SetLanguage*: `<built-in function SetLanguage>`
|
||||
```
|
||||
res Scrap.SetLanguage(Name[,forcetoreload]) : Modifica la lengua actual. false si ya es la lengua la selecionada
|
||||
```
|
||||
- *AddParams*: `<built-in function AddParams>`
|
||||
```
|
||||
Scrap.AddParams(string) : Incluye un parametro a una funcion callback (c++).
|
||||
```
|
||||
- *GetVideoModes*: `<built-in function GetVideoModes>`
|
||||
```
|
||||
GetVideoModes(NumMode) : Get Video Mode Info
|
||||
```
|
||||
- *GetSaveGamesList*: `<built-in function GetSaveGamesList>`
|
||||
```
|
||||
[(fecha, slot)] Scrap.GetSaveGamesList() : Devuelve una lista de tuplas donde para cada tupla el primer elemento indica el nombre (fecha) del archivo y el segundo elemento indica el slot del que se leerá la partida. La lista está ordenada por la fecha, de la más reciente a la más antigua.
|
||||
```
|
||||
- *GetLevelPath*: `<built-in function GetLevelPath>`
|
||||
```
|
||||
levelpath GetLevelPath() : Obtiene el path del nivel actual
|
||||
```
|
||||
- *BuildFont*: `<built-in function BuildFont>`
|
||||
```
|
||||
BuildFont(name,size) : Construye un archivo de fuente de letras a partir de un .TGA dado
|
||||
```
|
||||
- *DeleteScheduledFuncs*: `<built-in function DeleteScheduledFuncs>`
|
||||
```
|
||||
DeleteScheduledFuncs(name) : Borra las scheduled funcs creadas con un nombre dado.
|
||||
```
|
||||
- *GetNetFlags*: `<built-in function GetNetFlags>`
|
||||
```
|
||||
GetNetFlags() : Obtiene la tupla de flags : client, server, dedicated
|
||||
```
|
||||
- *GetSaveVar*: `<built-in function GetSaveVar>`
|
||||
```
|
||||
value Scrap.GetSaveVar(Name) : obtiene una variable o devuelve none
|
||||
```
|
||||
- *GetLangEntries*: `<built-in function GetLangEntries>`
|
||||
```
|
||||
[str] Scrap.GetLangEntries(Name) : Obtiene un subconjunto de entradas de la tabla de lenguaje que empiecen por 'Name'.
|
||||
```
|
||||
- *FileExist*: `<built-in function FileExist>`
|
||||
```
|
||||
FileExist() check for file existence.
|
||||
```
|
||||
- *GetMinCamDist*: `<built-in function GetMinCamDist>`
|
||||
```
|
||||
GetMinCamDist(x,y,z) : Obtiene la distancia de un punto a la camara
|
||||
```
|
||||
- *EntityListSet*: `<built-in function EntityListSet>`
|
||||
```
|
||||
EntityListSet(listName, varName, value) : Modifica el valor de una variable de una lista de entidades
|
||||
```
|
||||
- *SetAlarmGrow*: `<built-in function SetAlarmGrow>`
|
||||
```
|
||||
Scrap.SetAlarmGrow(growcode) : -1 baja, 0 se mantiene, 1 sube.
|
||||
```
|
||||
- *Exit*: `<built-in function Exit>`
|
||||
```
|
||||
Exit() sale del juego.
|
||||
```
|
||||
- *DelSaveVars*: `<built-in function DelSaveVars>`
|
||||
```
|
||||
Scrap.DelSaveVars(str) : Elimina las <str>* variables
|
||||
```
|
||||
- *SaveConfig*: `<built-in function SaveConfig>`
|
||||
```
|
||||
res Scrap.SaveConfig() : Guarda el fichero de configuración
|
||||
```
|
||||
- *SetSaveProfile*: `<built-in function SetSaveProfile>`
|
||||
```
|
||||
int Scrap.SetSaveProfile(path,name) : Carga un profile de jugador.
|
||||
```
|
||||
- *GetSavedProfilesList*: `<built-in function GetSavedProfilesList>`
|
||||
```
|
||||
[(Directorio, nombre)] Scrap.GetSavedProfilesList() : Devuelve una lista de tuplas donde para cada tupla el primer elemento indica el directorio del profile y el segundo elemento indica el nombre del profile. La lista está ordenada por el criterio de microsoft
|
||||
```
|
||||
- *SetGrid*: `<built-in function SetGrid>`
|
||||
```
|
||||
SetGrid(x,y,z) : Modifica las dimensiones del grid de colision
|
||||
```
|
||||
- *TestSphere*: `<built-in function TestSphere>`
|
||||
```
|
||||
Scrap.TestSphere(x,y,z,radius,´strmask´) : testea una esfera y devuelve el nombre de la entidad o '' si es el mapa o None
|
||||
```
|
||||
- *EndLoading*: `<built-in function EndLoading>`
|
||||
```
|
||||
EndLoading() Inicia la pantalla de carga rapida.
|
||||
```
|
||||
- *Ver*: `<built-in function Ver>`
|
||||
```
|
||||
Ver() Obtiene la version del juego.
|
||||
```
|
||||
- *ConsoleError*: `<built-in function ConsoleError>`
|
||||
```
|
||||
ConsoleError(string name) : Muestra un mensaje de error por la consola
|
||||
```
|
||||
- *GetFloor*: `<built-in function GetFloor>`
|
||||
```
|
||||
i GetFloor(y) : Obtiene el numero de piso en el que esta.
|
||||
```
|
||||
- *AddParkingZone*: `<built-in function AddParkingZone>`
|
||||
```
|
||||
Scrap.AddParkingZone(occupied,pos,name) : Agrega un sitio de parking.
|
||||
```
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,22 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/cmake
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
|
||||
|
||||
### CMake ###
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
||||
### CMake Patch ###
|
||||
# External projects
|
||||
*-prefix/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/cmake
|
|
@ -5,24 +5,30 @@ project(ScrapHacks
|
|||
DESCRIPTION "Scrapland memory hacking library"
|
||||
LANGUAGES CXX)
|
||||
|
||||
message(STATUS "SCRAPLAND_DIR=${SCRAPLAND_DIR}")
|
||||
message(STATUS "Fetching Scrapland installation folder")
|
||||
get_filename_component(SCRAPLAND_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\MercurySteam Entertainment\\Scrapland;DIRECTORY]" ABSOLUTE CACHE)
|
||||
get_filename_component(DEFAULT_SCRAPLAND_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\MercurySteam Entertainment\\Scrapland;DIRECTORY]" ABSOLUTE CACHE)
|
||||
|
||||
if(NOT IS_ABSOLUTE "${SCRAPLAND_DIR}" OR NOT EXISTS "${SCRAPLAND_DIR}")
|
||||
message(FATAL_ERROR "Scrapland installation folder not found!")
|
||||
if(NOT IS_ABSOLUTE "${DEFAULT_SCRAPLAND_DIR}" OR NOT EXISTS "${DEFAULT_SCRAPLAND_DIR}")
|
||||
set(DEFAULT_SCRAPLAND_DIR "")
|
||||
endif()
|
||||
set(SCRAPLAND_DIR "${DEFAULT_SCRAPLAND_DIR}" CACHE STRING "Scrapland installation path")
|
||||
|
||||
|
||||
message(STATUS "Scrapland found at ${SCRAPLAND_DIR}")
|
||||
|
||||
message(STATUS "Checking Scrap.exe hash")
|
||||
message(CHECK_START "Checking Scrap.exe hash")
|
||||
file(SHA1 "${SCRAPLAND_DIR}/Bin/Scrap.exe" SCRAP_EXE_HASH)
|
||||
|
||||
if(NOT ${SCRAP_EXE_HASH} STREQUAL "d2dde960e8eca69d60c2e39a439088b75f0c89fa")
|
||||
message(FATAL_ERROR "Scrap.exe hash miss match!")
|
||||
message(CHECK_FAIL "Scrap.exe hash miss match ScrapHacks will probably crash your game!")
|
||||
else()
|
||||
message(CHECK_PASS "Hash matches!")
|
||||
endif()
|
||||
|
||||
# ==============================
|
||||
# "${SCRAPLAND_DIR}/Bin/Scrap.exe"
|
||||
|
||||
add_custom_target(
|
||||
run
|
||||
COMMAND "Scrap.exe"
|
||||
|
@ -30,6 +36,7 @@ add_custom_target(
|
|||
VERBATIM
|
||||
)
|
||||
add_dependencies(run install)
|
||||
|
||||
# ==============================
|
||||
|
||||
set(COMPONENT "ScrapHacks")
|
||||
|
@ -73,28 +80,28 @@ FetchContent_Declare(
|
|||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
ASM_JIT
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
GIT_REPOSITORY git@github.com:asmjit/asmjit.git
|
||||
GIT_SHALLOW true
|
||||
INSTALL_COMMAND ""
|
||||
CONFIGURE_COMMAND ""
|
||||
ASM_JIT
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
GIT_REPOSITORY git@github.com:asmjit/asmjit.git
|
||||
GIT_SHALLOW true
|
||||
INSTALL_COMMAND ""
|
||||
CONFIGURE_COMMAND ""
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
ASM_TK
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
GIT_REPOSITORY git@github.com:asmjit/asmtk.git
|
||||
GIT_SHALLOW true
|
||||
INSTALL_COMMAND ""
|
||||
ASM_TK
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
GIT_REPOSITORY git@github.com:asmjit/asmtk.git
|
||||
GIT_SHALLOW true
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
Zydis
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
GIT_REPOSITORY git@github.com:zyantific/zydis.git
|
||||
GIT_SHALLOW true
|
||||
INSTALL_COMMAND ""
|
||||
Zydis
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
GIT_REPOSITORY git@github.com:zyantific/zydis.git
|
||||
GIT_SHALLOW true
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(Python DirectX ASM_JIT ASM_TK Zydis)
|
||||
|
@ -125,6 +132,7 @@ add_custom_command(
|
|||
COMMENT "Generating D3D8_VMT.hpp from d3d8.h"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(D3D8_VMT ALL
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/D3D8_VMT.hpp")
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ This will find the Games's installation folder, verify that the version you have
|
|||
- type `import ScrapHack`
|
||||
- type `$help`
|
||||
|
||||
## Config file keys
|
||||
## Config file keys (not yet implemented?)
|
||||
|
||||
- patches.asm: map of address->list of assembly instructions
|
||||
- patches.hex: map of address->hex bytes
|
||||
|
@ -62,3 +62,4 @@ Example:
|
|||
- Zydis disassembler
|
||||
- asmJIT/asmTK assembler
|
||||
- nlohmann/json JSON-parser
|
||||
- LIEF/lief
|
|
@ -1,5 +1,6 @@
|
|||
@echo off
|
||||
setlocal
|
||||
set SCRAPLAND_DIR=%1
|
||||
if "%VSINSTALLDIR%"=="" (
|
||||
for /f "usebackq tokens=*" %%i in (`vswhere -latest -find **\vcvarsall.bat`) do (
|
||||
call "%%i" x86
|
||||
|
@ -7,13 +8,14 @@ if "%VSINSTALLDIR%"=="" (
|
|||
)
|
||||
if "%VSINSTALLDIR%"=="" (
|
||||
echo "VSINSTALLDIR" not set something is wrong!
|
||||
exit
|
||||
) else (
|
||||
if not exist build cmake -G"NMake Makefiles" -B build
|
||||
if "%1"=="--run" (
|
||||
if "%2"=="--run" (
|
||||
cmake --build build --target run
|
||||
) else (
|
||||
cmake --build build --target install
|
||||
)
|
||||
)
|
||||
|
||||
:END
|
||||
endlocal
|
|
@ -0,0 +1,24 @@
|
|||
import lief
|
||||
import sys
|
||||
|
||||
exit("WIP, not really useful yet")
|
||||
|
||||
Scrap = lief.PE.parse(sys.argv[1])
|
||||
|
||||
data = []
|
||||
|
||||
section_data = lief.PE.Section(".hdata")
|
||||
section_data.content = data
|
||||
section_data.virtual_address = 0x8000
|
||||
section_data.characteristics = (
|
||||
lief.PE.SECTION_CHARACTERISTICS.CNT_INITIALIZED_DATA
|
||||
| lief.PE.SECTION_CHARACTERISTICS.MEM_READ
|
||||
)
|
||||
sh = Scrap.add_library("_ScrapHack.pyd")
|
||||
sh.add_entry("Init")
|
||||
|
||||
builder = lief.PE.Builder(Scrap)
|
||||
|
||||
builder.build_imports(True).patch_imports(True).build()
|
||||
|
||||
builder.write("Scrap_mod_sh.exe")
|
|
@ -0,0 +1,4 @@
|
|||
target
|
||||
ext
|
||||
.history
|
||||
Cargo.lock
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "scrapper"
|
||||
version = "0.1.0"
|
||||
authors = ["Daniel Seiller <earthnuker@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.2"
|
||||
encoding = "0.2.33"
|
||||
structopt = {version="0.3.21",features = [ "paw" ]}
|
|
@ -0,0 +1,202 @@
|
|||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use encoding::{all::WINDOWS_1252, EncoderTrap};
|
||||
use encoding::{DecoderTrap, Encoding};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
convert::TryInto,
|
||||
fs::{self, File},
|
||||
io::Seek,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use std::{fs::create_dir_all, io::SeekFrom};
|
||||
use structopt::{StructOpt, paw};
|
||||
use std::{
|
||||
io::{BufReader, BufWriter, Read, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(about = "Scrapland .packed packer and unpacker")]
|
||||
enum Args {
|
||||
/// Unpack .packed file
|
||||
Unpack {
|
||||
destination_folder: PathBuf,
|
||||
packed_files: Vec<PathBuf>,
|
||||
},
|
||||
/// Repack .packed file
|
||||
Repack {
|
||||
input_folder: PathBuf,
|
||||
destination_folder: PathBuf
|
||||
}
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct FileEntry {
|
||||
path: String,
|
||||
offset: u32,
|
||||
size: u32,
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Packed {
|
||||
path: PathBuf,
|
||||
ext_path: Option<PathBuf>,
|
||||
magic: [u8; 4],
|
||||
version: [u8; 4],
|
||||
files: Vec<FileEntry>,
|
||||
}
|
||||
|
||||
impl Packed {
|
||||
fn from_file(filename: &PathBuf) -> std::io::Result<Packed> {
|
||||
let mut fh = BufReader::new(File::open(filename)?);
|
||||
let magic: [u8; 4] = [fh.read_u8()?, fh.read_u8()?, fh.read_u8()?, fh.read_u8()?];
|
||||
let version: [u8; 4] = [fh.read_u8()?, fh.read_u8()?, fh.read_u8()?, fh.read_u8()?];
|
||||
println!("Magic: {:?}", magic);
|
||||
println!("Version: {:?}", version);
|
||||
let num_files = fh.read_u32::<LittleEndian>()?;
|
||||
println!("{} files", num_files);
|
||||
let mut files: Vec<FileEntry> = Vec::new();
|
||||
for _ in 0..num_files {
|
||||
let name_len = fh.read_u32::<LittleEndian>()?;
|
||||
let mut name = vec![0; name_len as usize];
|
||||
fh.read_exact(&mut name)?;
|
||||
let size = fh.read_u32::<LittleEndian>()?;
|
||||
let offset = fh.read_u32::<LittleEndian>()?;
|
||||
let path = WINDOWS_1252.decode(&name, DecoderTrap::Strict).unwrap();
|
||||
files.push(FileEntry { path, offset, size });
|
||||
}
|
||||
Ok(Packed {
|
||||
path: filename.to_owned(),
|
||||
magic,
|
||||
version,
|
||||
files,
|
||||
ext_path: None,
|
||||
})
|
||||
}
|
||||
fn size(&self) -> (u64, u64) {
|
||||
let mut header_size: u64 = 4 * 3; // Magic+Version+Num files
|
||||
let mut data_size: u64 = 0;
|
||||
for entry in &self.files {
|
||||
header_size += 4 * 3; // Name length, Offset, Size
|
||||
let path = WINDOWS_1252
|
||||
.encode(&entry.path, EncoderTrap::Strict)
|
||||
.unwrap();
|
||||
let hs: u64 = path.len().try_into().unwrap();
|
||||
header_size += hs;
|
||||
data_size += entry.size as u64;
|
||||
}
|
||||
(header_size, data_size)
|
||||
}
|
||||
|
||||
fn from_folder(folder: PathBuf) -> std::io::Result<Self> {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(folder.clone());
|
||||
let mut header = Packed {
|
||||
path: PathBuf::new(),
|
||||
magic: [0x42, 0x46, 0x50, 0x4B], // BFPK
|
||||
version: [0x00, 0x00, 0x00, 0x00],
|
||||
files: vec![],
|
||||
ext_path: Some(folder.clone()),
|
||||
};
|
||||
while let Some(dir) = queue.pop_front() {
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
queue.push_back(path);
|
||||
} else {
|
||||
let size = path.metadata().unwrap().len().try_into().unwrap();
|
||||
header.files.push(FileEntry {
|
||||
path: path
|
||||
.strip_prefix(folder.clone())
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.replace("\\", "/"),
|
||||
offset: 0,
|
||||
size,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut offset = header.size().0.try_into().unwrap();
|
||||
for entry in header.files.iter_mut() {
|
||||
entry.offset = offset;
|
||||
offset += entry.size;
|
||||
}
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
fn write(&self, out_path: &PathBuf) -> std::io::Result<()> {
|
||||
let base_path = self.ext_path.clone().unwrap();
|
||||
let mut outfile = BufWriter::new(File::create(out_path)?);
|
||||
outfile.write_all(&self.magic)?;
|
||||
outfile.write_all(&self.version)?;
|
||||
outfile.write_u32::<LittleEndian>(self.files.len() as u32)?;
|
||||
println!("Building header");
|
||||
for entry in &self.files {
|
||||
let path = WINDOWS_1252
|
||||
.encode(&entry.path, EncoderTrap::Strict)
|
||||
.unwrap();
|
||||
outfile.write_u32::<LittleEndian>(path.len().try_into().unwrap())?;
|
||||
outfile.write_all(&path)?;
|
||||
outfile.write_u32::<LittleEndian>(entry.size)?;
|
||||
outfile.write_u32::<LittleEndian>(entry.offset)?;
|
||||
}
|
||||
let total = self.files.len();
|
||||
for (n, entry) in self.files.iter().enumerate() {
|
||||
println!(
|
||||
"[{}/{}] Writing: {} (offset: {}, size: {})",
|
||||
n + 1,
|
||||
total,
|
||||
entry.path,
|
||||
entry.offset,
|
||||
entry.size
|
||||
);
|
||||
let mut fh = BufReader::new(File::open(base_path.join(&entry.path))?);
|
||||
std::io::copy(&mut fh, &mut outfile)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract(&mut self, ext_folder: &PathBuf) -> std::io::Result<()> {
|
||||
let total = self.files.len();
|
||||
let ext_folder = ext_folder.join(&Path::new(&self.path).file_name().unwrap());
|
||||
println!("Extracting to {}", ext_folder.to_string_lossy());
|
||||
let mut fh = File::open(self.path.clone())?;
|
||||
for (n, entry) in self.files.iter().enumerate() {
|
||||
println!(
|
||||
"[{}/{}] Extracting: {} (offset: {}, size: {})",
|
||||
n + 1,
|
||||
total,
|
||||
entry.path,
|
||||
entry.offset,
|
||||
entry.size
|
||||
);
|
||||
fh.seek(SeekFrom::Start(entry.offset.try_into().unwrap()))?;
|
||||
let mut data = vec![0; entry.size.try_into().unwrap()];
|
||||
let path: PathBuf = PathBuf::from(&entry.path);
|
||||
let file = Path::new(&ext_folder).join(path);
|
||||
fh.read_exact(&mut data)?;
|
||||
create_dir_all(file.parent().unwrap())?;
|
||||
let mut fh = BufWriter::new(File::create(file)?);
|
||||
fh.write_all(&data)?;
|
||||
}
|
||||
self.ext_path = Some(ext_folder);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[paw::main]
|
||||
fn main(args: Args) -> std::io::Result<()> {
|
||||
match args {
|
||||
Args::Unpack { packed_files, destination_folder } => {
|
||||
for packed_file in &packed_files {
|
||||
let mut pkd = Packed::from_file(&packed_file)?;
|
||||
pkd.extract(&destination_folder)?;
|
||||
}
|
||||
}
|
||||
Args::Repack { input_folder, destination_folder } => {
|
||||
Packed::from_folder(input_folder)?.write(&destination_folder)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
51
config.yml
51
config.yml
|
@ -64,6 +64,9 @@ flags:
|
|||
0x8c6140: P_module_filename
|
||||
0x853954: P_D3DApp
|
||||
0x853091: N_Uniones
|
||||
0x7faa4c: server_state
|
||||
0x8039a8: client_data
|
||||
0x8038a0: client_ship
|
||||
|
||||
# 0x7fbe24:
|
||||
# 0x7fa778:
|
||||
|
@ -101,6 +104,48 @@ types:
|
|||
- "struct HashTable { uint32_t size; struct HashTableEntry** data; };"
|
||||
- "struct va_list { unsigned int gp_offset; unsigned int fp_offset; void *overflow_arg_area; void *reg_save_area; };"
|
||||
functions:
|
||||
0x5dadc0:
|
||||
name: read_MAT_block
|
||||
0x5daf10:
|
||||
name: read_MAP_block
|
||||
0x60d710:
|
||||
name: read_INI_block
|
||||
0x6155b0:
|
||||
name: read_DUM_block
|
||||
0x628760:
|
||||
name: read_EMI_block
|
||||
0x62c070:
|
||||
name: read_AMC_block
|
||||
0x62c580:
|
||||
name: read_SUEL_block
|
||||
0x631570:
|
||||
name: read_CMSH_block
|
||||
0x631940:
|
||||
name: read_QUAD_block
|
||||
0x64d380:
|
||||
name: read_LUZ_block
|
||||
0x650f80:
|
||||
name: read_SCN_block
|
||||
0x652480:
|
||||
name: read_LFVF_block
|
||||
0x658770:
|
||||
name: read_CAM_block
|
||||
0x6665a0:
|
||||
name: read_CM3_block
|
||||
0x666900:
|
||||
name: read_SM3_block
|
||||
0x6715e0:
|
||||
name: read_PORT_block
|
||||
0x675c90:
|
||||
name: read_MD3D_block
|
||||
0x6776d0:
|
||||
name: read_NAM_block
|
||||
0x6787a0:
|
||||
name: read_ANI_block
|
||||
0x6869b0:
|
||||
name: read_SPR3_block
|
||||
0x6875d0:
|
||||
name: read_EVA_block
|
||||
0x6283a0:
|
||||
name: load_emi
|
||||
0x4fa9f0:
|
||||
|
@ -371,15 +416,9 @@ functions:
|
|||
name: list_models
|
||||
0x63a2f0:
|
||||
name: gdi_draw_line
|
||||
0x650f80:
|
||||
name: load_sm3
|
||||
0x6597d0:
|
||||
name: read_ini_entry
|
||||
signature: bool read_ini_entry(void* dest,const char* key, const char* section);
|
||||
0x6665a0:
|
||||
name: load_m3d_1
|
||||
0x666900:
|
||||
name: load_m3d_2
|
||||
0x666c60:
|
||||
name: read_m3d
|
||||
0x6b1c70:
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
function dasm(addr, size) {
|
||||
var size = size || 8;
|
||||
var offset = 0;
|
||||
var ret = [];
|
||||
while (ret.length != size) {
|
||||
var inst = Instruction.parse(ptr(addr).add(offset));
|
||||
ret.push(("[" + inst.address + "] " + inst.mnemonic + " " + inst.opStr).trim());
|
||||
offset += inst.size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function r(addr, options) {
|
||||
var options = options || {}
|
||||
var max_depth = options.max_depth || 4;
|
||||
var num = options.num || 4;
|
||||
var ret = {};
|
||||
var vals = [
|
||||
"S8",
|
||||
"U8",
|
||||
"S16",
|
||||
"U16",
|
||||
"S32",
|
||||
"U32",
|
||||
"Float",
|
||||
"Double",
|
||||
"Pointer",
|
||||
"CString",
|
||||
"Utf8String",
|
||||
"Utf16String",
|
||||
"AnsiString"
|
||||
];
|
||||
vals.forEach(function (k) {
|
||||
try {
|
||||
ret[k] = ptr(addr)['read' + k]()
|
||||
} catch (e) {
|
||||
ret[k] = undefined;
|
||||
}
|
||||
})
|
||||
try {
|
||||
ret["code"] = dasm(addr, 8);
|
||||
} catch (e) {
|
||||
ret["code"] = undefined;
|
||||
}
|
||||
|
||||
if (max_depth > 1) {
|
||||
var p = {};
|
||||
var read_ptr = false;
|
||||
for (var i = 0; i < num; ++i) {
|
||||
if (ret["Pointer"] === undefined) {
|
||||
continue;
|
||||
}
|
||||
p[i * Process.pointerSize] = r(ret["Pointer"].add(i * Process.pointerSize), {
|
||||
max_depth: max_depth - 1,
|
||||
num
|
||||
});
|
||||
read_ptr = true;
|
||||
}
|
||||
if (read_ptr) {
|
||||
ret["p"] = p;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// function test() {
|
||||
// for (var p = 0; p < 4; ++p) {
|
||||
// var player = ptr(0x7FE944).readPointer().add(0x288 + p * 4).readPointer();
|
||||
// if (!player.isNull()) {
|
||||
// console.log("Player " + (p+1) + ":", player);
|
||||
// console.log(JSON.stringify(r(player),null,4));
|
||||
// }
|
||||
// }
|
||||
// }
|
File diff suppressed because one or more lines are too long
1558
helplib.txt
1558
helplib.txt
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
|||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/mdbook
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=mdbook
|
||||
|
||||
### MdBook ###
|
||||
book
|
||||
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/mdbook
|
|
@ -0,0 +1,25 @@
|
|||
[book]
|
||||
authors = ["Daniel Seiller"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "Scrapland Reverse Engineering Notes"
|
||||
|
||||
[output.html]
|
||||
preferred-dark-theme = "ayu"
|
||||
mathjax-support = true
|
||||
|
||||
# [preprocessor.graphviz]
|
||||
# command = "mdbook-graphviz"
|
||||
|
||||
[preprocessor.svgbob]
|
||||
text_width = 8.0
|
||||
text_height = 16.0
|
||||
class = "bob"
|
||||
font_family = "arial"
|
||||
font_size = 14.0
|
||||
stroke_width = 2.0
|
||||
# there's using css-variables from theme:
|
||||
stroke_color = "var(--fg)" # see default theme / variables.css
|
||||
background_color = "transparent" # also useful `var(--bg)`
|
||||
# all properties are optional.
|
|
@ -0,0 +1,140 @@
|
|||
# Chunked Formats
|
||||
|
||||
# General Block format
|
||||
|
||||
```cpp
|
||||
struct Block {
|
||||
unsigned char block_id[4],
|
||||
uint32_t size,
|
||||
unsigned char data[size],
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Block {
|
||||
unsigned char block_id[4],
|
||||
uint32_t size,
|
||||
T data,
|
||||
}
|
||||
```
|
||||
|
||||
# Block IDs
|
||||
|
||||
File ID | Chunk IDs
|
||||
------- | ------------------------------------------------------------------------------
|
||||
AMC | AMC, CMSH, QUAD
|
||||
CM3 | ANI, CM3, EVA, NAE, NAM, SCN
|
||||
DUM | DUM, INI
|
||||
EMI | EMI, LFVF, MAP, MAT, TRI
|
||||
SM3 | ANI, CAM, INI, LFVF, LUZ, MAP, MAT, MD3D, NAE, NAM, PORT, SCN, SM3, SPR3, SUEL
|
||||
|
||||
Read types:
|
||||
|
||||
- `i`: 4-byte unsigned integer
|
||||
- `s`: 4-byte signed integer
|
||||
- `p`: length prefixed string
|
||||
- `f`: 4-byte float
|
||||
- `3f`: array of 3 4-byte floats
|
||||
- `3i`: array of 3 4-byte unsigned integers
|
||||
|
||||
Chunk ID | Description | Reads
|
||||
-------- | --------------------------- | ------------------------
|
||||
AMC | Collision Data |
|
||||
ANI | Animation data? |
|
||||
CAM | Camera info? |
|
||||
CMSH | Collision Mesh Data |
|
||||
DUM | Dummy (map object) data |
|
||||
INI | INI-Configuration data |
|
||||
LFVF | FVF Vertex Data |
|
||||
LUZ | Lighting information |
|
||||
MAP | UV Map? |
|
||||
MAT | Material information |
|
||||
NAE | Animation Data? |
|
||||
NAM | Animation Data? |
|
||||
PORT | Map portals? | i==1, i, i, 4, 4
|
||||
QUAD | Mesh data? |
|
||||
SCN | Scene data? |
|
||||
SUEL | Ground plane? | 0x18, 0xc, 4, 4, 4, 0x18
|
||||
TRI | Triangle strip definitions? |
|
||||
MD3D | 3D Model definition? |
|
||||
|
||||
# Format of Specific chunks
|
||||
|
||||
## INI
|
||||
|
||||
Configuration Data
|
||||
|
||||
```cpp
|
||||
struct INI {
|
||||
uint32_t num_sections;
|
||||
struct {
|
||||
uint32_t num_lines;
|
||||
struct {
|
||||
uint32_t num_chars;
|
||||
char line[num_chars]
|
||||
} lines[num_lines];
|
||||
} sections[num_sections];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## LFVF
|
||||
|
||||
DirectX Flexible Vertex Format Data
|
||||
|
||||
```cpp
|
||||
struct Vertex { // fields according to flags
|
||||
float position[3]; // D3DFVF_XYZ | D3DFVF_XYZRHW | D3DFVF_XYZB*
|
||||
float rhw; // D3DFVF_XYZRHW
|
||||
float weights[3]; // D3DFVF_XYZB*
|
||||
float normal[3]; // D3DFVF_NORMAL
|
||||
float point_size; // D3DFVF_PSIZE
|
||||
uint32_t diffuse; // D3DFVF_DIFFUSE, RGBA
|
||||
uint32_t specular; //D3DFVF_SPECULAR, RGBA
|
||||
float tex_coords[D3DFVF_TEXTUREFORMAT][D3DFVF_TEX]; // D3DFVF_TEX* and D3DFVF_TEXTUREFORMAT*
|
||||
};
|
||||
|
||||
struct LFVF {
|
||||
uint32_t unk;
|
||||
uint32_t num_entries;
|
||||
struct {
|
||||
uint32_t FVF; // FVF vertex data configuration
|
||||
uint32_t vert_size; //?,
|
||||
uint32_t num_verts;
|
||||
Vertex vertices[num_vers];
|
||||
} entry[num_entries];
|
||||
};
|
||||
```
|
||||
|
||||
## DUM
|
||||
|
||||
Map object data
|
||||
|
||||
```cpp
|
||||
struct DUM {
|
||||
uint32_t unk_1;
|
||||
uint32_t num_dummies;
|
||||
uint32_t unk_2;
|
||||
struct {
|
||||
uint32_t name_length;
|
||||
char name[name_length];
|
||||
float position[3];
|
||||
float rotation[3];
|
||||
uint32_t has_ini;
|
||||
if (has_ini) {
|
||||
Block<INI> ini;
|
||||
};
|
||||
uint32_t unk_1; // has_next?
|
||||
} sections[num_sections];
|
||||
};
|
||||
```
|
||||
|
||||
## MAP
|
||||
|
||||
```cpp
|
||||
struct MAP {
|
||||
uint32_t version;
|
||||
uint32_t tex_name_len;
|
||||
char tex_name[tex_name_len];
|
||||
// TODO: rest
|
||||
}
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
# Entities
|
|
@ -0,0 +1,18 @@
|
|||
# File Formats
|
||||
|
||||
|
||||
File Extension | Description | Chunked
|
||||
-------------- | ------------------------ | -------
|
||||
.packed | Game Data Archive | n
|
||||
.cm3 | Animation file | y
|
||||
.sm3 | 3d model file | y
|
||||
.dum | Dummy (map object) file | y
|
||||
.pth | AI Path | n
|
||||
.emi | Emission maps/Materials? | y
|
||||
.amc | Collision Data | y
|
||||
.ini | Configuration | n
|
||||
.txa | Texture Animation Config | n
|
||||
|
||||
- [Chunked](Chunked.md)
|
||||
- [Packed](Packed.md)
|
||||
- [AI Pathfinding Graph](Nodegraph.md)
|
|
@ -0,0 +1 @@
|
|||
# File Formats
|
|
@ -0,0 +1,41 @@
|
|||
# Netplay
|
||||
|
||||
Game Info Packet
|
||||
|
||||
```
|
||||
Server 'B':FZ (0/10) Ver 1.0 at 192.168.99.1:28086
|
||||
[0-3] header/ID?
|
||||
[4-5] port (16-bit)
|
||||
[6-7] max_players (16-bit)
|
||||
[8-9] curr_player (16-bit)
|
||||
[10-x] server name (char*)
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
|
||||
0019fdc0 ba ce 00 01 b6 6d 0a 00 00 00 42 00 30 fe 19 00 .....m....B.0...
|
||||
0019fdd0 ff ff ff ff 27 2b b3 9b c7 3e bb 00 9c af 29 00 ....'+...>....).
|
||||
0019fde0 db 69 00 00 00 00 00 00 00 00 44 65 61 74 68 4d .i........DeathM
|
||||
0019fdf0 61 74 63 68 00 00 00 00 ff ff 46 5a 00 4a 91 f0 atch......FZ.J..
|
||||
0019fe00 92 8b 57 4e 7f 00 00 00 10 21 fe 38 0d ae 00 00 ..WN.....!.8....
|
||||
0019fe10 f0 ce f3 36 a0 e8 0b 77 a0 e8 ...6...w..
|
||||
```
|
||||
|
||||
|
||||
Player Join Packet
|
||||
|
||||
```
|
||||
[0-3] header/ID?
|
||||
[6-x] Player name
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
|
||||
09c9dfe8 7f 47 00 00 00 0e 55 6e 6e 61 6d 65 64 20 50 6c .G....Unnamed Pl
|
||||
09c9dff8 61 79 65 72 06 53 42 6f 73 73 31 b9 00 07 50 5f ayer.SBoss1...P_
|
||||
09c9e008 42 65 74 74 79 06 4d 42 4f 53 53 31 06 4d 42 4f Betty.MBOSS1.MBO
|
||||
09c9e018 53 53 31 00 00 10 30 2c 31 35 2c 30 2c 30 2c 31 SS1...0,15,0,0,1
|
||||
09c9e028 35 2c 31 35 2c 31 02 00 00 00 5,15,1....
|
||||
```
|
||||
|
||||
Message | Description
|
||||
---------------------------------------- | -----------------------------------------------------------------
|
||||
`5c68625c32383230395c73637261706c616e64` | "Scrapland Server" announcement broadcast (`\hb\28209\scrapland`)
|
||||
`7f01000007` | Retrieve Game info
|
||||
`48423d35323932322c3235363a323830383600` | Connection Information (`HB=52922,256:28086`)
|
|
@ -0,0 +1,26 @@
|
|||
# AI Nodegraph
|
||||
|
||||
Used for pathfinding using the A*-Algorithm.
|
||||
|
||||
```cpp
|
||||
// n= number of dimension (3 or 2)
|
||||
|
||||
template<size_t n>
|
||||
struct Node {
|
||||
float pos[n];
|
||||
};
|
||||
|
||||
template<size_t n>
|
||||
struct Edge {
|
||||
uint32_t num_edge_nodes;
|
||||
Node<n> nodes[];
|
||||
};
|
||||
|
||||
template<size_t n>
|
||||
struct Graph {
|
||||
uint32_t num_nodes;
|
||||
Node<n> nodes[];
|
||||
uint32_t num_edges;
|
||||
Edge<n> edges[];
|
||||
};
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
# Overview
|
|
@ -0,0 +1,15 @@
|
|||
# Packed
|
||||
|
||||
```cpp
|
||||
struct Header {
|
||||
unsigned char magic[4]; // always BFPK
|
||||
uint32_t version;
|
||||
uint32_t number_of_files;
|
||||
struct File {
|
||||
uint32_t path_length;
|
||||
char path[]; // latin1 encoding
|
||||
uint32_t data_size;
|
||||
uint32_t data_offset; // offset includes header size so it can be used directly in a seek() call
|
||||
} files[];
|
||||
};
|
||||
```
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
# Python API
|
|
@ -0,0 +1,13 @@
|
|||
# Summary
|
||||
|
||||
- [Overview](./Overview.md)
|
||||
- [ScrapEngine](./ScrapEngine.md)
|
||||
- [World](./World.md)
|
||||
- [Entities](./Entities.md)
|
||||
- [Netplay](./Netplay.md)
|
||||
- [Python API](./Python_API.md)
|
||||
- [File Formats](./File_Formats.md)
|
||||
- [Chunked Formats](./Chunked.md)
|
||||
- [Packed](./Packed.md)
|
||||
- [AI Nodegraph](./Nodegraph.md)
|
||||
- [ScrapHacks](./ScrapHacks.md)
|
|
@ -0,0 +1,54 @@
|
|||
# ScrapEngine
|
||||
|
||||
- Ingame Scripting Language: Python 1.5.2
|
||||
- Interesting memory locations and functions are noted in `config.yml`
|
||||
|
||||
## Launch options
|
||||
|
||||
- `-console`: open external console window on start
|
||||
- `-wideWindow`: start game in widescreen mode
|
||||
- `-dedicated`: start in multiplayer dedicated server mode (needs to be used with `-server`)
|
||||
- `-server`: start in multiplayer server mode
|
||||
- `-build`: Rebuild `Data.packed` (needs a `filelist.2Bpack`)
|
||||
|
||||
## Ingame-Console
|
||||
|
||||
(Ctrl+\^ or right click on window title bar and select "switch console") (Handler @ `0x402190`)
|
||||
|
||||
* `<Code>`: Evaluate Python code
|
||||
* `:<Var>`: Get Game Engine Variable
|
||||
* `:<Var> <Val>`: Set Game Engine Variable
|
||||
* `?`: Show all Game Engine Variables
|
||||
* `?<String>`: Show all Game Engine Variables 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)`
|
||||
|
||||
## External Console
|
||||
|
||||
(Scene graph debugging?) (Handler @ `0x5f9520`)
|
||||
|
||||
* `listar luces` List lights in scene
|
||||
* `listar` list models in scene
|
||||
* `arbol <model_name>` show details for model
|
||||
* `mem` (doesn't do anything?)
|
||||
* `ver uniones`
|
||||
* Easter Eggs:
|
||||
* `imbecil`
|
||||
* `idiota`
|
||||
* `capullo`
|
||||
|
||||
|
||||
## 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 scene graph debugging console)
|
||||
- `0x8b18f4`: pointer to Scenes Data (can be dumped using scene graph debugging console)
|
||||
- `0x8b18f8`: pointer to active Models Data (can be dumped using scene graph debugging console)
|
|
@ -0,0 +1 @@
|
|||
# ScrapHacks
|
|
@ -0,0 +1,80 @@
|
|||
# World
|
||||
|
||||
## Game World/State Pointer @ `0x7fe944`
|
||||
|
||||
Points to World struct
|
||||
|
||||
Offset | Type | Description
|
||||
------ | ------------------------ | --------------------------------------
|
||||
0x0000 | `void**` | Virtual Method Table
|
||||
0x0004 | `uint32_t` | Slots in Entity Hashtable
|
||||
0x0008 | `void**` | Pointer to Entity Hashtable
|
||||
0x00B0 | `??` | Pointer to Ground Object (?)
|
||||
0x0288 | `pyEntity*` | UsrEntity[0]
|
||||
0x028C | `pyEntity*` | UsrEntity[1]
|
||||
0x0290 | `pyEntity*` | UsrEntity[2]
|
||||
0x0294 | `pyEntity*` | UsrEntity[3]
|
||||
0x0298 | `uint32_t` | Slots in Model Hashtable
|
||||
0x029C | `void**` | Pointer to Model Hashtable
|
||||
0x02B8 | `uint32_t` | Slots in Entity lists Hashtable
|
||||
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`
|
||||
|
||||
## cPyEntity structure
|
||||
|
||||
Offset | Type | Description
|
||||
------ | -------- | --------------------
|
||||
0x0000 | `void**` | Virtual Method Table
|
||||
0x0004 | `char*` | Name
|
||||
0x0008 | `void*` | ???
|
||||
|
||||
|
||||
## Entity Hash Table
|
||||
|
||||
Hash-function used: [PJW](https://en.wikipedia.org/wiki/PJW_hash_function) (Same parameters as the example implementation)
|
||||
|
||||
Entry format:
|
||||
|
||||
```cpp
|
||||
struct HT_Entry {
|
||||
void* data;
|
||||
const char* key;
|
||||
HT_Entry* next;
|
||||
}
|
||||
```
|
||||
|
||||
Data format:
|
||||
|
||||
Offset | Type | Description
|
||||
------ | ------------- | ------------------------
|
||||
0x0 | `void**` | Virtual Method Table (?)
|
||||
0x4 | `const char*` | name as string
|
||||
0x14 | `void*` | pointer to self (why?)
|
||||
0x28 | `float[3]` | Position in Game World
|
||||
|
||||
## EntityList Hash Table
|
||||
|
||||
Attributes:
|
||||
- `Near`
|
||||
- `First`
|
||||
- `Num`
|
||||
- `OnDeath`
|
||||
- `OnDamage`
|
||||
- ...
|
|
@ -0,0 +1,21 @@
|
|||
import sys
|
||||
from construct import *
|
||||
from pprint import pprint
|
||||
|
||||
ScrapSaveVar = Struct(
|
||||
"name" / PascalString(Int32ul, encoding="utf-8"),
|
||||
"data" / PascalString(Int32ul, encoding="utf-8"),
|
||||
)
|
||||
ScrapSave = "ScarpSaveGame" / Struct(
|
||||
"title" / PascalString(Int32ul, encoding="utf-8"),
|
||||
"id" / PascalString(Int32ul, encoding="utf-8"),
|
||||
"data" / PrefixedArray(Int32ul, ScrapSaveVar),
|
||||
Terminated,
|
||||
)
|
||||
with open(sys.argv[1], "rb") as sav_file:
|
||||
save = ScrapSave.parse_stream(sav_file)
|
||||
print("ID:", save.id)
|
||||
print("Title:", save.title)
|
||||
for var in save.data:
|
||||
print(" {}: {}".format(var.name, var.data))
|
||||
|
|
@ -113,7 +113,6 @@ for addr, func in config.functions.items():
|
|||
r2_cmd(f"afr fcn.{name} {hex(addr)}")
|
||||
r2_cmd(f"afn fcn.{name} {hex(addr)}")
|
||||
if sig:
|
||||
sig = sig.replace(name, "fcn." + name)
|
||||
r2_cmd(f'"afs {sig}" @{hex(addr)}')
|
||||
|
||||
|
||||
|
@ -305,7 +304,7 @@ print("[+] Wrote scrap_dissect.x32dbg.txt")
|
|||
with open(r2_script_path, "w") as of:
|
||||
wcmds = []
|
||||
for cmd in r2cmds:
|
||||
if cmd == "avj":
|
||||
if cmd=="avj":
|
||||
continue
|
||||
record = True
|
||||
for start in ["p", "/", "s"]:
|
||||
|
@ -317,7 +316,6 @@ with open(r2_script_path, "w") as of:
|
|||
|
||||
print("[+] Wrote scrap_dissect.r2")
|
||||
|
||||
|
||||
def start_program(cmdl, **kwargs):
|
||||
if os.name == "nt":
|
||||
return SP.Popen(["cmd", "/c", "start"] + cmdl, **kwargs)
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
import rzpipe
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
import subprocess as SP
|
||||
from tqdm import tqdm
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
tqdm_ascii = False
|
||||
|
||||
rzcmds = []
|
||||
x64_dbg_script = []
|
||||
script_path = os.path.dirname(os.path.abspath(__file__))
|
||||
scrap_exe = os.path.abspath(sys.argv[1])
|
||||
scrapland_folder = os.path.abspath(os.path.dirname(scrap_exe))
|
||||
rz_script_path = os.path.join(scrapland_folder, "scrap_dissect.rz")
|
||||
x64_dbg_script_path = os.path.join(scrapland_folder, "scrap_dissect.x32dbg.txt")
|
||||
json_path = os.path.join(scrapland_folder, "scrap_dissect.json")
|
||||
|
||||
assert os.path.isfile(scrap_exe), "File not found!"
|
||||
rz = rzpipe.open(scrap_exe)
|
||||
file_hashes = rz.cmdj("itj")
|
||||
target_hashes = {
|
||||
"sha1": "d2dde960e8eca69d60c2e39a439088b75f0c89fa",
|
||||
"md5": "a934c85dca5ab1c32f05c0977f62e186",
|
||||
"sha256": "24ef449322f28f87b702834f1a1aac003f885db6d68757ff29fad3ddba6c7b88",
|
||||
}
|
||||
|
||||
assert file_hashes == target_hashes, "Hash mismatch"
|
||||
|
||||
|
||||
def x64_dbg_label(addr, name, prefix=None):
|
||||
global x64_dbg_script
|
||||
if isinstance(addr, int):
|
||||
addr = hex(addr)
|
||||
if prefix:
|
||||
x64_dbg_script.append(f'lbl {addr},"{prefix}.{name}"')
|
||||
else:
|
||||
x64_dbg_script.append(f'lbl {addr},"{name}"')
|
||||
|
||||
|
||||
def rz_cmd(cmd):
|
||||
global rz, rzcmds
|
||||
rzcmds.append(cmd)
|
||||
return rz.cmd(cmd)
|
||||
|
||||
|
||||
def rz_cmdj(cmd):
|
||||
global rz, rzcmds
|
||||
rzcmds.append(cmd)
|
||||
return rz.cmdj(cmd)
|
||||
|
||||
|
||||
def rz_cmdJ(cmd):
|
||||
global rz, rzcmds
|
||||
rzcmds.append(cmd)
|
||||
return rz.cmdJ(cmd)
|
||||
|
||||
|
||||
t_start = datetime.today()
|
||||
|
||||
|
||||
def analysis(full=False):
|
||||
print("[*] Running analysis")
|
||||
steps = []
|
||||
if full:
|
||||
steps = [
|
||||
"e anal.dataref = true",
|
||||
# "e anal.esil = true",
|
||||
"e anal.jmp.after = true",
|
||||
"e anal.jmp.indir = true",
|
||||
"e anal.loads = true",
|
||||
"e anal.pushret = true",
|
||||
"e anal.refstr = true",
|
||||
"e anal.strings = true",
|
||||
"e anal.vinfun = true",
|
||||
"e asm.anal = true",
|
||||
]
|
||||
if full:
|
||||
steps += ["aaaa"]
|
||||
else:
|
||||
steps += ["aaa"]
|
||||
for ac in steps:
|
||||
print(f"[*] Running '{ac}'")
|
||||
rz_cmd(f"{ac} 2>NUL")
|
||||
|
||||
|
||||
with open(os.path.join(script_path, "config.yml")) as cfg:
|
||||
print("[*] Loading config")
|
||||
config = type("Config", (object,), yaml.load(cfg, Loader=yaml.SafeLoader))
|
||||
|
||||
for line in config.script.strip().splitlines():
|
||||
rz_cmd(line)
|
||||
|
||||
analysis(False)
|
||||
|
||||
for addr, comment in config.comments.items():
|
||||
rz_cmd(f"CC {comment} @ {hex(addr)}")
|
||||
|
||||
for t in config.types:
|
||||
rz_cmd(f'"td {t}"')
|
||||
|
||||
for addr, name in config.flags.items():
|
||||
x64_dbg_label(addr, name, "loc")
|
||||
rz_cmd(f"f loc.{name} 4 {hex(addr)}")
|
||||
|
||||
|
||||
for addr, func in config.functions.items():
|
||||
name, sig = func.get("name"), func.get("signature")
|
||||
if name:
|
||||
x64_dbg_label(addr, name, "fcn")
|
||||
rz_cmd(f"afr fcn.{name} {hex(addr)}")
|
||||
rz_cmd(f"afn fcn.{name} {hex(addr)}")
|
||||
if sig:
|
||||
sig = sig.replace(name, "fcn." + name)
|
||||
rz_cmd(f'"afs {sig}" @{hex(addr)}')
|
||||
|
||||
|
||||
def vtables():
|
||||
ret = {}
|
||||
print("[*] Analyzing VTables")
|
||||
vtables = rz_cmdJ("avj")
|
||||
for c in tqdm(vtables, ascii=tqdm_ascii):
|
||||
methods = []
|
||||
name = config.VMTs.get(c.offset, f"{c.offset:08x}")
|
||||
x64_dbg_label(c.offset, name, "vmt")
|
||||
rz_cmd(f"f vmt.{name} 4 {hex(c.offset)}")
|
||||
for idx, m in enumerate(tqdm(c.methods, ascii=tqdm_ascii, leave=False)):
|
||||
methods.append(hex(m.offset))
|
||||
x64_dbg_label(m.offset, f"{name}.{idx}", "fcn.vmt")
|
||||
rz_cmd(f"afr fcn.vmt.{name}.{idx} {hex(m.offset)} 2>NUL")
|
||||
ret[hex(c.offset)] = methods
|
||||
return ret
|
||||
|
||||
|
||||
def c_callbacks():
|
||||
print("[*] Parsing C Callbacks")
|
||||
funcs = {}
|
||||
res = rz_cmd("/r fcn.register_c_callback ~CALL[1]").splitlines()
|
||||
for addr in tqdm(res, ascii=tqdm_ascii):
|
||||
rz_cmd(f"s {addr}")
|
||||
rz_cmd(f"so -3")
|
||||
func, name = rz_cmdJ(f"pdj 2")
|
||||
func = func.refs[0].addr
|
||||
name = rz_cmd(f"psz @{hex(name.refs[0].addr)}").strip()
|
||||
rz_cmd(f"afr fcn.callbacks.{name} {hex(func)} 2>NUL")
|
||||
x64_dbg_label(func, f"{name}", "fcn.callbacks")
|
||||
funcs[name] = hex(func)
|
||||
return funcs
|
||||
|
||||
|
||||
def assertions():
|
||||
assertions = {}
|
||||
for (n_args, a_addr) in [
|
||||
(3, "fcn.throw_assertion_1"),
|
||||
(4, "fcn.throw_assertion_2"),
|
||||
]:
|
||||
print(f"[*] Parsing C assertions for {a_addr}")
|
||||
res = rz_cmd(f"/r {a_addr} ~CALL[1]").splitlines()
|
||||
print()
|
||||
for line in tqdm(res, ascii=tqdm_ascii):
|
||||
addr = line.strip()
|
||||
rz_cmd(f"s {addr}")
|
||||
rz_cmd(f"so -{n_args}")
|
||||
dis = rz_cmdJ(f"pij {n_args}")
|
||||
if n_args == 4:
|
||||
line, date, file, msg = dis
|
||||
elif n_args == 3:
|
||||
date = None
|
||||
line, file, msg = dis
|
||||
try:
|
||||
file = rz_cmd(f"psz @{file.refs[0].addr}").strip()
|
||||
msg = rz_cmd(f"psz @{msg.refs[0].addr}").strip()
|
||||
if date:
|
||||
date = rz_cmd(f"psz @{date.refs[0].addr}").strip()
|
||||
line = line.val
|
||||
file = file.replace("\\\\", "\\")
|
||||
assertions.setdefault(file, [])
|
||||
assertions[file].append(
|
||||
{"line": line, "date": date, "addr": addr, "msg": msg}
|
||||
)
|
||||
except:
|
||||
pass
|
||||
for path in assertions:
|
||||
assertions[path].sort(key=lambda v: v["line"])
|
||||
return assertions
|
||||
|
||||
|
||||
def bb_refs(addr):
|
||||
ret = {}
|
||||
res = rz_cmd(f"/r {addr} ~fcn[0,1]").splitlines()
|
||||
print()
|
||||
for ent in tqdm(res, ascii=tqdm_ascii):
|
||||
func, hit = ent.split()
|
||||
ret[hit] = {"asm": [], "func": func}
|
||||
for ins in rz_cmdJ(f"pdbj @{hit}"):
|
||||
ret[hit]["asm"].append(ins.disasm)
|
||||
return ret
|
||||
|
||||
|
||||
def world():
|
||||
print("[*] Parsing World offsets")
|
||||
return bb_refs("loc.P_World")
|
||||
|
||||
|
||||
def render():
|
||||
print("[*] Parsing D3D_Device offsets")
|
||||
return bb_refs("loc.P_D3D8_Dev")
|
||||
|
||||
|
||||
def py_mods():
|
||||
print("[*] Parsing Python modules")
|
||||
res = rz_cmd("/r fcn.Py_InitModule ~CALL[1]").splitlines()
|
||||
print()
|
||||
py_mods = {}
|
||||
for call_loc in tqdm(res, ascii=tqdm_ascii):
|
||||
rz_cmd(f"s {call_loc}")
|
||||
rz_cmd(f"so -3")
|
||||
args = rz_cmdJ("pdj 3")
|
||||
refs = []
|
||||
if not all(arg.type == "push" for arg in args):
|
||||
continue
|
||||
for arg in args:
|
||||
refs.append(hex(arg.val))
|
||||
doc, methods, name = refs
|
||||
doc = rz_cmd(f"psz @{doc}").strip()
|
||||
name = rz_cmd(f"psz @{name}").strip()
|
||||
rz_cmd(f"s {methods}")
|
||||
rz_cmd(f"f py.{name} 4 {methods}")
|
||||
x64_dbg_label(methods, f"{name}", "py")
|
||||
py_mods[name] = {"methods_addr": methods, "doc": doc, "methods": {}}
|
||||
while True:
|
||||
m_name, m_func, _, m_doc = [v.value for v in rz_cmdJ(f"pfj xxxx")]
|
||||
if m_name == 0:
|
||||
break
|
||||
m_name, m_func, m_doc = map(hex, (m_name, m_func, m_doc))
|
||||
m_name = rz_cmd(f"psz @{m_name}").strip()
|
||||
rz_cmd(f"f py.{name}.{m_name}.__doc__ 4 {m_doc}")
|
||||
if int(m_doc, 16) != 0:
|
||||
x64_dbg_label(m_doc, f"{name}.{m_name}.__doc__", "py")
|
||||
m_doc = rz_cmd(f"psz @{m_doc}").strip()
|
||||
else:
|
||||
m_doc = None
|
||||
py_mods[name]["methods"][m_name] = {"addr": m_func, "doc": m_doc}
|
||||
rz_cmd(f"afr py.{name}.{m_name} {m_func} 2>NUL")
|
||||
x64_dbg_label(m_func, f"{name}.{m_name}", "fcn.py")
|
||||
rz_cmd("s +16")
|
||||
return py_mods
|
||||
|
||||
|
||||
def game_vars():
|
||||
ret = {}
|
||||
print("[*] Parsing Game variables")
|
||||
res = rz_cmd("/r fcn.setup_game_vars ~CALL[1]").splitlines()
|
||||
print()
|
||||
for line in tqdm(res, ascii=tqdm_ascii):
|
||||
addr = line.strip()
|
||||
rz_cmd(f"s {addr}")
|
||||
args = rz_cmd("pdj -5") # seek and print disassembly
|
||||
if not args:
|
||||
continue
|
||||
args = json.loads(args)
|
||||
args_a = []
|
||||
push_cnt = 0
|
||||
for arg in args[::-1]:
|
||||
if arg["type"] not in ["push", "mov"]:
|
||||
continue
|
||||
if arg["type"] == "push":
|
||||
push_cnt += 1
|
||||
args_a.append(arg)
|
||||
if push_cnt == 3:
|
||||
break
|
||||
if len(args_a) != 4:
|
||||
continue
|
||||
if not all("val" in v for v in args_a):
|
||||
continue
|
||||
addr, name, _, desc = [v["val"] for v in args_a]
|
||||
name = rz_cmd(f"psz @{hex(name)}").strip()
|
||||
desc = rz_cmd(f"psz @{hex(desc)}").strip()
|
||||
addr = hex(addr)
|
||||
rz_cmd(f"f loc.gvar.{name} 4 {addr}")
|
||||
x64_dbg_label(addr, f"{name}", "loc.gvar")
|
||||
ret[addr] = {"name": name, "desc": desc}
|
||||
return ret
|
||||
|
||||
|
||||
ret = {}
|
||||
# world, render
|
||||
for func in ["game_vars", "c_callbacks", "py_mods", "assertions", "vtables"]:
|
||||
ret[func] = globals()[func]()
|
||||
|
||||
analysis(True)
|
||||
|
||||
with open(json_path, "w") as of:
|
||||
json.dump(ret, of, indent=4)
|
||||
|
||||
print("[+] Wrote scrap_dissect.json")
|
||||
|
||||
with open(x64_dbg_script_path, "w") as of:
|
||||
of.write("\n".join(x64_dbg_script))
|
||||
|
||||
print("[+] Wrote scrap_dissect.x32dbg.txt")
|
||||
|
||||
with open(rz_script_path, "w") as of:
|
||||
wcmds = []
|
||||
for cmd in rzcmds:
|
||||
if cmd == "avj":
|
||||
continue
|
||||
record = True
|
||||
for start in ["p", "/", "s"]:
|
||||
if cmd.strip('"').startswith(start):
|
||||
record = False
|
||||
if record:
|
||||
wcmds.append(cmd)
|
||||
of.write("\n".join(wcmds))
|
||||
|
||||
print("[+] Wrote scrap_dissect.rz")
|
||||
|
||||
|
||||
def start_program(cmdl, **kwargs):
|
||||
if os.name == "nt":
|
||||
return SP.Popen(["cmd", "/c", "start"] + cmdl, **kwargs)
|
||||
else:
|
||||
return SP.Popen(cmdl, **kwargs)
|
||||
|
||||
|
||||
print("[+] Analysis took:", datetime.today() - t_start)
|
||||
rz.cmd("Ps Scrap.rzdb")
|
||||
exit()
|
||||
|
||||
print("[+] Executing Cutter")
|
||||
try:
|
||||
start_program(
|
||||
["cutter", "-A", "0", "-i", rz_script_path, scrap_exe],
|
||||
cwd=scrapland_folder,
|
||||
shell=False,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
print("[-] cutter not installed, falling back to rz")
|
||||
start_program(
|
||||
["rz", "-i", rz_script_path, scrap_exe], cwd=scrapland_folder, shell=False
|
||||
)
|
|
@ -0,0 +1,132 @@
|
|||
import argparse
|
||||
from collections import OrderedDict
|
||||
import glob
|
||||
import os
|
||||
import shutil
|
||||
from construct import *
|
||||
from tqdm import tqdm
|
||||
|
||||
setglobalstringencoding(None)
|
||||
|
||||
ScrapFile = Struct(
|
||||
"path" / PascalString(Int32ul),
|
||||
"size" / Int32ul,
|
||||
"offset" / Int32ul,
|
||||
"data" / OnDemandPointer(this.offset, Bytes(this.size)),
|
||||
)
|
||||
DummyFile = Struct("path" / PascalString(Int32ul), "size" / Int32ul, "offset" / Int32ul)
|
||||
|
||||
PackedHeader = Struct(
|
||||
Const(b"BFPK"), Const(b"\0\0\0\0"), "files" / PrefixedArray(Int32ul, ScrapFile)
|
||||
)
|
||||
DummyHeader = Struct(
|
||||
Const(b"BFPK"), Const(b"\0\0\0\0"), "files" / PrefixedArray(Int32ul, DummyFile)
|
||||
)
|
||||
parser = argparse.ArgumentParser(description="Unpack and Repack .packed files")
|
||||
parser.add_argument(
|
||||
"-u", "--unpack", action="store_true", help="unpack file to 'extracted' directory"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r", "--repack", action="store_true", help="repack file from 'extracted' directory"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--reset", action="store_true", default=False, help="restore backup"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"scrap_dir",
|
||||
metavar="Scrapland Directory",
|
||||
type=str,
|
||||
default=".",
|
||||
help="Scrapland installation directory",
|
||||
)
|
||||
options = parser.parse_args()
|
||||
scrap_dir = os.path.abspath(options.scrap_dir)
|
||||
|
||||
if options.reset:
|
||||
print("Restoring Backups and removing extracted folder...")
|
||||
for packed_file in glob.glob(os.path.join(scrap_dir, "*.packed.bak")):
|
||||
outfile = os.path.basename(packed_file)
|
||||
orig_filename = outfile[:-4]
|
||||
if os.path.isfile(outfile):
|
||||
print("deleting", orig_filename)
|
||||
os.remove(orig_filename)
|
||||
print("moving", outfile, "->", orig_filename)
|
||||
shutil.move(outfile, orig_filename)
|
||||
target_folder = os.path.join("extracted", os.path.basename(orig_filename))
|
||||
print("deleting", target_folder)
|
||||
shutil.rmtree(target_folder)
|
||||
if os.path.isdir("extracted"):
|
||||
input("Press enter to remove rest of extracted folder")
|
||||
shutil.rmtree("extracted")
|
||||
exit("Done!")
|
||||
|
||||
if not (options.unpack or options.repack):
|
||||
parser.print_help()
|
||||
exit()
|
||||
pstatus = ""
|
||||
if options.unpack:
|
||||
if os.path.isdir("extracted"):
|
||||
print("Removing extracted folder")
|
||||
shutil.rmtree("extracted")
|
||||
for packed_file in glob.glob(os.path.join(scrap_dir, "*.packed")):
|
||||
os.chdir(scrap_dir)
|
||||
BN = os.path.basename(packed_file)
|
||||
target_folder = os.path.join("extracted", os.path.basename(packed_file))
|
||||
os.makedirs(target_folder, exist_ok=True)
|
||||
os.chdir(target_folder)
|
||||
print("Unpacking {}".format(os.path.basename(packed_file)))
|
||||
with open(packed_file, "rb") as pkfile:
|
||||
data = PackedHeader.parse_stream(pkfile)
|
||||
print("Offset:", hex(pkfile.tell()))
|
||||
for file in tqdm(data.files, ascii=True):
|
||||
folder, filename = os.path.split(file.path)
|
||||
if folder:
|
||||
os.makedirs(folder, exist_ok=True)
|
||||
with open(file.path, "wb") as outfile:
|
||||
outfile.write(file.data())
|
||||
print("\r" + " " * len(pstatus) + "\r", end="", flush=True)
|
||||
os.chdir(scrap_dir)
|
||||
|
||||
if options.unpack and options.repack:
|
||||
input(
|
||||
"Press enter to rebuild *.packed files from folders in 'extracted' dir..."
|
||||
) # noqa
|
||||
pass
|
||||
|
||||
|
||||
def file_gen(files, offset=0):
|
||||
for real_path, size, path in files:
|
||||
file = dict(path=path, offset=offset, size=size)
|
||||
yield file
|
||||
offset += file["size"]
|
||||
|
||||
|
||||
def make_header(files, offset=0):
|
||||
files_list = list(file_gen(files, offset))
|
||||
return DummyHeader.build(dict(files=files_list))
|
||||
|
||||
|
||||
if options.repack:
|
||||
for folder in glob.glob(os.path.join(scrap_dir, "extracted", "*.packed")):
|
||||
data = []
|
||||
filename = os.path.join(scrap_dir, os.path.basename(folder))
|
||||
for root, folders, files in os.walk(folder):
|
||||
for file in sorted(files):
|
||||
file = os.path.join(root, file)
|
||||
rel_path = bytes(
|
||||
file.replace(folder, "").replace("\\", "/").lstrip("/"),
|
||||
"windows-1252",
|
||||
)
|
||||
size = os.stat(file).st_size
|
||||
data.append((file, size, rel_path))
|
||||
print("Found {} files for {}".format(len(data), filename))
|
||||
offset = len(make_header(data))
|
||||
print("Writing", filename)
|
||||
header = make_header(data, offset)
|
||||
with open(filename, "wb") as outfile:
|
||||
outfile.write(header)
|
||||
for file, size, rel_path in tqdm(data, ascii=True):
|
||||
outfile.write(open(file, "rb").read())
|
||||
print("Done!")
|
|
@ -8,10 +8,13 @@ import string
|
|||
import re
|
||||
from binascii import hexlify
|
||||
|
||||
|
||||
def gen():
|
||||
with open(sys.argv[1], "rb") as fh:
|
||||
size = os.stat(sys.argv[1]).st_size
|
||||
progbar = tqdm(total=size, unit="bytes", unit_scale=True, unit_divisor=1024)
|
||||
progbar = tqdm(
|
||||
total=size, unit="bytes", unit_scale=True, unit_divisor=1024, leave=False
|
||||
)
|
||||
pos = 0
|
||||
for entry in mp.Unpacker(fh, raw=True):
|
||||
progbar.update(fh.tell() - pos)
|
||||
|
@ -27,14 +30,10 @@ def gen():
|
|||
yield entry
|
||||
|
||||
|
||||
|
||||
def strdump(data):
|
||||
printable_chars = set(bytes(string.printable, "ascii")) - set(b"\n\r\t\x0b\x0c")
|
||||
return "".join(chr(c) if c in printable_chars else "." for c in data)
|
||||
|
||||
def tohex(data):
|
||||
return str(hexlify(data), "utf8").upper()
|
||||
|
||||
|
||||
# best=sorted(tqdm(gen(),ascii=True),key=lambda v:len(v['data']),reverse=True)
|
||||
|
||||
|
@ -53,16 +52,24 @@ def tohex(data):
|
|||
# entry['infos'][fmt]=[v[0] for v in struct.iter_unpack(fmt,data)]
|
||||
# return entry
|
||||
|
||||
filters=[re.compile(s) for s in sys.argv[2:]]
|
||||
|
||||
filters = sys.argv[2:]
|
||||
with open("all.log", "w") as of:
|
||||
for entry in gen():
|
||||
fm=[(f.match(entry['filename']) is not None) for f in filters]
|
||||
if filters and not any(fm):
|
||||
fm = any(
|
||||
all(s.lower() in entry["filename"].lower() for s in f.split("|"))
|
||||
for f in filters
|
||||
)
|
||||
if filters and not fm:
|
||||
continue
|
||||
is_magic = bytes(entry["block_id"], "utf8").ljust(4, b"\0") == entry["data"]
|
||||
entry["data_len"] = len(entry["data"])
|
||||
entry["str"] = strdump(entry["data"])
|
||||
entry["data"] = tohex(entry["data"])
|
||||
entry["data"] = entry["data"].hex().upper()
|
||||
if is_magic:
|
||||
print("#" * 50, file=of)
|
||||
print(
|
||||
"{timestamp} {block_id} {filename} {data_len:08X} {data} {str}".format(**entry), file=of
|
||||
"{timestamp} {block_id} {filename} {data_len:08X} {data} {str}".format(
|
||||
**entry
|
||||
),
|
||||
file=of,
|
||||
)
|
||||
|
|
|
@ -38,12 +38,12 @@ def seek_to(fh, offset, pos=None):
|
|||
yield
|
||||
fh.seek(pos)
|
||||
|
||||
def read_array(s,fh):
|
||||
ret=[]
|
||||
|
||||
def read_array(s, fh):
|
||||
ret = []
|
||||
count = read_struct("<I", fh)[0]
|
||||
size = struct.calcsize(s)
|
||||
for _ in range(count):
|
||||
ret.append(read_struct(s,fh))
|
||||
ret.append(read_struct(s, fh))
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -93,7 +93,10 @@ class Parser:
|
|||
print("{}[{}] {} bytes".format(" " * self.depth, magic, len(data)))
|
||||
self.depth += 1
|
||||
fh = BytesIO(data)
|
||||
ret = getattr(self, magic, lambda fh: self._default(magic, fh))(fh)
|
||||
if len(data) != 0:
|
||||
ret = getattr(self, magic, lambda fh: self._default(magic, fh))(fh)
|
||||
else:
|
||||
ret = None
|
||||
pos = fh.tell()
|
||||
leftover = len(fh.read())
|
||||
fh.seek(pos)
|
||||
|
@ -198,17 +201,27 @@ class Parser:
|
|||
dum = {}
|
||||
dum["name"] = read_str(fh)
|
||||
dum["pos"] = read_struct("<fff", fh)
|
||||
dum["rot"] = read_struct("<fff", fh)
|
||||
dum["ang"] = read_struct("<fff", fh)
|
||||
dum["has_ini"] = read_struct("<I", fh)[0]
|
||||
if dum["has_ini"]:
|
||||
dum['ini']=self.parse_block(fh)
|
||||
dum["has_next"] = read_struct("<I", fh)[0]
|
||||
dum["ini"] = self.parse_block(fh)
|
||||
dum["unk_1"] = read_struct("<I", fh)[0]
|
||||
ret["dummies"].append(dum)
|
||||
assert fh.read() == b"", "Leftover Data"
|
||||
return ret
|
||||
|
||||
# def AMC(self, fh):
|
||||
# return len(fh.read())
|
||||
def AMC(self, fh):
|
||||
ret = {}
|
||||
ret["unk_1"] = read_struct("<I", fh)[0]
|
||||
ret["unk_2"] = read_struct("<I", fh)[0]
|
||||
ret["floats"] = read_struct("<16f", fh) # ???
|
||||
ret["cmsh_1"] = [self.parse_block(fh) for _ in range(2)]
|
||||
ret["num_submeshes"] = read_struct("<I", fh)[0]
|
||||
ret["cmsh_2"] = [self.parse_block(fh) for _ in range(ret["num_submeshes"])]
|
||||
return ret
|
||||
|
||||
def CMSH(self, fh):
|
||||
return {"ret": len(fh.read())}
|
||||
|
||||
# def EMI(self, fh):
|
||||
# return len(fh.read())
|
||||
|
@ -218,30 +231,14 @@ class Parser:
|
|||
|
||||
basedir = r"D:/Games/Deep Silver/Scrapland/extracted/Data.packed"
|
||||
|
||||
files = [
|
||||
r"Models/Chars/Dtritus/Dtritus.sm3",
|
||||
r"Models/Elements/AnilloEstructuraA/AnilloEstructuraA.SM3",
|
||||
r"models/elements/antenaa/antenaa.lod1.sm3",
|
||||
# r"models/elements/abshield/anm/loop.cm3",
|
||||
# r"levels/fake/map/map3d.amc",
|
||||
# r"levels/shipedit/map/map3d.dum",
|
||||
# r"levels/menu/map/map3d.emi",
|
||||
r"Models/Skies/Menu/Sky.SM3",
|
||||
r"Levels/Menu/Map/Map3D.SM3",
|
||||
r"Models/Elements/AnilloEstructuraD/AnilloEstructuraD.LOD1.SM3",
|
||||
# r"levels/menu/map/map3d.amc",
|
||||
# r"levels/menu/map/map3d.dum",
|
||||
# r"levels/menu/map/scenecamera/anm/loop.cm3",
|
||||
r"models/chars/boss/boss.sm3",
|
||||
# r"models/chars/boss/anm/boss_walk.cm3",
|
||||
]
|
||||
|
||||
filt = [s.lower() for s in sys.argv[1:]]
|
||||
|
||||
for root, folders, files in os.walk(basedir):
|
||||
for root, _, files in os.walk(basedir):
|
||||
for file in files:
|
||||
path = os.path.join(root, file).replace("\\","/")
|
||||
if not path.lower().endswith(".dum".lower()):
|
||||
path = os.path.join(root, file).replace("\\", "/")
|
||||
if not path.lower().endswith(".amc".lower()):
|
||||
continue
|
||||
if "menu" not in path.lower():
|
||||
continue
|
||||
print("Parsing", path)
|
||||
p = Parser(debug=True)
|
||||
|
@ -252,4 +249,3 @@ for root, folders, files in os.walk(basedir):
|
|||
break
|
||||
pprint(parsed, compact=False, indent=4)
|
||||
print("#" * 50)
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import sys
|
||||
from construct import *
|
||||
from pprint import pprint
|
||||
|
||||
ScrapSaveVar = Struct(
|
||||
"name" / PascalString(Int32ul, encoding="utf-8"),
|
||||
"data" / PascalString(Int32ul, encoding="utf-8"),
|
||||
)
|
||||
ScrapSave = "ScarpSaveGame" / Struct(
|
||||
"title" / PascalString(Int32ul, encoding="utf-8"),
|
||||
"id" / PascalString(Int32ul, encoding="utf-8"),
|
||||
"data" / PrefixedArray(Int32ul, ScrapSaveVar),
|
||||
Terminated,
|
||||
)
|
||||
with open(sys.argv[1], "rb") as sav_file:
|
||||
save = ScrapSave.parse_stream(sav_file)
|
||||
print("ID:", save.id)
|
||||
print("Title:", save.title)
|
||||
for var in save.data:
|
||||
print(" {}: {}".format(var.name, var.data))
|
||||
|
|
@ -3,29 +3,18 @@ from collections import OrderedDict
|
|||
import glob
|
||||
import os
|
||||
import shutil
|
||||
from construct import (
|
||||
Struct,
|
||||
PascalString,
|
||||
Int32ul,
|
||||
Lazy,
|
||||
Pointer,
|
||||
Bytes,
|
||||
this,
|
||||
PrefixedArray,
|
||||
Const,
|
||||
Debugger
|
||||
)
|
||||
from construct import *
|
||||
from tqdm import tqdm
|
||||
|
||||
setglobalstringencoding(None)
|
||||
|
||||
ScrapFile = Struct(
|
||||
"path" / PascalString(Int32ul, encoding="ascii"),
|
||||
"path" / PascalString(Int32ul),
|
||||
"size" / Int32ul,
|
||||
"offset" / Int32ul,
|
||||
"data" / Lazy(Pointer(this.offset, Bytes(this.size))),
|
||||
)
|
||||
DummyFile = Struct(
|
||||
"path" / PascalString(Int32ul, encoding="u8"), "size" / Int32ul, "offset" / Int32ul
|
||||
"data" / OnDemandPointer(this.offset, Bytes(this.size)),
|
||||
)
|
||||
DummyFile = Struct("path" / PascalString(Int32ul), "size" / Int32ul, "offset" / Int32ul)
|
||||
|
||||
PackedHeader = Struct(
|
||||
Const(b"BFPK"), Const(b"\0\0\0\0"), "files" / PrefixedArray(Int32ul, ScrapFile)
|
||||
|
|
Loading…
Reference in New Issue