Skip to content

Commit

Permalink
Start backwards compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
Fernando-A-Rocha committed Jul 6, 2024
1 parent 3d86e8d commit a2754de
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 33 deletions.
63 changes: 39 additions & 24 deletions newmodels_reborn/core/client.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
addEvent("newmodels_reborn:receiveCustomModels", true)

local loadedModels = {}
loadedModels = {}

local FREE_ID_DELAY = 10000 -- ms
local FREE_ID_DELAY = 10000 -- ms
local FREE_ID_DELAY_STEP = 500 -- ms
local currFreeIdDelay = FREE_ID_DELAY

local function applyElementCustomModel(element)
local customModel = tonumber(getElementData(element, CUSTOM_MODEL_DATA_KEY))
local customModel = tonumber(getElementData(element, getCustomModelDataKey(element)))
if not customModel then return end
local loadedModel = loadedModels[customModel]
if not loadedModel then return end
Expand All @@ -19,7 +19,7 @@ local function applyElementCustomModel(element)
paintjob = getVehiclePaintjob(element)
end

_setElementModel(element, loadedModel.id)
_setElementModel(element, loadedModel.id)

if upgrades then
for _, v in pairs(upgrades) do
Expand Down Expand Up @@ -47,7 +47,7 @@ local function loadCustomModel(customModel, elementToApply)
if not allocatedModel then return end

local colPath, txdPath, dffPath = customInfo.col, customInfo.txd, customInfo.dff

local col, txd, dff
if colPath then
col = engineLoadCOL(colPath)
Expand All @@ -58,10 +58,10 @@ local function loadCustomModel(customModel, elementToApply)
if dffPath then
dff = engineLoadDFF(dffPath)
end

if (colPath and not col)
or (txdPath and not txd)
or (dffPath and not dff) then
or (txdPath and not txd)
or (dffPath and not dff) then
if col and isElement(col) then destroyElement(col) end
if txd and isElement(txd) then destroyElement(txd) end
if dff and isElement(dff) then destroyElement(dff) end
Expand All @@ -70,8 +70,8 @@ local function loadCustomModel(customModel, elementToApply)
end

if (col and not engineReplaceCOL(col, allocatedModel))
or (txd and not engineImportTXD(txd, allocatedModel))
or (dff and not engineReplaceModel(dff, allocatedModel)) then
or (txd and not engineImportTXD(txd, allocatedModel))
or (dff and not engineReplaceModel(dff, allocatedModel)) then
if col and isElement(col) then destroyElement(col) end
if txd and isElement(txd) then destroyElement(txd) end
if dff and isElement(dff) then destroyElement(dff) end
Expand All @@ -87,15 +87,16 @@ local function loadCustomModel(customModel, elementToApply)
elseif customInfo.type == "object" then
elementTypes = { "object", "pickup" }
end

-- Set loadedModel info
loadedModels[customModel] = {
id = allocatedModel, baseModel = customInfo.baseModel,
id = allocatedModel,
baseModel = customInfo.baseModel,
elementTypes = elementTypes,
freeAllocatedTimer = nil,
elements = { txd = txd, dff = dff, col = col }
}

if isElement(elementToApply) then
applyElementCustomModel(elementToApply)
end
Expand All @@ -105,7 +106,7 @@ local function countStreamedElementsWithCustomModel(elementTypes, customModel)
local count = 0
for _, elementType in pairs(elementTypes) do
for _, v in pairs(getElementsByType(elementType, root, true)) do
if getElementData(v, CUSTOM_MODEL_DATA_KEY) == customModel then
if getElementData(v, getCustomModelDataKey(elementType)) == customModel then
count = count + 1
end
end
Expand All @@ -129,10 +130,10 @@ local function freeAllocatedModel(customModel, loadedModel)
if isElement(loadedModel.elements.col) then destroyElement(loadedModel.elements.col) end
if isElement(loadedModel.elements.txd) then destroyElement(loadedModel.elements.txd) end
if isElement(loadedModel.elements.dff) then destroyElement(loadedModel.elements.dff) end

-- Unset loadedModel info
loadedModels[customModel] = nil

currFreeIdDelay = currFreeIdDelay - FREE_ID_DELAY_STEP
end, currFreeIdDelay, 1)
end
Expand All @@ -145,19 +146,19 @@ local function freeAllocatedModelIfUnused(customModel)
end
end

local function setElementCustomModel(veh)
local customModel = getElementData(veh, CUSTOM_MODEL_DATA_KEY)
local function setElementCustomModel(element)
local customModel = getElementData(element, getCustomModelDataKey(element))
if not customModel then return end
if not loadedModels[customModel] then
loadCustomModel(customModel, veh)
loadCustomModel(customModel, element)
else
applyElementCustomModel(veh)
applyElementCustomModel(element)
end
end

addEventHandler("onClientElementDataChange", root, function(key, prevCustomModel, newCustomModel)
if not isValidElement(source) then return end
if key ~= CUSTOM_MODEL_DATA_KEY then return end
if key ~= getCustomModelDataKey(source) then return end
prevCustomModel = tonumber(prevCustomModel)

-- Get the base model of the previous custom model the element has
Expand All @@ -179,7 +180,6 @@ addEventHandler("onClientElementDataChange", root, function(key, prevCustomModel
setElementCustomModel(source)
end
if prevCustomModel then

-- Force-set the base model of the previous custom model if resetting the custom model
if (not newCustomModel) and prevLoadedModelBaseModel then
_setElementModel(source, prevLoadedModelBaseModel)
Expand All @@ -197,14 +197,14 @@ end)

addEventHandler("onClientElementStreamOut", root, function()
if not isValidElement(source) then return end
local customModel = getElementData(source, CUSTOM_MODEL_DATA_KEY)
local customModel = getElementData(source, getCustomModelDataKey(source))
if not customModel then return end
freeAllocatedModelIfUnused(customModel)
end)

addEventHandler("onClientElementDestroy", root, function()
if not isValidElement(source) then return end
local customModel = getElementData(source, CUSTOM_MODEL_DATA_KEY)
local customModel = getElementData(source, getCustomModelDataKey(source))
if not customModel then return end
freeAllocatedModelIfUnused(customModel)
end)
Expand All @@ -218,3 +218,18 @@ addEventHandler("newmodels_reborn:receiveCustomModels", resourceRoot, function(c
end
end
end, false)

addEventHandler("onClientResourceStop", resourceRoot, function()
-- Restore the base models of all elements with custom models
for _, elementType in pairs(ELEMENT_TYPES) do
for _, v in pairs(getElementsByType(elementType, root, true)) do
local model = getElementModel(v)
for _, loadedModel in pairs(loadedModels) do
if loadedModel.id == model then
setElementModel(v, loadedModel.baseModel)
break
end
end
end
end
end, false)
18 changes: 11 additions & 7 deletions newmodels_reborn/core/shared.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
CUSTOM_MODEL_DATA_KEY = "newmodels_simple:customModel"
ELEMENT_TYPES = { "vehicle", "ped", "player", "object", "pickup" }

customModels = {}
Expand Down Expand Up @@ -69,6 +68,11 @@ function isDefaultID(elementType, id)
return false
end

-- Variable is unused, it is only necessary for backwards compatibility
function getCustomModelDataKey(elementOrElementType)
return "newmodels_reborn:customModel"
end

function isValidElement(element)
local elementType = getElementType(element)
for _, elementType2 in pairs(ELEMENT_TYPES) do
Expand Down Expand Up @@ -123,7 +127,7 @@ local function createElementSafe(elementType, id, ...)
return false
end
if baseModel ~= id then
setElementData(element, CUSTOM_MODEL_DATA_KEY, id, not isClientsideScript)
setElementData(element, getCustomModelDataKey(elementType), id, not isClientsideScript)
end
return element
end
Expand Down Expand Up @@ -181,20 +185,20 @@ function setPickupType(thePickup, theType, id, ammo)
if theType and theType == 3 then
local baseModel = getBaseModelIdFromCustomModelId(id)
if baseModel ~= id then
setElementData(thePickup, CUSTOM_MODEL_DATA_KEY, id, not isClientsideScript)
setElementData(thePickup, getCustomModelDataKey("pickup"), id, not isClientsideScript)
return true
end
end

setElementData(thePickup, CUSTOM_MODEL_DATA_KEY, nil, not isClientsideScript)
setElementData(thePickup, getCustomModelDataKey("pickup"), nil, not isClientsideScript)
return _setPickupType(thePickup, theType, id, ammo)
end

-- Returns a custom model ID (if custom) or a default model ID (if default)
function getElementModel(element)
assert(isElement(element), "Invalid element passed: " .. tostring(element))
assert(isValidElement(element), "Invalid element type passed: " .. getElementType(element))
return getElementData(element, CUSTOM_MODEL_DATA_KEY) or _getElementModel(element)
return getElementData(element, getCustomModelDataKey(element)) or _getElementModel(element)
end

-- PS. You can't set element model on a pickup
Expand All @@ -209,9 +213,9 @@ function setElementModel(element, id)
end

if baseModel ~= id then
setElementData(element, CUSTOM_MODEL_DATA_KEY, id, not isClientsideScript)
setElementData(element, getCustomModelDataKey(element), id, not isClientsideScript)
else
setElementData(element, CUSTOM_MODEL_DATA_KEY, nil, not isClientsideScript)
setElementData(element, getCustomModelDataKey(element), nil, not isClientsideScript)
end

return true
Expand Down
9 changes: 7 additions & 2 deletions newmodels_reborn/meta.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
https://nightly.mtasa.com -->
<min_mta_version client="1.6.0-9.22505.0" server="1.6.0-9.22505.0"></min_mta_version>

<!-- Scripts -->
<script src="optional/s_testing.lua" type="server"/> <!-- Feel free to delete this script -->
<!-- Main Scripts -->
<script src="core/shared.lua" type="shared"/>
<script src="core/client.lua" type="client"/>
<script src="core/server.lua" type="server"/>

<!-- Testing -->
<script src="optional/s_testing.lua" type="server"/>

<!-- Backwards compatibility with newmodels 3.3.0 -->
<script src="optional/shared/*.lua" type="shared"/>

<!-- Exported functions -->
<export function="isDefaultID" type="shared"/>
<export function="createObject" type="shared"/>
Expand Down
137 changes: 137 additions & 0 deletions newmodels_reborn/optional/compatibility/shared/funcs.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
-- Backwards compatibility with newmodels 3.3.0

local OLD_DATA_NAMES = {
ped = "skinID",
vehicle = "vehicleID",
object = "objectID",
}
OLD_DATA_NAMES.pickup = OLD_DATA_NAMES.object
OLD_DATA_NAMES.player = OLD_DATA_NAMES.ped

local OLD_BASE_DATA_NAME = "baseID"

local function convertCustomModelInfoToOldFormat(customModelInfo)
local baseModel = customModelInfo.baseModel
local customModel = customModelInfo.id
local colPath, txdPath, dffPath = customModelInfo.col, customModelInfo.txd, customModelInfo.dff
local mod = {
id = customModel,
base_id = baseModel,
name = "",
path = { col = colPath, txd = txdPath, dff = dffPath },
}
mod.paths = mod.path
return mod
end

-- Exported
function getDataNameFromType(elementType)
if type(elementType) == "string" then
return OLD_DATA_NAMES[elementType]
end
end

-- Rewrite this function
function getCustomModelDataKey(elementType)
if type(elementType) == "string" then
return OLD_DATA_NAMES[elementType]
end
end

-- Exported
function getBaseModelDataName()
return OLD_BASE_DATA_NAME
end

-- Exported
function getModDataFromID(id)
id = tonumber(id)
if not id then return end
local customInfo = customModels[id]
if not customInfo then return end
local mod = convertCustomModelInfoToOldFormat(customInfo)
return mod, customInfo.type
end

-- Exported
function getModList()
local modList = {}
for customModel, customInfo in pairs(customModels) do
modList[customModel] = convertCustomModelInfoToOldFormat(customInfo)
end
return modList
end

-- Exported
function getBaseModel(element)
if not isElement(localPlayer) then
return getElementModel(element)
else
local customModel = tonumber(getElementData(element, getCustomModelDataKey(element)))
if customModel then
return customModels[customModel] and customModels[customModel].baseModel or nil
else
return getElementModel(element)
end
end
end

-- Exported
function isCustomModID(id)
local mod, modType = getModDataFromID(id)
if not mod then return false end
return true, mod, modType
end

-- Exported
function isRightModType(et, modEt)
if et == modEt then
return true
end
if (et == "player" or et == "ped") and (modEt == "player" or modEt == "ped") then
return true
end
if (et == "pickup" or et == "object") and (modEt == "pickup" or modEt == "object") then
return true
end
return false
end

-- Exported
function checkModelID(id, elementType)
assert(tonumber(id), "Non-number ID passed")
assert(
(elementType == "ped" or elementType == "player" or elementType == "object" or elementType == "vehicle" or elementType == "pickup"),
"Invalid element type passed: " .. tostring(elementType))
local dataName = OLD_DATA_NAMES[elementType]
assert(dataName, "No data name for element type: " .. tostring(elementType))
if elementType == "pickup" then
elementType = "object"
end
local baseModel
local isCustom, mod, modType = isCustomModID(id)
if isCustom then
if not isRightModType(elementType, modType) then
return "WRONG_MOD"
end
if mod then baseModel = mod.base_id end
elseif isDefaultID(elementType, id) then
baseModel = id
else
return "INVALID_MODEL"
end

return baseModel, isCustom, dataName, OLD_BASE_DATA_NAME
end

if isElement(localPlayer) then
-- Exported
function isClientReady() return true end -- Now the client is always ready :-)

-- Exported
function isModAllocated(id)
id = tonumber(id)
if not id then return end
return loadedModels[id] ~= nil
end
end

0 comments on commit a2754de

Please sign in to comment.