3d models are structured in 2 file:
#.i3d that contains information about 3d models in xml language.
#.shape that contains 3d models structure
On dlc the .shape file are cripted, and giants editor crash when try to import a models with cript shape.
From my test i've discover thath:
Open i3d with normal shape file:
reading frist 4096 bytes,next 4096 bytes,next 4096.
finally it start reading shape from offeset 8192.
Open i3d with cripted shape file:
reading frist 4096 bytes,reading frist 4096 bytes,reading next 4096 bytes,
finally it start reading shape from offeset 4096.
This protected shape are parts of some DLC, and i've extracted dlc, fixed all encripted script then put into game like as normal mod. And it works until you try to buy element with shape cripted. this made game crashes.
I've figured this have different function for loading dlc and standar mod,then i've decripted base data from the game and i've find function thath load mod and dlc(it's lua script):
Code: Select all
function loadDlcs()
if g_isDemo or g_isGamescomVersion then
return
end
for i = 1, table.getn(g_dlcsDirectories) do
local dir = g_dlcsDirectories[i]
if dir.isLoaded then
loadDlcsFromDirectory(dir.path)
end
end
end
function loadDlcsFromDirectory(dlcsDir)
createFolder(dlcsDir)
local files = Files:new(dlcsDir)
for k, v in pairs(files.files) do
local addDLCPrefix = false
local dlcFileHash, dlcDir, xmlFilename
if v.isDirectory then
if g_isDevelopmentVersion then
dlcDir = v.filename
xmlFilename = "dlcDesc.xml"
addDLCPrefix = true
end
else
local len = v.filename:len()
if len > 4 then
local ext = v.filename:sub(len - 3)
if ext == ".dlc" then
dlcDir = v.filename:sub(1, len - 4)
dlcFileHash = getFileMD5(dlcsDir .. "/" .. v.filename, dlcDir)
xmlFilename = "dlcDesc.xml"
addDLCPrefix = true
elseif ext == ".zip" or ext == ".gar" then
dlcDir = v.filename:sub(1, len - 4)
dlcFileHash = getFileMD5(dlcsDir .. "/" .. v.filename, dlcDir)
xmlFilename = "modDesc.xml"
addDLCPrefix = false
end
end
end
if dlcDir ~= nil and xmlFilename ~= nil and g_dlcModNameHasPrefix[dlcDir] == nil then
local absDlcDir = dlcsDir .. "/" .. dlcDir .. "/"
local dlcFile = absDlcDir .. xmlFilename
g_dlcModNameHasPrefix[dlcDir] = addDLCPrefix
loadModDesc(dlcDir, absDlcDir, dlcFile, dlcFileHash, dlcsDir .. "/" .. v.filename, v.isDirectory, addDLCPrefix)
end
end
end
function loadMods()
local modsDir = g_modsDirectory
if g_isDemo or g_isGamescomVersion then
return
end
g_showIllegalActivityInfo = false
local files = Files:new(modsDir)
for k, v in pairs(files.files) do
local modFileHash, modDir
if v.isDirectory then
modDir = v.filename
else
local len = v.filename:len()
if len > 4 then
local ext = v.filename:sub(len - 3)
if ext == ".zip" or ext == ".gar" then
modDir = v.filename:sub(1, len - 4)
modFileHash = getFileMD5(modsDir .. "/" .. v.filename, modDir)
end
end
end
if modDir ~= nil then
local absModDir = modsDir .. "/" .. modDir .. "/"
local modFile = absModDir .. "modDesc.xml"
loadModDesc(modDir, absModDir, modFile, modFileHash, modsDir .. "/" .. v.filename, v.isDirectory, false)
end
end
if g_showIllegalActivityInfo then
print("Info: This game protects you from illegal activity")
end
g_showIllegalActivityInfo = nil
end
function loadModDesc(modName, modDir, modFile, modFileHash, absBaseFilename, isDirectory, addDLCPrefix)
if not getIsValidModDir(modName) then
print("Error: Invalid mod name '" .. modName .. "'! Characters allowed: (_, A-Z, a-z, 0-9). The first character must not be a digit")
return
end
local origModName = modName
if addDLCPrefix then
modName = g_uniqueDlcNamePrefix .. modName
end
if g_modNameToDirectory[modName] ~= nil then
return
end
g_modNameToDirectory[modName] = modDir
local isDLCFile = false
if Utils.endsWith(modFile, "dlcDesc.xml") then
isDLCFile = true
if not fileExists(modFile) then
g_hasLicenseError = true
print("Error: No license for dlc " .. modName .. ". Please reinstall.")
return
end
end
if isDLCFile then
print("Load dlc: " .. modName)
else
print("Load mod: " .. modName)
end
local xmlFile = loadXMLFile("ModFile", modFile)
local modDescVersion = getXMLInt(xmlFile, "modDesc#descVersion")
if modDescVersion == nil then
print("Error: Missing descVersion attribute in mod " .. modName)
delete(xmlFile)
return
end
if modDescVersion ~= 9 and modDescVersion ~= 10 and modDescVersion ~= 11 and modDescVersion ~= 12 and modDescVersion ~= 13 and modDescVersion ~= 14 and modDescVersion ~= 15 and modDescVersion ~= 16 then
print("Error: Unsupported mod description version in mod " .. modName)
delete(xmlFile)
return
end
if _G[modName] ~= nil then
print("Error: Invalid mod name '" .. modName .. "'")
delete(xmlFile)
return
end
if isDLCFile then
local requiredModName = getXMLString(xmlFile, "modDesc.multiplayer#requiredModName")
if requiredModName ~= nil and requiredModName ~= origModName then
print("Error: Do not rename dlcs. Name: '" .. origModName .. "'. Expect: '" .. requiredModName .. "'")
delete(xmlFile)
return
end
end
local modEnv = {}
_G[modName] = modEnv
local modEnv_mt = {__index = _G}
setmetatable(modEnv, modEnv_mt)
if not isDLCFile then
modEnv._G = modEnv
end
modEnv.g_i18n = I18N:new(false)
I18N.initModI18N(modEnv.g_i18n, g_i18n, modName)
function modEnv.loadstring(str, chunkname)
str = "setfenv(1," .. modName .. "); " .. str
return loadstring(str, chunkname)
end
function modEnv.source(filename, env)
if isAbsolutPath(filename) then
source(filename, modName)
else
source(filename)
end
end
function modEnv.InitEventClass(classObject, className)
InitEventClass(classObject, modName .. "." .. className)
end
function modEnv.InitObjectClass(classObject, className)
InitObjectClass(classObject, modName .. "." .. className)
end
function modEnv.registerObjectClassName(object, className)
registerObjectClassName(object, modName .. "." .. className)
end
function modEnv.registerPlaceableType(typeName, object)
registerPlaceableType(modName .. "." .. typeName, object)
end
modEnv.InitStaticEventClass = ""
modEnv.InitStaticObjectClass = ""
modEnv.loadMod = ""
modEnv.loadModDesc = ""
modEnv.loadDlcs = ""
modEnv.loadDlcsFromDirectory = ""
modEnv.loadMods = ""
modEnv.deleteFile = ""
modEnv.deleteFolder = ""
if not isDLCFile then
modEnv.getClassObject = ""
modEnv.getFunction = ""
end
if g_dedicatedServerInfo ~= nil then
function modEnv.setFramerateLimiter()
end
modEnv.g_dedicatedServerMinFrameLimit = g_dedicatedServerMinFrameLimit
modEnv.g_dedicatedServerMaxFrameLimit = g_dedicatedServerMaxFrameLimit
end
local onCreateUtil = {}
onCreateUtil.onCreateFunctions = {}
modEnv.g_onCreateUtil = onCreateUtil
function onCreateUtil.addOnCreateFunction(name, func)
onCreateUtil.onCreateFunctions[name] = func
end
function onCreateUtil.activateOnCreateFunctions()
for name in pairs(modOnCreate) do
modOnCreate[name] = nil
end
for name, func in pairs(onCreateUtil.onCreateFunctions) do
modOnCreate[name] = function(self, id)
func(id)
end
end
end
function onCreateUtil.deactivateOnCreateFunctions()
for name in pairs(modOnCreate) do
modOnCreate[name] = nil
end
end
local i = 0
while true do
local baseName = string.format("modDesc.l10n.text(%d)", i)
local name = getXMLString(xmlFile, baseName .. "#name")
if name == nil then
break
end
local text = getXMLString(xmlFile, baseName .. "." .. g_languageShort)
if text == nil then
text = getXMLString(xmlFile, baseName .. ".en")
if text == nil then
text = getXMLString(xmlFile, baseName .. ".de")
end
end
if text == nil then
print("Warning: No l10n text found for entry '" .. name .. "' in mod '" .. modName .. "'")
elseif modEnv.g_i18n:hasModText(name) then
print("Warning: Duplicate l10n entry '" .. name .. "' in mod '" .. modName .. "'. Ignoring this defintion.")
else
modEnv.g_i18n:setText(name, text)
end
i = i + 1
end
local l10nFilenamePrefix = getXMLString(xmlFile, "modDesc.l10n#filenamePrefix")
if l10nFilenamePrefix ~= nil then
local l10nFilenamePrefixFull = Utils.getFilename(l10nFilenamePrefix, modDir)
local l10nXmlFile
local langs = {
g_languageShort,
"en",
"de"
}
for _, lang in ipairs(langs) do
local l10nFilename = l10nFilenamePrefixFull .. "_" .. lang .. ".xml"
if fileExists(l10nFilename) then
l10nXmlFile = loadXMLFile("TempConfig", l10nFilename)
break
end
end
if l10nXmlFile ~= nil then
local textI = 0
while true do
local key = string.format("l10n.texts.text(%d)", textI)
if not hasXMLProperty(l10nXmlFile, key) then
break
end
local name = getXMLString(l10nXmlFile, key .. "#name")
local text = getXMLString(l10nXmlFile, key .. "#text")
if name ~= nil and text ~= nil then
if modEnv.g_i18n:hasModText(name) then
print("Warning: Duplicate l10n entry '" .. name .. "' in '" .. l10nFilename .. "'. Ignoring this defintion.")
else
modEnv.g_i18n:setText(name, text:gsub("\r\n", "\n"))
end
end
textI = textI + 1
end
delete(l10nXmlFile)
else
print("Warning: No l10n file found for '" .. l10nFilenamePrefix .. "' in mod '" .. modName .. "'")
end
end
local title = Utils.getXMLI18N(xmlFile, "modDesc.title", nil, "", modName)
local desc = Utils.getXMLI18N(xmlFile, "modDesc.description", nil, "", modName)
local iconFilename = Utils.getXMLI18N(xmlFile, "modDesc.iconFilename", nil, "", modName)
if title == "" then
print("Error: Missing title in mod " .. modName)
delete(xmlFile)
return
end
if desc == "" then
print("Error: Missing description in mod " .. modName)
delete(xmlFile)
return
end
local isMultiplayerSupported = Utils.getNoNil(getXMLBool(xmlFile, "modDesc.multiplayer#supported"), false)
if modFileHash == nil then
if isMultiplayerSupported then
print("Warning: Only zip mods are supported in multiplayer. You need to zip the mod " .. modName .. " to use it in multiplayer.")
end
isMultiplayerSupported = false
end
if isMultiplayerSupported and iconFilename == "" then
print("Error: Missing icon filename in mod " .. modName)
delete(xmlFile)
return
end
loadModDescInput(xmlFile, modName)
local i = 0
while true do
local baseName = string.format("modDesc.maps.map(%d)", i)
if not hasXMLProperty(xmlFile, baseName) then
break
end
local mapId = Utils.getNoNil(getXMLString(xmlFile, baseName .. "#id"), "")
local defaultVehiclesXMLFilename = Utils.getNoNil(getXMLString(xmlFile, baseName .. "#defaultVehiclesXMLFilename"), "")
local mapTitle = Utils.getXMLI18N(xmlFile, baseName .. ".title", nil, "", modName)
local mapDesc = Utils.getXMLI18N(xmlFile, baseName .. ".description", nil, "", modName)
local mapClassName = Utils.getNoNil(getXMLString(xmlFile, baseName .. "#className"), "")
local mapFilename = Utils.getNoNil(getXMLString(xmlFile, baseName .. "#filename"), "")
local briefingImagePrefix = Utils.getXMLI18N(xmlFile, baseName .. ".briefingImagePrefix", nil, "", modName)
local briefingTextPrefix = Utils.getXMLI18N(xmlFile, baseName .. ".briefingTextPrefix", nil, "", modName)
local mapIconFilename = Utils.getXMLI18N(xmlFile, baseName .. ".iconFilename", nil, "", modName)
local altMapIconFilename = Utils.getXMLI18N(xmlFile, baseName .. ".altIconFilename", nil, mapIconFilename, modName)
if mapClassName:find("[^%w_]") ~= nil then
print("Error: invalid map class name: " .. mapClassName)
elseif mapId ~= "" and mapTitle ~= "" and mapDesc ~= "" and mapClassName ~= "" and mapFilename ~= "" and defaultVehiclesXMLFilename ~= "" and briefingImagePrefix ~= "" and briefingTextPrefix ~= "" and mapIconFilename ~= "" then
local customEnvironment
local useModDirectory = true
local baseDirectory = modDir
mapFilename, useModDirectory = Utils.getFilename(mapFilename, baseDirectory)
if useModDirectory then
customEnvironment = modName
mapClassName = modName .. "." .. mapClassName
end
mapId = modName .. "." .. mapId
mapIconFilename = Utils.getFilename(mapIconFilename, baseDirectory)
altMapIconFilename = Utils.getFilename(altMapIconFilename, baseDirectory)
briefingImagePrefix = Utils.getFilename(briefingImagePrefix, baseDirectory)
defaultVehiclesXMLFilename = Utils.getFilename(defaultVehiclesXMLFilename, baseDirectory)
MapsUtil.addMapItem(mapId, mapFilename, mapClassName, briefingImagePrefix, briefingTextPrefix, defaultVehiclesXMLFilename, mapTitle, mapDesc, mapIconFilename, altMapIconFilename, baseDirectory, customEnvironment)
end
i = i + 1
end
local version = Utils.getXMLI18N(xmlFile, "modDesc.version", nil, "", modName)
local author = Utils.getXMLI18N(xmlFile, "modDesc.author", nil, "", modName)
if isDLCFile then
local dlcProductId = getXMLString(xmlFile, "modDesc.productId")
if dlcProductId == nil or version == nil then
print("Error: invalid product id or version in DLC " .. modName)
elseif not g_isDemo then
addNotificationFilter(dlcProductId, version)
end
end
iconFilename = Utils.getFilename(iconFilename, modDir)
ModsUtil.addModItem(title, desc, version, author, iconFilename, modName, modDir, modFile, isMultiplayerSupported, modFileHash, absBaseFilename, isDirectory)
delete(xmlFile)
end
can have a suggestion to how to decode shape file?