Skip to content

Add server-side model allocation and functions (follow-up #5232) - #5233

Open
MohabCodeX wants to merge 7 commits into
multitheftauto:masterfrom
MohabCodeX:feat/server-model-allocation-part-2
Open

Add server-side model allocation and functions (follow-up #5232)#5233
MohabCodeX wants to merge 7 commits into
multitheftauto:masterfrom
MohabCodeX:feat/server-model-allocation-part-2

Conversation

@MohabCodeX

@MohabCodeX MohabCodeX commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

This PR is a follow-up to #5232 and implements a server-authoritative model allocation system. It allows servers to dynamically register custom vehicle, ped, and object models, automatically synchronize them with connected and joining players, inherit properties and handling from base models, and safely remap active entities when models are freed.

Special thanks to @Dryxio for proposing the concept, sharing his initial implementation approach, and providing valuable insights that helped shape this server-authoritative system.

Summary of Changes

  • Servers can now allocate custom models dynamically in real-time without requiring manual ID coordination or client-side pre-allocation.
  • Custom models automatically inherit handling physics, names, passenger limits, and visual properties from their parent models.
  • When a custom model is freed in real-time, any active in-game entities using it automatically revert to their parent model to prevent crashes or desync.
  • Added server-side and shared scripting functions to request models, free models, find models by name, and query model metadata.

New Lua Functions

engineRequestModel

Side: Shared (Client & Server)
Allocates a new custom model ID inheriting properties and handling from an existing base model.

Syntax
int engineRequestModel ( string modelType, int parentModelId [, string name ] )
Required Arguments
  • modelType: The element type to allocate ("vehicle", "ped", or "object").
  • parentModelId: The base game model ID to inherit properties and handling from.
Optional Arguments
  • name: A unique custom name or alias for the model.
Returns
  • Returns the allocated integer model ID (42341..65534) on success, or false on failure.

engineFreeModel

Side: Shared (Client & Server)
Frees a previously allocated custom model ID. Any live entities in the game world using this model will automatically fall back to their parent model.

Syntax
bool engineFreeModel ( int modelId )
Required Arguments
  • modelId: The custom model ID to free.
Returns
  • Returns true if the model was successfully freed, or false otherwise.

engineGetModelParent

Side: Shared (Client & Server)
Retrieves the parent base model ID that a custom model inherits properties from.

Syntax
int engineGetModelParent ( int modelId )
Required Arguments
  • modelId: The model ID to query.
Returns
  • Returns the parent model ID as an integer, or false on failure.

engineGetModelType

Side: Shared (Client & Server)
Retrieves the element type associated with a model ID.

Syntax
string engineGetModelType ( int modelId )
Required Arguments
  • modelId: The model ID to query.
Returns
  • Returns "vehicle", "ped", or "object" as a string, or false on failure.

engineGetModelName

Side: Shared (Client & Server)
Retrieves the registered custom name of a model ID.

Syntax
string engineGetModelName ( int modelId )
Required Arguments
  • modelId: The model ID to query.
Returns
  • Returns the model name as a string, or false if not found.

engineGetModelFromName

Side: Shared (Client & Server)
Resolves a custom model's registered name to its logical model ID.

Syntax
int engineGetModelFromName ( string name )
Required Arguments
  • name: The model name to look up.
Returns
  • Returns the integer model ID, or false if no model with that name exists.

engineGetModelAllocatingResource

Side: Server-only
Retrieves the resource that originally requested and allocated the custom model.

Syntax
resource engineGetModelAllocatingResource ( int modelId )
Required Arguments
  • modelId: The custom model ID to query.
Returns
  • Returns the resource element that allocated the model, or false.

engineGetModelsByType

Side: Shared (Client & Server)
Returns a table containing all registered model IDs of a specific type.

Syntax
table engineGetModelsByType ( string modelType [, int minModelId ] )
Required Arguments
  • modelType: The model type to filter by ("vehicle", "ped", or "object").
Optional Arguments
  • minModelId: An optional lower bound to filter model IDs from.
Returns
  • Returns a table array of model ID integers.

engineIsModelCustom

Side: Shared (Client & Server)
Checks whether a model ID represents a custom allocated model.

Syntax
bool engineIsModelCustom ( int modelId )
Required Arguments
  • modelId: The model ID to check.
Returns
  • Returns true if the model is a custom allocated model, or false if it is a vanilla game model.

engineGetModelRuntimeID

Side: Client-only
Gets the internal GTA engine slot currently bound to a server logical model ID.

Syntax
int engineGetModelRuntimeID ( int modelId )
Required Arguments
  • modelId: The server logical model ID (42341..65534).
Returns
  • Returns the integer GTA slot ID, or false.

engineGetModelLogicalID

Side: Client-only
Resolves an internal GTA engine slot ID back to its server logical model ID.

Syntax
int engineGetModelLogicalID ( int runtimeSlot )
Required Arguments
  • runtimeSlot: The internal GTA engine slot ID.
Returns
  • Returns the integer server logical model ID, or false.

Example Workflow

1. Server Script (server.lua)

-- Dynamically allocate custom models on the server
local bmwModel = engineRequestModel("vehicle", 551, "BMW M5")

-- Spawn the custom vehicle directly using the allocated model ID
addCommandHandler("spawnbmw", function(player)
    local x, y, z = getElementPosition(player)
    local veh = createVehicle(bmwModel, x + 2, y, z + 0.5)
    warpPedIntoVehicle(player, veh)
end)

2. Client Script (client.lua)

-- Apply custom textures and geometries to the synchronized model
addEventHandler("onClientResourceStart", resourceRoot, function()
    local bmwModel = engineGetModelFromName("BMW M5")
    if bmwModel then
        local txd = engineLoadTXD("bmw/merit.txd")
        engineImportTXD(txd, bmwModel)

        local dff = engineLoadDFF("bmw/merit.dff")
        engineReplaceModel(dff, bmwModel)
    end
end)

Testing & Verification

server_model_registry_test.zip

  • /testmodels runs automated assertions covering dynamic allocation, handling inheritance, name resolution, and resource cleanup.
  • /spawnbmw, /spawnlada, and /spawnisuzu spawn and warp into the custom vehicles.
  • /freebmw frees the custom model while seated and reverts the car to the base Merit (551).
  • /allocbmw re-allocates the model and transforms the car back to the BMW M5.

…l Allocation Part 1)

- Move hardcoded handling array to handling.conf
- Add objects.conf, peds.conf, and vehicles.conf
- Add config loader classes for handling, vehicles, objects, and peds
…del Allocation Part 2)

- Add CModel base class and CModelVehicle, CModelPed, CModelObject classes
- Add CModelManager for dynamic model allocation and base model registration
- Integrate CModelManager with CGame startup and CResource cleanup
… Allocation Part 3)

- Connect entity managers (vehicle, ped, object) to CModelManager for dynamic validation
- Update vehicle property getters to query CModelVehicle
- Enable parent handling ID resolution in CHandlingManager
…part 4)

- Add CLuaEngineDefs with modern ArgumentParser bindings for server model functions:
  engineRequestModel, engineFreeModel, engineGetModelParent, engineGetModelType,
  engineGetModelAllocatingResource, engineGetModelsByType, and engineIsModelCustom.
- Support requestedId in CModelManager::RequestModel to allow 1:1 synchronization with client-allocated model IDs.
- Fix base model parent ID resolution in CModel.
- Register CLuaEngineDefs in CLuaManager.
- Verified in-game with model_allocation_test resource: 21 unit tests passed and custom BMW vehicle successfully spawned."
@Dryxio

Dryxio commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

I used a similar idea but with server logical IDs separated from each client’s local GTA runtime IDs.
The server automatically syncs models to clients and late joiners, and before freeing a model, existing entities are remapped back to the parent.
I was about to open a PR for it, but maybe some of these ideas can be useful directly in your PR, I think your CModelManager and config approach can still be a good base with a stronger network/lifecycle layer on top

You can check my commits and docs here: server model registry (Dryxio/mtasa-neon@a7a20d32b), completed registry (Dryxio/mtasa-neon@dc25a615c), API docs (https://mtasa-neon-wiki.vercel.app/neon/models-and-streaming)

@MohabCodeX

Copy link
Copy Markdown
Contributor Author

Man, you’re doing some really great work <3 Thank you for the suggestions and sharing. I’ll definitely go through them and review the ideas you mentioned.

@FileEX FileEX added enhancement New feature or request feedback Further information is requested labels Aug 21, 2026
…ic sync

- Enables server-driven model allocation without requiring manual ID coordination or client pre-allocation.
- Automatically inherits handling physics, properties, and vehicle attributes from base game models.
- Safely remaps live in-game entities to their parent models whenever a custom model is freed in real-time.
@MohabCodeX

Copy link
Copy Markdown
Contributor Author

Quick update

  • Transitioned to a fully server-authoritative architecture, eliminating the need for manual ID coordination or client-first allocation.
  • Added real-time fallback to parent models when freeing custom models, alongside safe live re-allocation.
  • Updated the PR description with the Lua API reference.

Special thanks again to @Dryxio.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request feedback Further information is requested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants