Vehicles
This commit is contained in:
@@ -5,8 +5,8 @@ Drop a `.dff` and `.txd` into `models/`, open `/samp/skin/<id>`, and it renders.
|
||||
The RenderWare files are parsed in the browser — no conversion step, no Blender,
|
||||
no build tooling.
|
||||
|
||||
`/samp/skin/<id>` is the only thing the server exposes. The root, `/index.html`
|
||||
and any other path return 404.
|
||||
`/samp/skin/<id>` and `/samp/vehicle/<id>` are the only things the server
|
||||
exposes. The root, `/index.html` and any other path return 404.
|
||||
|
||||
## Running
|
||||
|
||||
@@ -52,6 +52,137 @@ That yields **265 skins**. Three groups are absent for real reasons:
|
||||
|
||||
Extracted models are gitignored; they're Rockstar's assets, not yours to ship.
|
||||
|
||||
## Vehicles
|
||||
|
||||
`/samp/vehicle/<id>` renders a vehicle, where `<id>` is the SA-MP model id
|
||||
(400-611). They come out of your own install the same way skins do:
|
||||
|
||||
```bash
|
||||
node tools/extract-vehicles.js --game "D:/SteamLibrary/steamapps/common/Grand Theft Auto San Andreas"
|
||||
```
|
||||
|
||||
That reads `data/vehicles.ide` for the id -> model mapping, pulls each `.dff`
|
||||
and `.txd` out of `models/gta3.img`, and writes them to
|
||||
`models/vehicles/<id>.dff` / `<id>.txd`. All 212 come across, along with the 194
|
||||
upgrade parts from `data/maps/veh_mods/veh_mods.ide` - vehicles are 400-611 and
|
||||
parts 1000-1193, so one flat folder holds both. It also copies two things the
|
||||
viewer needs:
|
||||
|
||||
- `vehicle.txd`, from `models/generic/`. The grunge, glass, light and tyre
|
||||
textures every vehicle's materials name live there rather than in the
|
||||
per-vehicle txd, so without it most of a car renders untextured.
|
||||
- `vehicles.json`, built from `data/carcols.dat` and `data/carmods.dat`: the 127
|
||||
entry colour palette, each vehicle's factory colour combinations, how many
|
||||
paintjobs it has, and which upgrade parts it accepts.
|
||||
|
||||
A vehicle clump is not just "every atomic, drawn at its frame". Three rules come
|
||||
with it, all in [public/js/vehicle.js](public/js/vehicle.js):
|
||||
|
||||
- **Damage variants.** `bump_front_ok` and `bump_front_dam` are both in the
|
||||
clump. The `_dam` ones are hidden, or they z-fight the intact panels.
|
||||
- **`chassis_vlo`.** The low detail chassis sits inside the real one, and is
|
||||
hidden for the same reason.
|
||||
- **Wheels.** A car carries exactly *one* `wheel` atomic, parented to whichever
|
||||
`wheel_XX_dummy` the modeller happened to pick. The game clones it to every
|
||||
dummy, so the viewer does too - mirrored on the left, because all the dummies
|
||||
share one orientation and differ only in position. Six wheelers work out of
|
||||
the box (`wheel_lm_dummy`), and a vehicle that models a corner itself keeps
|
||||
its own geometry.
|
||||
|
||||
### Colours
|
||||
|
||||
SA encodes paint in the material colour: the game looks for a reserved value and
|
||||
swaps in the carcols entry. Checked against the retail models - every car uses
|
||||
`60,255,0` for the primary, two thirds also use `255,0,175` for the secondary,
|
||||
and the `car4` vehicles (camper, cement, squalo) add `0,255,255` for the third.
|
||||
Those materials keep their colour when textured rather than being forced to
|
||||
white, so the grunge map multiplies over the body colour the way it does in
|
||||
game.
|
||||
|
||||
Colours are carcols palette indices - the same numbers `ChangeVehicleColor`
|
||||
takes - and default to the vehicle's first factory combination:
|
||||
|
||||
```
|
||||
/samp/vehicle/596?c1=3&c2=1
|
||||
```
|
||||
|
||||
Repainting does not need a reload, so the console gets `setColors(3, 1)`, plus
|
||||
`carcols` for the palette and `viewer` for everything else.
|
||||
|
||||
### Upgrade parts
|
||||
|
||||
Parts are fitted by component id - the same numbers `AddVehicleComponent` takes
|
||||
- and stack with the colour parameters:
|
||||
|
||||
```
|
||||
/samp/vehicle/401?u=1005,1006,1001,1007,1020,1013,1008,1025&c1=3&c2=1
|
||||
```
|
||||
|
||||
An upgrade dff is a single atomic on a single root frame and carries no
|
||||
attachment information at all. What holds it on is a dummy frame in the vehicle,
|
||||
picked by the prefix of the part's model name:
|
||||
|
||||
| prefix | frame | |
|
||||
| --- | --- | --- |
|
||||
| `spl_` `rf_` `nto_` `lgt_` | `ug_spoiler` `ug_roof` `ug_nitro` `ug_lights` | |
|
||||
| `bnt_` `bntl_` `bntr_` | `ug_bonnet` `ug_bonnet_left` `ug_bonnet_right` | |
|
||||
| `wg_l_` `wg_r_` | `ug_wing_left` `ug_wing_right` | |
|
||||
| `misc_a_` `misc_c_` | `misc_a` `misc_c` | |
|
||||
| `fbb_` `bbb_` | `ug_frontbullbar` `ug_backbullbar` | slamvan only |
|
||||
| `fbmp_` `rbmp_` | `bump_front_dummy` `bump_rear_dummy` | replaces the stock bumper |
|
||||
| `exh_` | `exhaust_ok` | replaces the stock exhaust |
|
||||
| `wheel_` | every wheel dummy | |
|
||||
|
||||
Two of those took measuring rather than guessing:
|
||||
|
||||
- **Exhausts hang off `exhaust_ok`, not `exhaust`.** The `exhaust` frame is the
|
||||
smoke emitter and sits about a metre behind the car. Across the 31 vehicles
|
||||
that accept `exh_b_l`, mounting on the stock exhaust component puts the pipe
|
||||
end within a few cm of the rear of the body every time; mounting on `exhaust`
|
||||
overshoots by a metre every time.
|
||||
- **A part's own root transform is dropped.** Fitting one re-frames its atomic
|
||||
onto the vehicle's dummy, which discards the frame it came with. Only the
|
||||
bumpers have a non-identity root - `fbmp_a_l`'s is a metre off centre and its
|
||||
geometry cancels that out, exactly like the stock bumper does against
|
||||
`bump_front_dummy` - so they are the only parts where it shows.
|
||||
|
||||
Parts carry their own `_dam` twins, skipped like the vehicle's own. Fitting a
|
||||
left hand body kit part fits its right hand twin too, which is what carmods'
|
||||
`link` section is for. Wheels are the one part that needs scaling: a stock wheel
|
||||
already comes at the vehicle's own size, an upgrade wheel is modelled at unit
|
||||
diameter and the ide's wheel scale is what sizes it - measured, infernus stock
|
||||
0.70 against a scale of 0.70, linerun 1.10 against 1.10, every `wheel_*` upgrade
|
||||
0.99.
|
||||
|
||||
`?u=` accepts anything; `mods` in the console lists what the vehicle is actually
|
||||
offered, id to part name.
|
||||
|
||||
### Paintjobs
|
||||
|
||||
Thirteen vehicles take one - the six Transfender tuners, the six lowriders and
|
||||
the camper. Three each, except broadway with two and camper with one:
|
||||
|
||||
```
|
||||
/samp/vehicle/562?pj=0
|
||||
```
|
||||
|
||||
A paintjob is a one texture dictionary stored beside the vehicle in the archive
|
||||
as `<model>1.txd` upwards, extracted zero based to `<id>_pj<n>.txd` because that
|
||||
is what `ChangeVehiclePaintjob` counts from. It is not a name for name texture
|
||||
swap: the vehicle's own txd marks the panels a paintjob covers by giving them a
|
||||
texture called `remap*`, and fitting one replaces that texture on every material
|
||||
using it - seven of them on the elegy, across the chassis, doors, bonnet, boot
|
||||
and both bumpers.
|
||||
|
||||
The artwork carries the colour, so those panels stop taking the primary paint
|
||||
while a paintjob is on and go back to it when it comes off. `setPaintjob(0)` in
|
||||
the console switches without a reload, and anything out of range takes it back
|
||||
off the way 3 does in game.
|
||||
|
||||
Not yet handled: `stereo` and `hydralics` have component ids but no geometry,
|
||||
the light corona materials, dirt level, and the `_hi`/`_lo` LOD split some
|
||||
planes use.
|
||||
|
||||
## Naming
|
||||
|
||||
Files are named by id: `<id>.dff` and `<id>.txd`, in `models/` locally or under
|
||||
@@ -88,6 +219,7 @@ failed fetch instead.
|
||||
## API
|
||||
|
||||
- `GET /api/skin/:id` — the URLs for one id, or 404
|
||||
- `GET /api/vehicle/:id` — the same, plus the shared txd and catalogue URLs
|
||||
|
||||
## What's implemented
|
||||
|
||||
|
||||
Reference in New Issue
Block a user