Skip to content
Open
11 changes: 11 additions & 0 deletions [editor]/edf/edf.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,17 @@ function edfAddElementNodeData(node, resource)
local validModels = xmlNodeGetAttribute(subnode, "validModels")
dataFields[dname].validModels = validModels and split(validModels, ",") or dataFields[dname].validModels

--[[ Set to false to only save the value if it is not the default value,
useful to prevent map files from growing too much,
especially for properties that are not always required (default: true)
]]
local persistDefault = xmlNodeGetAttribute(subnode, "persistDefault")
if persistDefault then
dataFields[dname].persistDefault = convert.boolean(persistDefault)
else
dataFields[dname].persistDefault = dataFields[dname].persistDefault or true
end

-- update the required flag (default: true)
local requiredAttribute = xmlNodeGetAttribute(subnode,"required")
if requiredAttribute then
Expand Down
40 changes: 40 additions & 0 deletions [editor]/edf/properties.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,46 @@ propertyGetters = {
else
return "false"
end
end,
moveSpeed = function(element)
local time = getElementData(element, "moveSpeed")
if time == nil or time == false then
return 1
else
return time
end
end,
moveDelay = function(element)
local delay = getElementData(element, "moveDelay")
if delay == nil or delay == false then
return 0
else
return delay
end
end,
moveX = function(element)
local offsetX = getElementData(element, "moveX")
if offsetX == nil or offsetX == false then
return 0
else
return offsetX
end
end,
moveY = function(element)
local offsetY = getElementData(element, "moveY")
if offsetY == nil or offsetY == false then
return 0
else
return offsetY
end
end,
moveZ = function(element)
local offsetZ = getElementData(element, "moveZ")
if offsetZ == nil or offsetZ == false then
return 0
else
return offsetZ
end
end
},
ped = {
Expand Down
40 changes: 40 additions & 0 deletions [editor]/edf/properties_client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,46 @@ propertyGetters = {
else
return "false"
end
end,
moveSpeed = function(element)
local time = getElementData(element, "moveSpeed")
if time == nil or time == false then
return 1
else
return time
end
end,
moveDelay = function(element)
local delay = getElementData(element, "moveDelay")
if delay == nil or delay == false then
return 0
else
return delay
end
end,
moveX = function(element)
local offsetX = getElementData(element, "moveX")
if offsetX == nil or offsetX == false then
return 0
else
return offsetX
end
end,
moveY = function(element)
local offsetY = getElementData(element, "moveY")
if offsetY == nil or offsetY == false then
return 0
else
return offsetY
end
end,
moveZ = function(element)
local offsetZ = getElementData(element, "moveZ")
if offsetZ == nil or offsetZ == false then
return 0
else
return offsetZ
end
end
},
ped = {
Expand Down
126 changes: 125 additions & 1 deletion [editor]/editor_main/client/gridlines.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,135 @@ function drawXYZLines()
drawLine({x,y,z},{zx,zy,zz},tocolor(0,0,200,200),thickness)
end

--[[
Draws the where the object will be moved to.
]]
function drawObjectMoveLines()
if not isElement(attachedToElement) then return end
if getElementType(attachedToElement) ~= "object" then return end
if getElementDimension(attachedToElement) ~= getElementDimension(localPlayer) then return end
local x,y,z = edf.edfGetElementPosition(attachedToElement)
if not x then return end

local offsetX = edf.edfGetElementProperty(attachedToElement, "moveX")
local offsetY = edf.edfGetElementProperty(attachedToElement, "moveY")
local offsetZ = edf.edfGetElementProperty(attachedToElement, "moveZ")

if offsetX and math.abs(offsetX) > 0 or offsetY and math.abs(offsetY) > 0 or offsetZ and math.abs(offsetZ) > 0 then
if not offsetX then offsetX = 0 end
if not offsetY then offsetY = 0 end
if not offsetZ then offsetZ = 0 end

local speed = tonumber(edf.edfGetElementProperty(attachedToElement, "moveSpeed"))
if not speed then speed = 1 end
local delay = tonumber(edf.edfGetElementProperty(attachedToElement, "moveDelay"))
if not delay then delay = 0 end
local time = getDistanceBetweenPoints3D(x,y,z,x + offsetX,y + offsetY,z + offsetZ) / speed * 1000
local lineStartPos = {x,y,z}
local lineEndPos = {x + offsetX,y + offsetY,z + offsetZ}
local timeNow = getTickCount()

local progress = timeNow % (time + delay) / time
if progress > 1 then
progress = 1
end

local movementAnimationOffset = {
(lineEndPos[1] - lineStartPos[1]) * progress,
(lineEndPos[2] - lineStartPos[2]) * progress,
(lineEndPos[3] - lineStartPos[3]) * progress
}


local minX,minY,minZ,maxX,maxY,maxZ = edf.edfGetElementBoundingBox ( attachedToElement )
if not minX then
local radius = edf.edfGetElementRadius ( attachedToElement )
if radius then
minX,minY,minZ,maxX,maxY,maxZ = -radius,-radius,-radius,radius,radius,radius
end
end

if minX and minY and minZ and maxX and maxY and maxZ then
-- Define the 8 corners in relative coordinates
local relativeCorners = {
{minX, minY, minZ}, -- 1: min corner
{maxX, minY, minZ}, -- 2
{maxX, maxY, minZ}, -- 3
{minX, maxY, minZ}, -- 4
{minX, minY, maxZ}, -- 5
{maxX, minY, maxZ}, -- 6
{maxX, maxY, maxZ}, -- 7
{minX, maxY, maxZ} -- 8: max corner
}

-- Draw the bounding box moving to the destination position
do
local corners = {}
for i, relCorner in ipairs(relativeCorners) do
local worldX, worldY, worldZ = getPositionFromElementAtOffset(attachedToElement, relCorner[1], relCorner[2], relCorner[3])
corners[i] = {worldX + movementAnimationOffset[1], worldY + movementAnimationOffset[2], worldZ + movementAnimationOffset[3]}
end

local boxColor = tocolor(255, 255, 255, 100)
local lineWidth = 2

-- Bottom face (z = minZ)
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[2][1], corners[2][2], corners[2][3], boxColor, lineWidth)
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[3][1], corners[3][2], corners[3][3], boxColor, lineWidth)
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[4][1], corners[4][2], corners[4][3], boxColor, lineWidth)
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[1][1], corners[1][2], corners[1][3], boxColor, lineWidth)

-- Top face (z = maxZ)
dxDrawLine3D(corners[5][1], corners[5][2], corners[5][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
dxDrawLine3D(corners[6][1], corners[6][2], corners[6][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
dxDrawLine3D(corners[7][1], corners[7][2], corners[7][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
dxDrawLine3D(corners[8][1], corners[8][2], corners[8][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)

-- Vertical edges connecting bottom to top
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
end

-- Draw the bounding box at the destination position
do
local corners = {}
for i, relCorner in ipairs(relativeCorners) do
local worldX, worldY, worldZ = getPositionFromElementAtOffset(attachedToElement, relCorner[1], relCorner[2], relCorner[3])
corners[i] = {worldX + offsetX, worldY + offsetY, worldZ + offsetZ}
end

local boxColor = tocolor(255, 255, 0, 200)
local lineWidth = 2

-- Bottom face (z = minZ)
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[2][1], corners[2][2], corners[2][3], boxColor, lineWidth)
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[3][1], corners[3][2], corners[3][3], boxColor, lineWidth)
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[4][1], corners[4][2], corners[4][3], boxColor, lineWidth)
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[1][1], corners[1][2], corners[1][3], boxColor, lineWidth)

-- Top face (z = maxZ)
dxDrawLine3D(corners[5][1], corners[5][2], corners[5][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
dxDrawLine3D(corners[6][1], corners[6][2], corners[6][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
dxDrawLine3D(corners[7][1], corners[7][2], corners[7][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
dxDrawLine3D(corners[8][1], corners[8][2], corners[8][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)

-- Vertical edges connecting bottom to top
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
end
end
end
end

function doBasicElementRenders()
if not isElement(attachedToElement) then return end
if exports["editor_gui"]:sx_getOptionData("enableBox") then renderGridlines() end
if exports["editor_gui"]:sx_getOptionData("enableXYZlines") then drawXYZLines() end

drawObjectMoveLines()
end
addEventHandler ( "onClientRender", root, doBasicElementRenders )

Expand Down
5 changes: 5 additions & 0 deletions [editor]/editor_main/editor_main.edf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
<data name="collisions" type="selection:true,false" description="Object collisions" required="false" default="true" />
<data name="breakable" type="selection:true,false" description="Object breakablity" required="false" default="true" />
<data name="frozen" type="selection:false,true" description="Frozen" required="false" default="false" />
<data name="moveX" persistDefault="false" type="number" description="Move offset along the X axis" required="false" default="0" />
<data name="moveY" persistDefault="false" type="number" description="Move offset along the Y axis" required="false" default="0" />
<data name="moveZ" persistDefault="false" type="number" description="Move offset along the Z axis" required="false" default="0" />
<data name="moveSpeed" persistDefault="false" type="integer" description="Movement speed" required="false" default="1" />
<data name="moveDelay" persistDefault="false" type="integer" description="Delay before moving again in miliseconds" required="false" default="0" />
</element>
<element name="removeWorldObject" friendlyname="World object remover" icon="client/images/icons/wor.png" shortcut="removeworld" minver="1.3.0">
<data name="position" type="coord3d" description="XYZ position" default="0,0,0" />
Expand Down
77 changes: 72 additions & 5 deletions [editor]/editor_main/server/saveloadtest_server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,8 @@ function createElementAttributesForSaving(xmlNode, element)
-- Add an ID attribute first off
xmlNodeSetAttribute(elementNode, "id", getElementID(element))
-- Dump raw properties from the getters
for dataField in pairs(loadedEDF[edf.edfGetCreatorResource(element)].elements[getElementType(element)].data) do
local dataFields = loadedEDF[edf.edfGetCreatorResource(element)].elements[getElementType(element)].data
for dataField, dataDefinition in pairs(dataFields) do
if (dataField ~= "color1" and dataField ~= "color2" and dataField ~= "color3" and dataField ~= "color4") then
local value
if ( specialSyncers[dataField] ) then
Expand All @@ -673,7 +674,9 @@ function createElementAttributesForSaving(xmlNode, element)
value = edf.edfGetElementProperty(element, dataField)
end
if type(value) == "number" or type(value) == "string" then
xmlNodeSetAttribute(elementNode, dataField, value )
if dataDefinition.persistDefault == true or dataDefinition.default ~= value then
xmlNodeSetAttribute(elementNode, dataField, value )
end
end
end
end
Expand Down Expand Up @@ -706,7 +709,10 @@ function createElementAttributesForSaving(xmlNode, element)
elseif ( dataName == "rotX" or dataName == "rotY" or dataName == "rotZ") then
xmlNodeSetAttribute(elementNode, dataName, toAttribute(round(dataValue, 3)))
elseif ( dataName ~= "color1" and dataName ~= "color2" and dataName ~= "color3" and dataName ~= "color4" and ( not specialSyncers[dataName] or dataValue ~= getWorkingDimension() ) ) then
xmlNodeSetAttribute(elementNode, dataName, toAttribute(dataValue))
local dataDefinition = dataFields[dataName]
if not dataDefinition or dataDefinition.persistDefault == true or dataDefinition.default ~= dataValue then
xmlNodeSetAttribute(elementNode, dataName, toAttribute(dataValue))
end
end
end
-- Ensure that the element has a position set, else the map file can't load
Expand Down Expand Up @@ -1026,9 +1032,8 @@ function onResourceStartOrStop(startedResource)
if startEvent then
local resourceName = getResourceName(startedResource)
local useLODs = get(resourceName..".useLODs")

local objectsTable = getElementsByType("object", source)
if useLODs then
local objectsTable = getElementsByType("object", source)

for objectID = 1, #objectsTable do
local objectElement = objectsTable[objectID]
Expand All @@ -1052,11 +1057,73 @@ function onResourceStartOrStop(startedResource)
end
end
end

for i = 1, #objectsTable do
local objectElement = objectsTable[i]
local x, y, z = getElementPosition(objectElement)
local offsetX = tonumber(getElementData(objectElement, "moveX"))
local offsetY = tonumber(getElementData(objectElement, "moveY"))
local offsetZ = tonumber(getElementData(objectElement, "moveZ"))
if (offsetX and math.abs(offsetX) > 0) or (offsetY and math.abs(offsetY) > 0) or (offsetZ and math.abs(offsetZ) > 0) then
if not offsetX then offsetX = 0 end
if not offsetY then offsetY = 0 end
if not offsetZ then offsetZ = 0 end

local speed = tonumber(getElementData(objectElement, "moveSpeed")) or 1
local delay = tonumber(getElementData(objectElement, "moveDelay")) or 0
local time = getDistanceBetweenPoints3D(x,y,z,x + offsetX,y + offsetY,z + offsetZ) / speed * 1000

local currentPosX, currentPosY, currentPosZ = getElementPosition(objectElement)
local endPosX = currentPosX + offsetX
local endPosY = currentPosY + offsetY
local endPosZ = currentPosZ + offsetZ
local properties = {
moveTime = time,
delay = delay,
initialPosX = currentPosX,
initialPosY = currentPosY,
initialPosZ = currentPosZ,
endPosX = endPosX,
endPosY = endPosY,
endPosZ = endPosZ,
}
if delay > 0 then
setTimer(onObjectReachedInitialPosition, delay, 1, objectElement, properties)
else
onObjectReachedInitialPosition(objectElement, properties)
end
end
end
end
end
addEventHandler("onResourceStart", resourceRoot, onResourceStartOrStop)
addEventHandler("onResourceStop", resourceRoot, onResourceStartOrStop)

function onObjectReachedEndPosition(objectElement, properties)
if not isElement(objectElement) then return end
stopObject(objectElement)
local time = properties.moveTime
local delay = properties.delay
local initialPosX = properties.initialPosX
local initialPosY = properties.initialPosY
local initialPosZ = properties.initialPosZ
moveObject(objectElement, time, initialPosX, initialPosY, initialPosZ)
setTimer(onObjectReachedInitialPosition, time + delay, 1, objectElement, properties)
end

function onObjectReachedInitialPosition(objectElement, properties)
if not isElement(objectElement) then return end
stopObject(objectElement)
local time = properties.moveTime
if not time then return end
local delay = properties.delay
local endPosX = properties.endPosX
local endPosY = properties.endPosY
local endPosZ = properties.endPosZ
moveObject(objectElement, time, endPosX, endPosY, endPosZ)
setTimer(onObjectReachedEndPosition, time + delay, 1, objectElement, properties)
end

local function onPlayerResourceStart(resourceElement)
local mapResource = resourceElement == resource

Expand Down