File size: 7,648 Bytes
b6a38d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
local EDITOR = Platform.editor

local function SpotEntry(obj, idx)
	local name = idx >= 0 and obj:GetSpotName(idx) or ""
	if name == "" then
		return false
	end
	local offset = idx - obj:GetSpotBeginIndex(name)
	return offset == 0 and name or {name, offset}
end

DefineClass.AttachViaProp = {
	__parents = { "ComponentAttach" },
	properties = {
		{ category = "Attach-Via-Prop", id = "AttachList",    name = "Attach List",    editor = "prop_table",  default = "", no_edit = true },
		{ category = "Attach-Via-Prop", id = "AttachCounter", name = "Attach Counter", editor = "number", default = 0, dont_save = true, read_only = true },
	},
}

function AttachViaProp:SetAttachList(value)
	self.AttachList = value
	self:UpdatePropAttaches()
end

function AttachViaProp:ResolveSpotIdx(entry)
	local spot = entry.spot
	local offset
	if type(spot) == "table" then
		spot, offset = unpack_params(spot)
		assert(type(spot) == "string")
		assert(type(offset) == "number")
	end
	if type(spot) == "number" then
		-- support for older version
		entry.spot = SpotEntry(self, spot)
	elseif type(spot) == "string" then
		spot = self:HasSpot(spot) and self:GetSpotBeginIndex(spot)
	end
	return (spot or -1) + (offset or 0)
end

function AttachViaProp:UpdatePropAttaches()
	if self.AttachCounter > 0 then
		self:ForEachAttach(function(obj)
			if rawget(obj, "attach_via_prop") then
				DoneObject(obj)
			end
		end)
		self.AttachCounter = nil
	end
	local list = self.AttachList
	for i=#list,1,-1 do
		local entry = list[i]
		local spot = self:ResolveSpotIdx(entry)
		if not spot then
			table.remove(list, i)
		else
			local class = entry.class or ""
			local particles = entry.particles or ""
			local obj, err
			if particles ~= "" then
				obj = PlaceParticles(particles)
			else
				obj = PlaceObject(class)
			end
			if obj then
				rawset(obj, "attach_via_prop", true)
				if entry.offset then
					obj:SetAttachOffset(entry.offset)
				end
				if entry.axis then
					obj:SetAttachAxis(entry.axis)
				end
				if entry.angle then
					obj:SetAttachAngle(entry.angle)
				end
				err = self:Attach(obj, spot)
			end
			if not IsValid(obj) or obj:GetAttachSpot() ~= spot or err then
				StoreErrorSource(self, "Failed to attach via props!")
				DoneObject(obj)
			else
				self.AttachCounter = self.AttachCounter + 1
			end
		end
	end
	if not EDITOR then
		self.AttachList = nil
	end
end

----
if EDITOR then

local function SpotName(obj, idx)
	local name = obj:GetSpotName(idx)
	local anot = obj:GetSpotAnnotation(idx)
	return name .. (anot and (" (" .. anot .. ")") or "")
end

local function SpotNamesCombo(obj)
	local start_idx, end_idx = obj:GetAllSpots( obj:GetState() )
	local items = {}
	local names = {}
	for idx = start_idx, end_idx do
		items[#items + 1] = {value = SpotEntry(obj, idx), text = SpotName(obj, idx)}
	end
	table.sortby_field(items, "text")
	table.insert(items, 1, {value = false, text = ""})
	return items
end

if FirstLoad then
	l_used_entries = false
end

local function SmartAttachCombo()
	local items = {}
	local classes = ClassDescendantsList("ComponentAttach")
	local tbl = {"", " - Object"}
	for i = 1, #classes do
		local class = classes[i]
		tbl[1] = class
		local text = table.concat(tbl)
		items[#items + 1] = {value = { class, 1, text }, text = text}
	end
	local particles = ParticlesComboItems()
	local tbl = {"", " - Particle"}
	for i = 1, #particles do
		local particle = particles[i]
		tbl[1] = particle
		local text = table.concat(tbl)
		items[#items + 1] = {value = { particle, 2, text }, text = text}
	end
	table.sortby_field(items, "text")
	if l_used_entries then
		local idx = 1
		local tbl = {"> ", ""}
		for text, entry in sorted_pairs(l_used_entries) do
			tbl[2] = text
			table.insert(items, idx, {value = entry, text = table.concat(tbl)})
			idx = idx + 1
		end
		table.insert(items, idx, {value = "", text = ""})
	end
	table.insert(items, 1, {value = false, text = ""})
	return items
end

table.iappend(AttachViaProp.properties, {
	{ category = "Attach-Via-Prop", id = "AttachPreview",    name = "Attach List",     editor = "text", lines = 5, default = "",      dont_save = true, read_only = true, min = 10 },
	{ category = "Attach-Via-Prop", id = "AttachToSpot",     name = "Attach At",       editor = "combo",           default = false,   dont_save = true, items = SpotNamesCombo, min = 0, buttons = {{name = "Add", func = "ButtonAddAttach"}, {name = "Rem", func = "ButtonRemAttach"}, {name = "Rem All", func = "ButtonRemAllAttaches"}}},
	{ category = "Attach-Via-Prop", id = "AttachObject",     name = "Attach Object",   editor = "combo",           default = false,   dont_save = true, items = SmartAttachCombo },
	{ category = "Attach-Via-Prop", id = "AttachWithOffset", name = "Attach Offset ",  editor = "point",           default = point30, dont_save = true, scale = "m" },
	{ category = "Attach-Via-Prop", id = "AttachWithAxis",   name = "Attach Axis ",    editor = "point",           default = axis_z,  dont_save = true },
	{ category = "Attach-Via-Prop", id = "AttachWithAngle",  name = "Attach Angle ",   editor = "number",          default = 0,       dont_save = true, scale = "deg" },
})

function AttachViaProp:GetAttachListCombo()
	local items = {}
	local list = self.AttachList
	for i=#list,1,-1 do
		local entry = list[i]
		local spot = self:ResolveSpotIdx(entry)
		if not spot then
			table.remove(list, i)
		else
			local str = SpotName(self, spot) .. " -- " .. (entry.particles or entry.class or "?")
			if entry.offset then
				str = str .. " o" .. tostring(entry.offset)
			end
			if entry.axis then
				str = str .. " x" .. tostring(entry.axis)
			end
			if entry.angle then
				str = str .. " a" .. tostring(entry.angle)
			end
			items[#items + 1] = str
		end
	end
	table.sort(items)
	return items
end

function AttachViaProp:GetAttachPreview()
	local list = self:GetAttachListCombo()
	return table.concat(list, "\n")
end

function ButtonAddAttach(main_obj, object, prop_id)
	if type(object.AttachObject) ~= "table" then
		return
	end
	local oname, otype, otext = unpack_params(object.AttachObject)
	local class = otype == 1 and oname or ""
	local particles = otype == 2 and oname or ""
	if class == "" and particles == "" then
		return
	end
	l_used_entries = l_used_entries or {}
	l_used_entries[otext] = object.AttachObject
	local spot = object.AttachToSpot or nil
	local list = object.AttachList
	if #list == 0 then
		list = {}
		object.AttachList = list
	end
	local offset = object.AttachWithOffset
	if offset == point30 then
		offset = nil
	end
	local axis = object.AttachWithAxis
	if axis == axis_z then
		axis = nil
	end
	local angle = object.AttachWithAngle
	if angle == 0 then
		angle = nil
	end
	if class ~= "" then
		list[#list + 1] = {spot = spot, offset = offset, axis = axis, angle = angle, class = class, }
	end
	if particles ~= "" then
		list[#list + 1] = {spot = spot, offset = offset, axis = axis, angle = angle, particles = particles, }
	end
	object:UpdatePropAttaches()
end

function ButtonRemAllAttaches(main_obj, object, prop_id)
	if not object then
		return
	end
	object.AttachList = nil
	object:UpdatePropAttaches()
end
	
function ButtonRemAttach(main_obj, object, prop_id)
	if not object then
		return
	end
	local list = object:GetAttachListCombo()
	if #list == 0 then
		return
	end
	local entry, err = PropEditorWaitUserInput(main_obj, list[#list], "Select attach to remove", list)
	if not entry then
		assert(false, err)
		return
	end
	local idx = table.find(list, entry)
	if not idx then
		return
	end
	table.remove(object.AttachList, idx)
	if #object.AttachList == 0 then
		object.AttachList = nil
	end
	object:UpdatePropAttaches()
end

end -- EDITOR
----