-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathz_autorun_[trackassembly].txt
315 lines (290 loc) · 17.6 KB
/
z_autorun_[trackassembly].txt
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
--[[
* The purpose of this Lua file is to add your track pack pieces to the
* track assembly tool, so they can appear in the tool selection menu.
* Why the name starts with /z/ you may ask. When Gmod loads the game
* it goes trough all the Lua addons alphabetically.
* That means your file name ( The file you are reading right now )
* must be greater alphabetically than /trackasmlib/, so the API of the
* module can be loaded before you can use it like seen below.
]]--
-- Local reference to the module.
local asmlib = trackasmlib; if(not asmlib) then -- Module present
ErrorNoHaltWithStack("TOOL: Track assembly tool module fail!\n"); return end
--[[
* This is your addon name. It is mandatory and it must be string.
* It is used by TA in order to classify the content you are creating
* It must NOT be an empty string nil or any other type regarding
* The value will be automatically pattern converted to a index prefix
]]
local myAddon = "Test's track pack"
-- Log messages identifier. Leave DSV here or change it if you like
local mySource = "DSV"
--[[
* Change this if you want to use different in-game type
* You can also use multiple types myType1, myType2,
* myType3, ... myType/n when your addon contains
* multiple model packs.
]]--
local myType = myAddon -- The type your addon resides in the tool with
-- This is used for addon relation prefix. Fingers away from it
local myPrefix = myAddon:gsub("[^%w]","_") -- Addon prefix
-- This is the script path. It tells TA who wants to add these models
-- Do not touch this also, it is used for debugging
local myScript = tostring(debug.getinfo(1).source or "N/A")
myScript = "@"..myScript:gsub("^%W+", ""):gsub("\\","/")
mySource = tostring(mySource or ""):gsub("^%W+", "")
mySource = (asmlib.IsBlank(mySource) and "DSV" or mySource)
-- Store a reference to disable symbol
local gsMissDB = asmlib.GetOpVar("MISS_NOSQL")
local gsDirDSV = asmlib.GetOpVar("DIRPATH_DSV")
local gsToolPF = asmlib.GetOpVar("TOOLNAME_PU")
local gsSymOff = asmlib.GetOpVar("OPSYM_DISABLE")
-- This is the path to your DSV
local myDsv = asmlib.GetLibraryPath(gsDirDSV, myPrefix, gsToolPF.."PIECES")
--[[
* This flag is used when the track pieces list needs to be processed.
* It generally represents the locking file persistence flag. It is
* bound to finding a "PIECES" DSV external database for the prefix
* of your addon. You can use it for boolean value deciding whenever
* or not to run certain events. For example you can stop exporting
* your local database every time Gmod loads, but then the user will
* skip the available updates of your addon until he/she deletes the DSVs.
]]--
local myFlag = file.Exists(myDsv, "DATA")
--[[
* This function defines what happens when there is an error present
* Usually you can tell Gmod that you want it to generate an error
* and throw the message to the log also. In this case you will not
* have to change the function name in lots of places
* when you need it to do something else.
--]]
local function ThrowError(vMesg)
local sMesg = (myScript.." > ("..myAddon.."): "..tostring(vMesg)) -- Convert to string
if(asmlib) then asmlib.LogInstance(sMesg, mySource) end -- Update the tool logs
ErrorNoHaltWithStack(sMesg.."\n") -- Produce an error without breaking the stack
end
--[[
* This logic statement is needed for reporting the error
* in the console if the process fails.
*
@ bSuccess = trackasmlib.SynchronizeDSV(sTable, tData, bRepl, sPref, sDelim)
* sTable > The table you want to sync
* tData > A data table like the one described above
* bRepl > If set to /true/, makes the API replace the repeating models with
these of your addon. This is nice when you are constantly updating your track packs
If set to /false/ keeps the current model in the
database and ignores yours if they are the same file.
* sPref > An export file custom prefix. For synchronizing it must be related to your addon
* sDelim > The delimiter used by the server/client ( default is a tab symbol )
*
@ bSuccess = trackasmlib.TranslateDSV(sTable, sPref, sDelim)
* sTable > The table you want to translate to Lua script
* sPref > An export file custom prefix. For synchronizing it must be related to your addon
* sDelim > The delimiter used by the server/client ( default is a tab symbol )
]]--
local function DoSynchronize(sName, tData, bRepl)
local sRep = asmlib.GetReport(myPrefix, sName) -- Generate report if error is present
if(not asmlib.IsEmpty(tData)) then -- Something to be processed. Do stuff when the table is not empty
asmlib.LogInstance("Synchronization START "..sRep, mySource) -- Signal start synchronization
if(not asmlib.SynchronizeDSV(sName, tData, bRepl, myPrefix)) then -- Attempt to synchronize
ThrowError("Failed to synchronize content") -- Raise error when fails to sync tracks data
else -- Successful. You are saving me from all the work for manually generating these
asmlib.LogInstance("Translation START "..sRep, mySource) -- Signal start translation
if(not asmlib.TranslateDSV(sName, myPrefix)) then -- Attempt to translate the DSV to Lua source
ThrowError("Failed to translate content") end -- Raise error when fails
asmlib.LogInstance("Translation OK "..sRep, mySource) -- Translation is successful
end -- Now we have Lua inserts and DSV. Otherwise sent empty table and print status in logs
else asmlib.LogInstance("Synchronization EMPTY "..sRep, mySource) end -- Nothing to be done
end
--[[
* Register the addon to the auto-load prefix list when the
* PIECES file is missing. The auto-load list is located in
* (/garrysmod/data/trackassembly/set/trackasmlib_dsv.txt)
* a.k.a the DATA folder of Garry's mod.
*
* @bSuccess = trackasmlib.RegisterDSV(sProg, sPref, sDelim)
* sProg > The program which registered the DSV
* sPref > The external data prefix to be added ( default instance prefix )
* sDelim > The delimiter to be used for processing ( default tab )
* bSkip > Skip addition for the DSV prefix if exists ( default `false` )
]]--
local function DoRegister(bSkip)
local sRep = asmlib.GetReport(myPrefix, bSkip) -- Generate report if error is present
asmlib.LogInstance("Registration START "..sRep, mySource)
if(bSkip) then -- Your DSV must be registered only once when loading for the first time
asmlib.LogInstance("Registration SKIP "..sRep, mySource)
else -- If the locking file is not located that means this is the first run of your script
if(not asmlib.RegisterDSV(myScript, myPrefix)) then -- Register the DSV prefix and check for error
ThrowError("Failed to register content") -- Throw the error if fails
end -- Third argument is the delimiter. The default tab is used
asmlib.LogInstance("Registration OK "..sRep, mySource)
end
end
--[[
* This logic statement is needed for reporting the error in the console if the
* process fails.
*
@ bSuccess = trackasmlib.ExportCategory(nInd, tData, sPref)
* nInd > The index equal indent format to be stored with ( generally = 3 )
* tData > The category functional definition you want to use to divide your stuff with
* sPref > An export file custom prefix. For synchronizing
* it must be related to your addon ( default is instance prefix )
]]--
local function DoCategory(tCatg)
local sRep = asmlib.GetReport(myPrefix, bSkip) -- Generate report if error is present
asmlib.LogInstance("Category export START "..sRep, mySource)
if(CLIENT) then -- Category handling is client side only
if(not asmlib.IsEmpty(tCatg)) then
if(not asmlib.ExportCategory(3, tCatg, myPrefix)) then
ThrowError("Failed to synchronize category")
end; asmlib.LogInstance("Category export OK "..sRep, mySource)
else asmlib.LogInstance("Category export SKIP "..sRep, mySource) end
else asmlib.LogInstance("Category export SERVER "..sRep, mySource) end
end
-- Tell TA what custom script we just called don't touch it
asmlib.LogInstance(">>> "..myScript.." ("..tostring(myFlag).."): {"..myAddon..", "..myPrefix.."}", mySource)
-- Register the addon to the workshop ID list
asmlib.WorkshopID(myAddon, "287012681")
-- Register the addon to the plugable DSV list
local bS, vO = pcall(DoRegister, myFlag)
if(not bS) then ThrowError("Registration error: "..vO) end
--[[
* This is used if you want to make internal categories for your addon
* You must make a function as a string under the hash of your addon
* The function must take only one argument and that is the model
* For every sub-category of your track pieces, you must return a table
* with that much elements or return a /nil/ value to add the piece to
* the root of your branch. You can also return a second value if you
* want to override the track piece name. If you need to use categories
* for multiple track types, just put their hashes in the table below
* and make every track point to its dedicated category handler.
]]--
local myCategory = {
[myType] = {Txt = [[
function(m)
local r = m:gsub("models/props_phx/construct/",""):gsub("_","/")
local s = r:find("/"); r = s and r:sub(1,s-1) or nil
local n = nil
if(r) then
if(r == "metal" ) then n = "My metal plate" end
if(r == "windows") then n = "My glass plate" end
end
r = r and r:gsub("^%l", string.upper) or nil
p = r and {r} or nil
return p, n
end
]]}
}
-- Register the addon category to the plugable DSV list
local bS, vO = pcall(DoCategory, myCategory)
if(not bS) then ThrowError("Category error: "..vO) end
--[[
* Create a table and populate it as shown below
* In the square brackets goes your MODEL,
* and then for every active point, you must have one array of
* strings, where the elements match the following data settings.
* You can use the disable event /#/ to make TA auto-fill
* the value provided and you can also add multiple track types myType[1-n].
* If you need to use piece origin/angle with model attachment, you must use
* the attachment extraction event /!/. The model attachment format is
* /!<attachment_name>/ and it depends what attachment name you gave it when you
* created the model. If you need TA to extract the origin/angle from an attachment named
* /test/ for example, you just need to put the string /!test/ in the origin/angle column for that model.
* {MODEL, TYPE, NAME, LINEID, POINT, ORIGIN, ANGLE, CLASS}
* MODEL > This string contains the path to your /*.mdl/ file. It is mandatory and
* taken in pairs with LINEID, it forms the unique identifier of every record.
* When used in /DSV/ mode ( like seen below ) it is used as a hash index.
* TYPE > This string is the name of the type your stuff will reside in the panel.
* Disabling this, makes it use the value of the /DEFAULT_TYPE/ variable.
* If it is empty uses the string /TYPE/, so make sure you fill this.
* NAME > This is the name of your track piece. Put /#/ here to be auto-generated from
* the model ( from the last slash to the file extension ).
* LINEID > This is the ID of the point that can be selected for building. They must be
* sequential and mandatory. If provided, the ID must the same as the row index under
* a given model key. Disabling this, makes it use the index of the current line.
* Use that to swap the active points around by only moving the desired row up or down.
* For the example table definition below, the line ID in the database will be the same.
* POINT > This is the location vector that TA searches and selects the related ORIGIN for.
* An empty string is treated as taking the ORIGIN when assuming player traces can hit the origin
* Disabling via /#/ makes it take the ORIGIN. Used to disable a point but keep original data
* You can also fill it with attachment event /!/ followed by your attachment name.
* ORIGIN > This is the origin relative to which the next track piece position is calculated
* An empty string is treated as {0,0,0}. Disabling via /#/ also makes it use {0,0,0}
* You can also fill it with attachment event /!/ followed by your attachment name. It's mandatory
* ANGLE > This is the angle relative to which the forward and up vectors are calculated.
* An empty string is treated as {0,0,0}. Disabling via /#/ also makes it use {0,0,0}
* You can also fill it with attachment event /!/ followed by your attachment name. It's mandatory
* CLASS > This string is populated up when your entity class is not /prop_physics/ but something else
* used by ents.Create of the gmod ents API library. Keep this empty if your stuff is a normal prop.
* Disabling via /#/ makes it take the NULL value. In this case the model is spawned as a prop
]]--
local myPieces = {
["models/props_phx/construct/metal_plate1x2.mdl"] = { -- Here goes the model of your pack
{myType , gsSymOff, 1, "","0,-47.455105,1.482965","0,-90,0",""}, -- The first point parameter
{myType , gsSymOff, 2, "","0, 47.455105,1.482965","0, 90,0",""} -- The second point parameter
},
["models/props_phx/construct/windows/window1x2.mdl"] = {
{myType , gsSymOff, gsSymOff, "","0,-23.73248,1.482965","0,-90,0",""},
{myType , gsSymOff, gsSymOff, "","0, 71.17773,1.482965","0, 90,0",""}
}
}
-- Register the addon PIECES to the plugable DSV list
local bS, vO = pcall(DoSynchronize, "PIECES", myPieces, true)
if(not bS) then ThrowError("PIECES error: "..vO) end
--[[
* Create a table and populate it as shown below
* In the square brackets goes your MODELBASE,
* and then for every active point, you must have one array of
* strings and numbers, where the elements match the following data settings.
* {MODELBASE, MODELADD, ENTCLASS, LINEID, POSOFF, ANGOFF, MOVETYPE, PHYSINIT, DRSHADOW, PHMOTION, PHYSLEEP, SETSOLID}
* MODELBASE > This string contains the path to your base /*.mdl/ file the additions will be attached to.
* It is mandatory and taken in pairs with LINEID, it forms the unique identifier of every record.
* When used in /DSV/ mode ( like seen below ) it is used as a hash index.
* MODELADD > This is the /*.mdl/ path of the addition entity. It is mandatory and cannot be disabled.
* ENTCLASS > This is the class of the addition entity. When disabled or missing it defaults to a normal prop.
* LINEID > This is the ID of the point that can be selected for building. They must be
* sequential and mandatory. If provided, the ID must the same as the row index under
* a given model key. Disabling this, makes it use the index of the current line.
* Use that to swap the active points around by only moving the desired row up or down.
* For the example table definition below, the line ID in the database will be the same.
* POSOFF > This is the local position vector offset that TA uses to place the addition relative to MODELBASE.
* A NULL, empty, disabled or not available string is treated as taking {0,0,0}.
* ANGOFF > This is the local angle offset that TA uses to place the addition.
* A NULL, empty, disabled or not available string is treated as taking {0,0,0}.
* MOVETYPE > This internally calls /Entity:SetMoveType/ if the database parameter is zero or greater.
* PHYSINIT > This internally calls /Entity:PhysicsInit/ if the database parameter is zero or greater.
* DRSHADOW > This internally calls /Entity:DrawShadow/ if the database parameter is not zero.
* The call evaluates to /true/ for positive numbers and /false/ for negative.
* When the parameter is equal to zero skips the call of /Entity:DrawShadow/
* PHMOTION > This internally calls /PhysObj:EnableMotion/ if the database parameter is not zero on the validated physics object.
* The call evaluates to /true/ for positive numbers and /false/ for negative.
* When the parameter is equal to zero skips the call of /Entity:EnableMotion/
* PHYSLEEP > This internally calls /PhysObj:Sleep/ if the database parameter is grater than zero on the validated physics object.
* When the parameter is equal or less than zero skips the call of /Entity:Sleep/
* SETSOLID > This internally calls /Entity:SetSolid/ if the database parameter is zero or greater.
]]--
local myAdditions = {}
-- Register the addon ADDITIONS to the plugable DSV list
local bS, vO = pcall(DoSynchronize, "ADDITIONS", myAdditions, true)
if(not bS) then ThrowError("ADDITIONS error: "..vO) end
--[[
* Create a table and populate it as shown below
* In the square brackets goes your TYPE,
* and then for every active point, you must have one array of
* strings and numbers, where the elements match the following data settings.
* {TYPE, LINEID, NAME}
* TYPE > This is the category under your physical properties are stored internally.
* It is mandatory and taken in pairs with LINEID, it forms the unique identifier of every record.
* When used in /DSV/ mode ( like seen below ) it is used as a hash index.
* LINEID > This is the ID of the point that can be selected for building. They must be
* sequential and mandatory. If provided, the ID must the same as the row index under
* a given model key. Disabling this, makes it use the index of the current line.
* Use that to swap the active points around by only moving the desired row up or down.
* For the example table definition below, the line ID in the database will be the same.
* NAME > This stores the name of the physical property. It must an actual physical property.
]]--
local myPhysproperties = {}
-- Register the addon PHYSPROPERTIES to the plugable DSV list
local bS, vO = pcall(DoSynchronize, "PHYSPROPERTIES", myPhysproperties, true)
if(not bS) then ThrowError("PHYSPROPERTIES error: "..vO) end
asmlib.LogInstance("<<< "..myScript, mySource)