The article describes the expected result data for bridge construction, in a raw way.

In Transport Fever 2, bridge are constructed by UpdateFn, the game supplies bridgeutil.makeDefaultUpdateFn to generate an updateFn but you can ignore it and make you own bridge form.

**params**

The params are in the following structure:

```
{
pillarHeights = { ... },
pillarLength = ..,
pillarWidth = ..,
railingIntervals = {
{
hasPillar = { false, true },
lanes = {
{ offset = .., type = .. }
},
length = 26.934680938721
},
...
},
railingWidth = 4,
state = {
models = { ... }
}
}
```

Display More
If you want to make your customized updateFn for bridge, the important information are pillarHeights, railingIntervals, railingWidth

The state.models table stores some mdl size information, which maybe useful

**result**

The result table requires two elements:

**basic model elememt**

A model element is expected in the following structure, we call it an **M** in the following text

**pillarModels**

pillarHeights describes the pillars of different heights requires by the game, so you need to give the answer in pillarModels for each height

pillarModels can be obtained by mapping pillarHeights subElements

```
for i = 1, #pillarHeights do
pillarModels[i] = fx(pillarHeights[i], railingIntervals, railingWidth)
end
```

The internal structure of each pillarModels[i] element is expected as a 2-order table

```
function fx(height, railingIntervals, railingWidth)
local result = fz(height, fy(...))
return result
end
```

in which

fy(z, ...) returns a list of M arranged in horizontal direction, according to railingIntervals and railingWidth, z is the Z-axis displacement given by fz (only 1 M in case of a column pillar, or many in case of a wide pillar. nothing is case no pillar is needed)

fz(...) calculats the number and type of .mdl needed to stack the pillar in Z-axis and gives fy(...) needed information

__Attention:__

The heights given in pillarHeights are heights of the top of pillars

__Assertion__

#pillarModels == #pillarHeights

**railingModels**

railingModels describes the arrangement of railing models in forward direction, as X-axis, in each case, the railing many be divided into several segements

railingModels can be obtained by mapping railingIntervals subElements

for each segment, like the pillarModels, the railingModels[i] are expected to be a 2-order table

```
function fs(interval, railingWidth)
local result = fx(interval.length, fy(...))
return result
end
```

in which

fy(x, offset, ...) returns a list of M arranged in horizontal direction, according to offset and railingWidth, x is the X-axis displacement given by fx, the offset is interval.lanes.offset, a list of each track/street arranged on Y-axis

fx(...) calculats the number and type of .mdl needed to arrange the railing X-axis and gives fy(...) needed information, based on the length given by the interval

The x = 0 point is aligned to the start of the track/street and the x = length point is the end of end.

__Assertion__

#railingModels == #railingHeights

Other requirements

If you are suffering from strange rotation of model on curves, try to set its pivot on x = 0, and the rest part of model on the positive x side

__Attention:__

For if the left and right railings are on the same mdl file, use X-aixs flipping rather than Z-aixs rotation by 180°, since the game will flip the normals of flipped models automatically.

**Code example**

(from Ventabren viaduc)

```
updateFn = function(params)
local result = {
railingModels = {},
pillarModels = {}
}
for i, height in ipairs(params.pillarHeights) do
local colHeight = height - 10.2
local nSeg = math.ceil(colHeight / 6)
local rs = {
{
{
id = "bridge/ventabren/pillar_top.mdl",
transf = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, height, 1}
}
}
}
for s = 1, nSeg do
table.insert(
rs,
{
{
id = "bridge/ventabren/pillar_btm.mdl",
transf = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -10.2 - (s - 1) * 6 + height, 1}
}
}
)
end
table.insert(result.pillarModels, rs)
end
for i, interval in ipairs(params.railingIntervals) do
local nSeg = math.floor((interval.length) / 6)
if nSeg < 1 then nSeg = 1 end
local lSeg = interval.length / nSeg
local xScale = lSeg / 5.8
local minOffset = interval.lanes[1].offset
local maxOffset = interval.lanes[#interval.lanes].offset
local width = maxOffset - minOffset
local nPart = math.floor(width / 5)
local wPart = width / nPart
local yScale = wPart / 5
local set = function(n)
local partName = n == 1 and "start" or (n == nSeg and "end" or "start")
local x = (n - 1) * lSeg
local set = {
{
id = "bridge/ventabren/railing_" .. partName .. "_side.mdl",
transf = {xScale, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, minOffset - 2, 0, 1}
},
{
id = "bridge/ventabren/railing_" .. partName .. "_side_2.mdl",
transf = {xScale, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, maxOffset + 2, 0, 1}
}
}
for k = 1, nPart do
table.insert(set,
{
id = "bridge/ventabren/railing_" .. partName .. "_rep.mdl",
transf = {xScale, 0, 0, 0, 0, yScale, 0, 0, 0, 0, 1, 0, x, minOffset + (k - 1) * wPart, 0, 1}
}
)
end
return set
end
local rs = {}
for s = 1, nSeg do
table.insert(rs, set(s))
end
table.insert(result.railingModels, rs)
end
return result
end
```

Display More