Skip to content

Commit 25ba6cd

Browse files
authored
Map Editor: A feature for simple moving objects (#704)
* Add aclrequest for loadstring * Remove linebreak from meta.xml runcode * Ability to make objects move in the editor * Fix merge conflict * fix linter errors * Fix editor movement bouding box animation * Editor fix non-centered bounding box animation * Linter fix editor draw object lines
1 parent 4423fa5 commit 25ba6cd

6 files changed

Lines changed: 317 additions & 6 deletions

File tree

[editor]/edf/edf.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,17 @@ function edfAddElementNodeData(node, resource)
11981198
local validModels = xmlNodeGetAttribute(subnode, "validModels")
11991199
dataFields[dname].validModels = validModels and split(validModels, ",") or dataFields[dname].validModels
12001200

1201+
--[[ Set to false to only save the value if it is not the default value,
1202+
useful to prevent map files from growing too much,
1203+
especially for properties that are not always required (default: true)
1204+
]]
1205+
local persistDefault = xmlNodeGetAttribute(subnode, "persistDefault")
1206+
if persistDefault then
1207+
dataFields[dname].persistDefault = convert.boolean(persistDefault)
1208+
else
1209+
dataFields[dname].persistDefault = dataFields[dname].persistDefault or true
1210+
end
1211+
12011212
-- update the required flag (default: true)
12021213
local requiredAttribute = xmlNodeGetAttribute(subnode,"required")
12031214
if requiredAttribute then

[editor]/edf/properties.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,46 @@ propertyGetters = {
3737
else
3838
return "false"
3939
end
40+
end,
41+
moveSpeed = function(element)
42+
local time = getElementData(element, "moveSpeed")
43+
if time == nil or time == false then
44+
return 1
45+
else
46+
return time
47+
end
48+
end,
49+
moveDelay = function(element)
50+
local delay = getElementData(element, "moveDelay")
51+
if delay == nil or delay == false then
52+
return 0
53+
else
54+
return delay
55+
end
56+
end,
57+
moveX = function(element)
58+
local offsetX = getElementData(element, "moveX")
59+
if offsetX == nil or offsetX == false then
60+
return 0
61+
else
62+
return offsetX
63+
end
64+
end,
65+
moveY = function(element)
66+
local offsetY = getElementData(element, "moveY")
67+
if offsetY == nil or offsetY == false then
68+
return 0
69+
else
70+
return offsetY
71+
end
72+
end,
73+
moveZ = function(element)
74+
local offsetZ = getElementData(element, "moveZ")
75+
if offsetZ == nil or offsetZ == false then
76+
return 0
77+
else
78+
return offsetZ
79+
end
4080
end
4181
},
4282
ped = {

[editor]/edf/properties_client.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,46 @@ propertyGetters = {
1717
else
1818
return "false"
1919
end
20+
end,
21+
moveSpeed = function(element)
22+
local time = getElementData(element, "moveSpeed")
23+
if time == nil or time == false then
24+
return 1
25+
else
26+
return time
27+
end
28+
end,
29+
moveDelay = function(element)
30+
local delay = getElementData(element, "moveDelay")
31+
if delay == nil or delay == false then
32+
return 0
33+
else
34+
return delay
35+
end
36+
end,
37+
moveX = function(element)
38+
local offsetX = getElementData(element, "moveX")
39+
if offsetX == nil or offsetX == false then
40+
return 0
41+
else
42+
return offsetX
43+
end
44+
end,
45+
moveY = function(element)
46+
local offsetY = getElementData(element, "moveY")
47+
if offsetY == nil or offsetY == false then
48+
return 0
49+
else
50+
return offsetY
51+
end
52+
end,
53+
moveZ = function(element)
54+
local offsetZ = getElementData(element, "moveZ")
55+
if offsetZ == nil or offsetZ == false then
56+
return 0
57+
else
58+
return offsetZ
59+
end
2060
end
2161
},
2262
ped = {

[editor]/editor_main/client/gridlines.lua

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,159 @@ function drawXYZLines()
125125
drawLine({x,y,z},{zx,zy,zz},tocolor(0,0,200,200),thickness)
126126
end
127127

128+
--[[
129+
Draws the where the object will be moved to.
130+
]]
131+
function drawObjectMoveLines()
132+
if not isElement(attachedToElement) then return end
133+
if getElementType(attachedToElement) ~= "object" then return end
134+
if getElementDimension(attachedToElement) ~= getElementDimension(localPlayer) then return end
135+
local x,y,z = edf.edfGetElementPosition(attachedToElement)
136+
if not x then return end
137+
138+
local offsetX = edf.edfGetElementProperty(attachedToElement, "moveX")
139+
local offsetY = edf.edfGetElementProperty(attachedToElement, "moveY")
140+
local offsetZ = edf.edfGetElementProperty(attachedToElement, "moveZ")
141+
142+
if offsetX and math.abs(offsetX) > 0 or offsetY and math.abs(offsetY) > 0 or offsetZ and math.abs(offsetZ) > 0 then
143+
if not offsetX then offsetX = 0 end
144+
if not offsetY then offsetY = 0 end
145+
if not offsetZ then offsetZ = 0 end
146+
147+
local speed = tonumber(edf.edfGetElementProperty(attachedToElement, "moveSpeed"))
148+
if not speed then speed = 1 end
149+
local delay = tonumber(edf.edfGetElementProperty(attachedToElement, "moveDelay"))
150+
if not delay then delay = 0 end
151+
local time = getDistanceBetweenPoints3D(x,y,z,x + offsetX,y + offsetY,z + offsetZ) / speed * 1000
152+
local lineStartPos = {x,y,z}
153+
local lineEndPos = {x + offsetX,y + offsetY,z + offsetZ}
154+
local timeNow = getTickCount()
155+
156+
local fullCycle = 2 * time + 2 * delay
157+
local cyclePos = timeNow % fullCycle
158+
local progress
159+
if cyclePos < delay then
160+
-- Delay at 0
161+
progress = 0
162+
elseif cyclePos < delay + time then
163+
-- Forward: 0 to 1 over 'time' milliseconds
164+
progress = (cyclePos - delay) / time
165+
elseif cyclePos < delay + time + delay then
166+
-- Delay at 1
167+
progress = 1
168+
else
169+
-- Backward: 1 to 0 over 'time' milliseconds
170+
progress = 1 - (cyclePos - delay - time - delay) / time
171+
end
172+
173+
local movementAnimationOffset = {
174+
(lineEndPos[1] - lineStartPos[1]) * progress,
175+
(lineEndPos[2] - lineStartPos[2]) * progress,
176+
(lineEndPos[3] - lineStartPos[3]) * progress
177+
}
178+
179+
180+
local minX,minY,minZ,maxX,maxY,maxZ = edf.edfGetElementBoundingBox ( attachedToElement )
181+
if not minX then
182+
local radius = edf.edfGetElementRadius ( attachedToElement )
183+
if radius then
184+
minX,minY,minZ,maxX,maxY,maxZ = -radius,-radius,-radius,radius,radius,radius
185+
end
186+
end
187+
188+
if minX and minY and minZ and maxX and maxY and maxZ then
189+
local halfCenterX = (minX + maxX) * 0.25
190+
local halfCenterY = (minY + maxY) * 0.25
191+
local halfCenterZ = (minZ + maxZ) * 0.25
192+
193+
--subtracting half center
194+
minX = minX - halfCenterX
195+
minY = minY - halfCenterY
196+
minZ = minZ - halfCenterZ
197+
maxX = maxX - halfCenterX
198+
maxY = maxY - halfCenterY
199+
maxZ = maxZ - halfCenterZ
200+
201+
-- Define the 8 corners in relative coordinates
202+
local relativeCorners = {
203+
{minX, minY, minZ}, -- 1: min corner
204+
{maxX, minY, minZ}, -- 2
205+
{maxX, maxY, minZ}, -- 3
206+
{minX, maxY, minZ}, -- 4
207+
{minX, minY, maxZ}, -- 5
208+
{maxX, minY, maxZ}, -- 6
209+
{maxX, maxY, maxZ}, -- 7
210+
{minX, maxY, maxZ} -- 8: max corner
211+
}
212+
213+
-- Draw the bounding box moving to the destination position
214+
do
215+
local corners = {}
216+
for i, relCorner in ipairs(relativeCorners) do
217+
local worldX, worldY, worldZ = getPositionFromElementAtOffset(attachedToElement, relCorner[1], relCorner[2], relCorner[3])
218+
corners[i] = {worldX + movementAnimationOffset[1], worldY + movementAnimationOffset[2], worldZ + movementAnimationOffset[3]}
219+
end
220+
221+
local boxColor = tocolor(255, 255, 255, 100)
222+
local lineWidth = 2
223+
224+
-- Bottom face (z = minZ)
225+
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[2][1], corners[2][2], corners[2][3], boxColor, lineWidth)
226+
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[3][1], corners[3][2], corners[3][3], boxColor, lineWidth)
227+
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[4][1], corners[4][2], corners[4][3], boxColor, lineWidth)
228+
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[1][1], corners[1][2], corners[1][3], boxColor, lineWidth)
229+
230+
-- Top face (z = maxZ)
231+
dxDrawLine3D(corners[5][1], corners[5][2], corners[5][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
232+
dxDrawLine3D(corners[6][1], corners[6][2], corners[6][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
233+
dxDrawLine3D(corners[7][1], corners[7][2], corners[7][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
234+
dxDrawLine3D(corners[8][1], corners[8][2], corners[8][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)
235+
236+
-- Vertical edges connecting bottom to top
237+
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)
238+
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
239+
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
240+
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
241+
end
242+
243+
-- Draw the bounding box at the destination position
244+
do
245+
local corners = {}
246+
for i, relCorner in ipairs(relativeCorners) do
247+
local worldX, worldY, worldZ = getPositionFromElementAtOffset(attachedToElement, relCorner[1], relCorner[2], relCorner[3])
248+
corners[i] = {worldX + offsetX, worldY + offsetY, worldZ + offsetZ}
249+
end
250+
251+
local boxColor = tocolor(255, 255, 0, 200)
252+
local lineWidth = 2
253+
254+
-- Bottom face (z = minZ)
255+
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[2][1], corners[2][2], corners[2][3], boxColor, lineWidth)
256+
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[3][1], corners[3][2], corners[3][3], boxColor, lineWidth)
257+
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[4][1], corners[4][2], corners[4][3], boxColor, lineWidth)
258+
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[1][1], corners[1][2], corners[1][3], boxColor, lineWidth)
259+
260+
-- Top face (z = maxZ)
261+
dxDrawLine3D(corners[5][1], corners[5][2], corners[5][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
262+
dxDrawLine3D(corners[6][1], corners[6][2], corners[6][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
263+
dxDrawLine3D(corners[7][1], corners[7][2], corners[7][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
264+
dxDrawLine3D(corners[8][1], corners[8][2], corners[8][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)
265+
266+
-- Vertical edges connecting bottom to top
267+
dxDrawLine3D(corners[1][1], corners[1][2], corners[1][3], corners[5][1], corners[5][2], corners[5][3], boxColor, lineWidth)
268+
dxDrawLine3D(corners[2][1], corners[2][2], corners[2][3], corners[6][1], corners[6][2], corners[6][3], boxColor, lineWidth)
269+
dxDrawLine3D(corners[3][1], corners[3][2], corners[3][3], corners[7][1], corners[7][2], corners[7][3], boxColor, lineWidth)
270+
dxDrawLine3D(corners[4][1], corners[4][2], corners[4][3], corners[8][1], corners[8][2], corners[8][3], boxColor, lineWidth)
271+
end
272+
end
273+
end
274+
end
275+
128276
function doBasicElementRenders()
129277
if not isElement(attachedToElement) then return end
130278
if exports["editor_gui"]:sx_getOptionData("enableBox") then renderGridlines() end
131279
if exports["editor_gui"]:sx_getOptionData("enableXYZlines") then drawXYZLines() end
132-
280+
drawObjectMoveLines()
133281
end
134282
addEventHandler ( "onClientRender", root, doBasicElementRenders )
135283

[editor]/editor_main/editor_main.edf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
<data name="collisions" type="selection:true,false" description="Object collisions" required="false" default="true" />
1212
<data name="breakable" type="selection:true,false" description="Object breakablity" required="false" default="true" />
1313
<data name="frozen" type="selection:false,true" description="Frozen" required="false" default="false" />
14+
<data name="moveX" persistDefault="false" type="number" description="Move offset along the X axis" required="false" default="0" />
15+
<data name="moveY" persistDefault="false" type="number" description="Move offset along the Y axis" required="false" default="0" />
16+
<data name="moveZ" persistDefault="false" type="number" description="Move offset along the Z axis" required="false" default="0" />
17+
<data name="moveSpeed" persistDefault="false" type="integer" description="Movement speed" required="false" default="1" />
18+
<data name="moveDelay" persistDefault="false" type="integer" description="Delay before moving again in miliseconds" required="false" default="0" />
1419
</element>
1520
<element name="removeWorldObject" friendlyname="World object remover" icon="client/images/icons/wor.png" shortcut="removeworld" minver="1.3.0">
1621
<data name="position" type="coord3d" description="XYZ position" default="0,0,0" />

0 commit comments

Comments
 (0)