autoverse-cli 0.28.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autoverse_cli-0.28.1.dist-info/METADATA +91 -0
- autoverse_cli-0.28.1.dist-info/RECORD +51 -0
- autoverse_cli-0.28.1.dist-info/WHEEL +5 -0
- autoverse_cli-0.28.1.dist-info/entry_points.txt +2 -0
- autoverse_cli-0.28.1.dist-info/licenses/LICENSE +33 -0
- autoverse_cli-0.28.1.dist-info/top_level.txt +1 -0
- avrs/__init__.py +0 -0
- avrs/app_version.py +24 -0
- avrs/argparse_help.py +30 -0
- avrs/avrs.py +183 -0
- avrs/can_tool.py +192 -0
- avrs/can_tool_util.py +190 -0
- avrs/cfg.py +78 -0
- avrs/launcher.py +256 -0
- avrs/launcher_util.py +203 -0
- avrs/race_cloud.py +506 -0
- avrs/race_cloud_bridge_can.py +100 -0
- avrs/race_cloud_cfg_util.py +310 -0
- avrs/race_cloud_fwd_api.py +49 -0
- avrs/race_cloud_util.py +384 -0
- avrs/requests/change_camera.py +24 -0
- avrs/requests/code_booz.py +69 -0
- avrs/requests/demo.py +19 -0
- avrs/requests/dump_sim_config.py +14 -0
- avrs/requests/environment.py +46 -0
- avrs/requests/fault_injection.py +186 -0
- avrs/requests/get_object_config.py +18 -0
- avrs/requests/get_web_viz_meta.py +11 -0
- avrs/requests/leaderboard.py +74 -0
- avrs/requests/list_sim_objects.py +26 -0
- avrs/requests/log_path.py +28 -0
- avrs/requests/misc.py +70 -0
- avrs/requests/move_to_landmark.py +16 -0
- avrs/requests/npc.py +289 -0
- avrs/requests/race_control.py +48 -0
- avrs/requests/request.py +61 -0
- avrs/requests/reset_to_track.py +21 -0
- avrs/requests/rest_request.py +45 -0
- avrs/requests/restart.py +12 -0
- avrs/requests/scenario_control.py +43 -0
- avrs/requests/spawn_object.py +44 -0
- avrs/requests/teleport.py +40 -0
- avrs/requests/toggle_hud.py +11 -0
- avrs/requests/vd.py +64 -0
- avrs/requests/vehicle_input.py +21 -0
- avrs/requests/vehicle_replay.py +454 -0
- avrs/shell_completion.py +121 -0
- avrs/simconfig.py +75 -0
- avrs/simconfig_util.py +170 -0
- avrs/tests.py +9 -0
- avrs/util.py +13 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from avrs.requests.request import AvrsApiRequest
|
|
2
|
+
|
|
3
|
+
class AvrsConfigureVehicleInputRequest(AvrsApiRequest):
|
|
4
|
+
def __init__(self, parser, cfg):
|
|
5
|
+
AvrsApiRequest.__init__(self, parser, cfg, 'ConfigureVehicleInput', 'Ego')
|
|
6
|
+
psr = parser.add_parser(
|
|
7
|
+
'configure-vehicle-input',
|
|
8
|
+
help='Allows different input modes to be set for a vehicle')
|
|
9
|
+
|
|
10
|
+
psr.add_argument(
|
|
11
|
+
'input_mode',
|
|
12
|
+
default='None',
|
|
13
|
+
choices=['None', 'Keyboard', 'WheelAndPedals', 'CAN'],
|
|
14
|
+
help='the type of input mode to set')
|
|
15
|
+
|
|
16
|
+
psr.set_defaults(func=self.send_request)
|
|
17
|
+
|
|
18
|
+
def get_request_body(self, args):
|
|
19
|
+
return {
|
|
20
|
+
"InputMode": args.input_mode
|
|
21
|
+
}
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from avrs.requests.request import AvrsApiRequest
|
|
3
|
+
from argparse import RawDescriptionHelpFormatter
|
|
4
|
+
from argparse import RawTextHelpFormatter
|
|
5
|
+
|
|
6
|
+
class AvrsVehicleReplayRequests():
|
|
7
|
+
def __init__(self, parser, cfg):
|
|
8
|
+
psr = parser.add_parser('vehicle-replay', help='utilty for recording and replaying vehicle motion')
|
|
9
|
+
sps = psr.add_subparsers(required= True, help='sub-command vehicle-replay')
|
|
10
|
+
SpawnReplayVehicle(sps, cfg)
|
|
11
|
+
StartVehicleReplayRecording(sps, cfg)
|
|
12
|
+
StopVehicleReplayRecording(sps, cfg)
|
|
13
|
+
DespawnReplayVehicle(sps, cfg)
|
|
14
|
+
SpawnVehicleReplayGroup(sps, cfg)
|
|
15
|
+
|
|
16
|
+
class SpawnReplayVehicle(AvrsApiRequest):
|
|
17
|
+
def __init__(self, parser, cfg):
|
|
18
|
+
AvrsApiRequest.__init__(self, parser, cfg, 'SpawnObject', '')
|
|
19
|
+
psr = parser.add_parser(
|
|
20
|
+
'spawn', help='spawn a vehicle intended to replay motion', formatter_class=RawTextHelpFormatter)
|
|
21
|
+
|
|
22
|
+
psr.add_argument(
|
|
23
|
+
'replay_file',
|
|
24
|
+
default='',
|
|
25
|
+
help='the replay file to use ("random" for a random profile)')
|
|
26
|
+
|
|
27
|
+
psr.add_argument(
|
|
28
|
+
'--name',
|
|
29
|
+
default='',
|
|
30
|
+
help='name of the replay vehicle to spawn')
|
|
31
|
+
|
|
32
|
+
psr.add_argument(
|
|
33
|
+
'--vehicle-type',
|
|
34
|
+
default='EAV24',
|
|
35
|
+
help='what type of vehicle to spawn for replay')
|
|
36
|
+
|
|
37
|
+
# psr.add_argument(
|
|
38
|
+
# '--position',
|
|
39
|
+
# choices=('relative', 'absolute'),
|
|
40
|
+
# default='absolute',
|
|
41
|
+
# help=NPC_SPAWN_POSITION_HELP)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# psr.add_argument(
|
|
45
|
+
# '--velocity-type',
|
|
46
|
+
# default='constant',
|
|
47
|
+
# help='the path the NPC follows is a constant velocity or speed')
|
|
48
|
+
|
|
49
|
+
# psr.add_argument(
|
|
50
|
+
# '--speed',
|
|
51
|
+
# type=float,
|
|
52
|
+
# default=20,
|
|
53
|
+
# help='the speed of the npc is m/s')
|
|
54
|
+
|
|
55
|
+
psr.add_argument(
|
|
56
|
+
'--rate',
|
|
57
|
+
type=float,
|
|
58
|
+
default=1.0,
|
|
59
|
+
help='the playback rate, 1.0 is normal')
|
|
60
|
+
|
|
61
|
+
psr.add_argument(
|
|
62
|
+
'--random-start',
|
|
63
|
+
action='store_true',
|
|
64
|
+
help='if set, will start at a random point in the replay')
|
|
65
|
+
|
|
66
|
+
psr.add_argument(
|
|
67
|
+
'--relative-dist',
|
|
68
|
+
type=float,
|
|
69
|
+
default=40.0,
|
|
70
|
+
help='the distance relative to ego to start the playback (-1 to start at playback start)')
|
|
71
|
+
|
|
72
|
+
psr.add_argument(
|
|
73
|
+
'--auto-start',
|
|
74
|
+
action='store_true',
|
|
75
|
+
help='if set, the npc will begin moving immediately')
|
|
76
|
+
|
|
77
|
+
psr.add_argument(
|
|
78
|
+
'--count',
|
|
79
|
+
type=int,
|
|
80
|
+
default=1,
|
|
81
|
+
help='the number of npcs to spawn (only works with automatic name)')
|
|
82
|
+
|
|
83
|
+
psr.add_argument(
|
|
84
|
+
'--group-name',
|
|
85
|
+
default="",
|
|
86
|
+
help="if specified, all vehicles will begin recording with the given group name")
|
|
87
|
+
|
|
88
|
+
psr.add_argument(
|
|
89
|
+
'--enable-front-lidar',
|
|
90
|
+
action='store_true',
|
|
91
|
+
help='if set, will enable the front lidar on the replay vehicle')
|
|
92
|
+
|
|
93
|
+
psr.add_argument(
|
|
94
|
+
'--enable-left-lidar',
|
|
95
|
+
action='store_true',
|
|
96
|
+
help='if set, will enable the left lidar on the replay vehicle')
|
|
97
|
+
|
|
98
|
+
psr.add_argument(
|
|
99
|
+
'--enable-right-lidar',
|
|
100
|
+
action='store_true',
|
|
101
|
+
help='if set, will enable the right lidar on the replay vehicle')
|
|
102
|
+
|
|
103
|
+
# psr.add_argument(
|
|
104
|
+
# '--enable-sensors',
|
|
105
|
+
# type=bool,
|
|
106
|
+
# default=False,
|
|
107
|
+
# help='whether to enable sensors on the replay vehicle')
|
|
108
|
+
|
|
109
|
+
psr.add_argument(
|
|
110
|
+
'--with-view-cameras',
|
|
111
|
+
action='store_true',
|
|
112
|
+
help='if set, will attach viewing cameras to the replay vehicle')
|
|
113
|
+
|
|
114
|
+
psr.set_defaults(func=self.send_request)
|
|
115
|
+
|
|
116
|
+
def send_request(self, args):
|
|
117
|
+
for i in range(args.count):
|
|
118
|
+
self.send_http_request(args)
|
|
119
|
+
|
|
120
|
+
def get_request_body(self, args):
|
|
121
|
+
|
|
122
|
+
replay_ipd = {
|
|
123
|
+
'bEnableRecording': False,
|
|
124
|
+
'bRecordOnPhysicsTick': False,
|
|
125
|
+
'recordMotionMinSpeedThreshold': 0.01,
|
|
126
|
+
'bEnableReplay': True,
|
|
127
|
+
'bApplyInitialConfig': True,
|
|
128
|
+
'initialConfig': {
|
|
129
|
+
'playRate': args.rate,
|
|
130
|
+
'profile': args.replay_file,
|
|
131
|
+
'bUseRandomProfile': args.replay_file == 'random',
|
|
132
|
+
'replayAction': 'start' if args.auto_start else '',
|
|
133
|
+
'bStartReplayAtRandomTime': args.random_start,
|
|
134
|
+
'relativeDistance': args.relative_dist,
|
|
135
|
+
'bRecordAllVehiclesAsGroup': args.group_name != "",
|
|
136
|
+
'RecordingGroupName': args.group_name
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
eav_init_pld = {
|
|
141
|
+
"bEnablePrimaryCan": False,
|
|
142
|
+
"bEnableSecondaryCan": False,
|
|
143
|
+
"bEnableBadeniaCan": False,
|
|
144
|
+
"bHudEnabled": False,
|
|
145
|
+
"bLidarEnabled": True,
|
|
146
|
+
"bCameraEnabled": False,
|
|
147
|
+
"bPublishInputs": False,
|
|
148
|
+
"bPublishGroundTruth": False
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
lidar_front_pld = {
|
|
152
|
+
'componentConfig': {
|
|
153
|
+
'instanceName': 'lidar_front'
|
|
154
|
+
},
|
|
155
|
+
'sensorDesc': {
|
|
156
|
+
'frame': 'lidar_front',
|
|
157
|
+
'leverarm': {
|
|
158
|
+
'translation': {
|
|
159
|
+
'x': 85,
|
|
160
|
+
'y': 0,
|
|
161
|
+
'z': 73
|
|
162
|
+
},
|
|
163
|
+
'translationUnits': 'centimeters',
|
|
164
|
+
'rotation': {
|
|
165
|
+
'pitch': 0,
|
|
166
|
+
'yaw': 0,
|
|
167
|
+
'roll': 0
|
|
168
|
+
},
|
|
169
|
+
'rotationUnits': 'degrees'
|
|
170
|
+
},
|
|
171
|
+
'dataStream': {
|
|
172
|
+
'streamName': 'lidar_front/points',
|
|
173
|
+
'rateHz': 15
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
lidar_left_pld = {
|
|
179
|
+
'componentConfig': {
|
|
180
|
+
'instanceName': 'lidar_left'
|
|
181
|
+
},
|
|
182
|
+
'sensorDesc': {
|
|
183
|
+
'frame': 'lidar_left',
|
|
184
|
+
'leverarm': {
|
|
185
|
+
'translation': {
|
|
186
|
+
'x': 15,
|
|
187
|
+
'y': -20,
|
|
188
|
+
'z': 82
|
|
189
|
+
},
|
|
190
|
+
'translationUnits': 'centimeters',
|
|
191
|
+
'rotation': {
|
|
192
|
+
'pitch': 0,
|
|
193
|
+
'yaw': 240,
|
|
194
|
+
'roll': 0
|
|
195
|
+
},
|
|
196
|
+
'rotationUnits': 'degrees'
|
|
197
|
+
},
|
|
198
|
+
'dataStream': {
|
|
199
|
+
'streamName': 'lidar_left/points',
|
|
200
|
+
'rateHz': 15
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
lidar_right_pld = {
|
|
206
|
+
'componentConfig': {
|
|
207
|
+
'instanceName': 'lidar_right'
|
|
208
|
+
},
|
|
209
|
+
'sensorDesc': {
|
|
210
|
+
'frame': 'lidar_right',
|
|
211
|
+
'leverarm': {
|
|
212
|
+
'translation': {
|
|
213
|
+
'x': 15,
|
|
214
|
+
'y': 20,
|
|
215
|
+
'z': 82
|
|
216
|
+
},
|
|
217
|
+
'translationUnits': 'centimeters',
|
|
218
|
+
'rotation': {
|
|
219
|
+
'pitch': 0,
|
|
220
|
+
'yaw': 120,
|
|
221
|
+
'roll': 0
|
|
222
|
+
},
|
|
223
|
+
'rotationUnits': 'degrees'
|
|
224
|
+
},
|
|
225
|
+
'dataStream': {
|
|
226
|
+
'streamName': 'lidar_right/points',
|
|
227
|
+
'rateHz': 15
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
world_label_pld = {
|
|
233
|
+
"typeName": "WorldTextComponent",
|
|
234
|
+
"bEnabled": True,
|
|
235
|
+
"body": {
|
|
236
|
+
"bUseObjectName": False,
|
|
237
|
+
"defaultString": "",
|
|
238
|
+
"fontSize": 34,
|
|
239
|
+
"offsetCm": {
|
|
240
|
+
"x": 0,
|
|
241
|
+
"y": 0,
|
|
242
|
+
"z": 150
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
plds = [
|
|
248
|
+
{
|
|
249
|
+
'typeName': 'WheeledVehicleReplayIpd',
|
|
250
|
+
'body': replay_ipd
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
'typeName': 'Eav24Initializer',
|
|
254
|
+
'body': eav_init_pld
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
'typeName': 'GenericLidarIpd',
|
|
258
|
+
'bEnabled': args.enable_front_lidar,
|
|
259
|
+
'body': lidar_front_pld
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
'typeName': 'GenericLidarIpd',
|
|
263
|
+
'bEnabled': args.enable_left_lidar,
|
|
264
|
+
'body': lidar_left_pld
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
'typeName': 'GenericLidarIpd',
|
|
268
|
+
'bEnabled': args.enable_right_lidar,
|
|
269
|
+
'body': lidar_right_pld
|
|
270
|
+
},
|
|
271
|
+
world_label_pld
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
if args.with_view_cameras:
|
|
275
|
+
plds.append(
|
|
276
|
+
{
|
|
277
|
+
'typeName': 'InitializerTemplates',
|
|
278
|
+
'body': {
|
|
279
|
+
'templates': [
|
|
280
|
+
{
|
|
281
|
+
'payloadType': 'SimViewTargetIpd',
|
|
282
|
+
'payloadSpec': 'DefaultCarCams'
|
|
283
|
+
}
|
|
284
|
+
]
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
# Create time based name if not specified
|
|
289
|
+
name = args.name
|
|
290
|
+
if name == '':
|
|
291
|
+
name = 'npc_{}'.format(random.randint(0, 100000))
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
'Name': name,
|
|
295
|
+
'Type': args.vehicle_type,
|
|
296
|
+
'Location': {},
|
|
297
|
+
'Rotation': {},
|
|
298
|
+
'Payloads': plds
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
class SpawnVehicleReplayGroup(AvrsApiRequest):
|
|
302
|
+
def __init__(self, parser, cfg):
|
|
303
|
+
AvrsApiRequest.__init__(self, parser, cfg, 'ConfigureVehicleReplay', '')
|
|
304
|
+
psr = parser.add_parser(
|
|
305
|
+
'spawn-group', help='spawn each replay vehicle for a given group', formatter_class=RawTextHelpFormatter)
|
|
306
|
+
|
|
307
|
+
psr.add_argument(
|
|
308
|
+
'group_name',
|
|
309
|
+
default="",
|
|
310
|
+
help="if specified, all vehicles will begin recording with the given group name")
|
|
311
|
+
|
|
312
|
+
psr.add_argument(
|
|
313
|
+
'--start-time',
|
|
314
|
+
type=float,
|
|
315
|
+
default=-1.0,
|
|
316
|
+
help="start the replay this many seconds in")
|
|
317
|
+
|
|
318
|
+
psr.add_argument(
|
|
319
|
+
'--rate',
|
|
320
|
+
type=float,
|
|
321
|
+
default=-1.0,
|
|
322
|
+
help="")
|
|
323
|
+
|
|
324
|
+
psr.set_defaults(func=self.send_request)
|
|
325
|
+
|
|
326
|
+
def get_request_body(self, args):
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
'PlayRate': args.rate,
|
|
330
|
+
'startTime': args.start_time,
|
|
331
|
+
'profile': '',
|
|
332
|
+
'replayAction': 'start',
|
|
333
|
+
#'teleportLocation': '',
|
|
334
|
+
'recordAction': '',
|
|
335
|
+
'bShouldOverrideRecordSingleLap': False,
|
|
336
|
+
'bRecordSingleLapOverride': False,
|
|
337
|
+
'bShouldOverrideRecordMinSpeedThresh': False,
|
|
338
|
+
'RecordMinSpeedThreshOverride': -1.0,
|
|
339
|
+
'recordFileName': '',
|
|
340
|
+
'recordRateHz': 100,
|
|
341
|
+
"RecordingGroupName": args.group_name
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
class StartVehicleReplayRecording(AvrsApiRequest):
|
|
345
|
+
def __init__(self, parser, cfg):
|
|
346
|
+
AvrsApiRequest.__init__(self, parser, cfg, 'ConfigureVehicleReplay', 'Ego')
|
|
347
|
+
psr = parser.add_parser(
|
|
348
|
+
'start-recording', help='begin recording vehicle motion', formatter_class=RawTextHelpFormatter)
|
|
349
|
+
|
|
350
|
+
psr.add_argument(
|
|
351
|
+
'out_file',
|
|
352
|
+
help='the file name to use for the saved recording')
|
|
353
|
+
|
|
354
|
+
psr.add_argument('--object-name', default='Ego', help='the name of the object to record')
|
|
355
|
+
|
|
356
|
+
psr.add_argument(
|
|
357
|
+
'--rate-hz',
|
|
358
|
+
type=float,
|
|
359
|
+
default=100.0,
|
|
360
|
+
help='the rate to record vehicle motion. high rates will produce large files')
|
|
361
|
+
|
|
362
|
+
psr.add_argument(
|
|
363
|
+
'--group-name',
|
|
364
|
+
default="",
|
|
365
|
+
help="if specified, all vehicles will begin recording with the given group name")
|
|
366
|
+
|
|
367
|
+
psr.add_argument(
|
|
368
|
+
'--not-single-lap',
|
|
369
|
+
action='store_true',
|
|
370
|
+
help='if set, recording will not try to capture exactly one lap and must be stopped by the user')
|
|
371
|
+
|
|
372
|
+
psr.set_defaults(func=self.send_request)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def get_request_body(self, args):
|
|
376
|
+
self.target_object_id = args.object_name
|
|
377
|
+
|
|
378
|
+
# we do not want to default to ego for group recordings
|
|
379
|
+
# because we want the replay manager to handle them
|
|
380
|
+
if args.group_name != "":
|
|
381
|
+
self.target_object_id = ""
|
|
382
|
+
# it doesnt make sense to do group recordings as single laps
|
|
383
|
+
args.not_single_lap = True
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
'PlayRate': -1.0,
|
|
387
|
+
'profile': '',
|
|
388
|
+
'replayAction': '',
|
|
389
|
+
#'teleportLocation': '',
|
|
390
|
+
'recordAction': 'start',
|
|
391
|
+
'bShouldOverrideRecordSingleLap': args.not_single_lap,
|
|
392
|
+
'bRecordSingleLapOverride': not args.not_single_lap,
|
|
393
|
+
'bShouldOverrideRecordMinSpeedThresh': args.group_name != "", # no min speed for groups
|
|
394
|
+
'RecordMinSpeedThreshOverride': -1.0,
|
|
395
|
+
'recordFileName': args.out_file,
|
|
396
|
+
'recordRateHz': args.rate_hz,
|
|
397
|
+
"RecordingGroupName": args.group_name
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
class StopVehicleReplayRecording(AvrsApiRequest):
|
|
401
|
+
def __init__(self, parser, cfg):
|
|
402
|
+
AvrsApiRequest.__init__(self, parser, cfg, 'ConfigureVehicleReplay', 'Ego')
|
|
403
|
+
psr = parser.add_parser(
|
|
404
|
+
'stop-recording', help='begin recording vehicle motion', formatter_class=RawTextHelpFormatter)
|
|
405
|
+
|
|
406
|
+
psr.add_argument('--object-name', default='Ego', help='the name of the object to record')
|
|
407
|
+
|
|
408
|
+
psr.add_argument(
|
|
409
|
+
'--group-name',
|
|
410
|
+
default="",
|
|
411
|
+
help="if specified, all vehicles will begin recording with the given group name")
|
|
412
|
+
|
|
413
|
+
psr.set_defaults(func=self.send_request)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def get_request_body(self, args):
|
|
417
|
+
self.target_object_id = args.object_name
|
|
418
|
+
|
|
419
|
+
# we do not want to default to ego for group recordings
|
|
420
|
+
# because we want the replay manager to handle them
|
|
421
|
+
if args.group_name != "":
|
|
422
|
+
self.target_object_id = ""
|
|
423
|
+
return {
|
|
424
|
+
'recordAction': 'stop',
|
|
425
|
+
"RecordingGroupName": args.group_name
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
class DespawnReplayVehicle(AvrsApiRequest):
|
|
429
|
+
def __init__(self, parser, cfg):
|
|
430
|
+
AvrsApiRequest.__init__(self, parser, cfg, 'DespawnObject', 'Ego')
|
|
431
|
+
psr = parser.add_parser(
|
|
432
|
+
'despawn', help='despawn a replay vehicle or all replay vehicles', formatter_class=RawTextHelpFormatter)
|
|
433
|
+
|
|
434
|
+
psr.add_argument(
|
|
435
|
+
'--name',
|
|
436
|
+
default='',
|
|
437
|
+
help='name of the replay vehicle to despawn')
|
|
438
|
+
|
|
439
|
+
psr.add_argument(
|
|
440
|
+
'--all',
|
|
441
|
+
action='store_true',
|
|
442
|
+
help='if set, will despawn all replay vehicles')
|
|
443
|
+
|
|
444
|
+
psr.set_defaults(func=self.send_request)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def get_request_body(self, args):
|
|
448
|
+
self.target_object_id = args.name
|
|
449
|
+
tags = ["Npc"] if args.all else []
|
|
450
|
+
|
|
451
|
+
return {
|
|
452
|
+
'tags': tags,
|
|
453
|
+
'bMatchAnyTag': True
|
|
454
|
+
}
|
avrs/shell_completion.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import subprocess
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def get_shell_name():
|
|
7
|
+
"""Detect the current shell from SHELL environment variable or parent process."""
|
|
8
|
+
shell = os.environ.get('SHELL', '')
|
|
9
|
+
if shell:
|
|
10
|
+
return os.path.basename(shell)
|
|
11
|
+
|
|
12
|
+
# Fallback: try to get parent shell
|
|
13
|
+
try:
|
|
14
|
+
parent_pid = os.getppid()
|
|
15
|
+
with open(f'/proc/{parent_pid}/comm', 'r') as f:
|
|
16
|
+
return f.read().strip()
|
|
17
|
+
except:
|
|
18
|
+
return 'bash'
|
|
19
|
+
|
|
20
|
+
def get_shell_config_file():
|
|
21
|
+
"""Get the config file path for the detected shell."""
|
|
22
|
+
shell = get_shell_name()
|
|
23
|
+
home = str(Path.home())
|
|
24
|
+
|
|
25
|
+
if 'zsh' in shell:
|
|
26
|
+
return os.path.join(home, '.zshrc')
|
|
27
|
+
elif 'fish' in shell:
|
|
28
|
+
return os.path.join(home, '.config/fish/config.fish')
|
|
29
|
+
elif 'tcsh' in shell:
|
|
30
|
+
return os.path.join(home, '.tcshrc')
|
|
31
|
+
else: # bash and others
|
|
32
|
+
return os.path.join(home, '.bashrc')
|
|
33
|
+
|
|
34
|
+
def get_completion_command():
|
|
35
|
+
"""Get the shell-specific completion registration command."""
|
|
36
|
+
shell = get_shell_name()
|
|
37
|
+
|
|
38
|
+
# Try to use register-python-argcomplete if available, fall back to register-python-argcomplete3
|
|
39
|
+
# This makes it compatible with both pip-installed and system-package versions
|
|
40
|
+
register_cmd = "register-python-argcomplete"
|
|
41
|
+
|
|
42
|
+
if 'zsh' in shell:
|
|
43
|
+
return f'eval "$({register_cmd} --shell zsh avrs 2>/dev/null || {register_cmd}3 --shell zsh avrs)"'
|
|
44
|
+
elif 'fish' in shell:
|
|
45
|
+
return f'{register_cmd} --shell fish avrs 2>/dev/null | source || {register_cmd}3 --shell fish avrs | source'
|
|
46
|
+
elif 'tcsh' in shell:
|
|
47
|
+
return f'eval "$({register_cmd} --shell tcsh avrs 2>/dev/null || {register_cmd}3 --shell tcsh avrs)"'
|
|
48
|
+
else: # bash
|
|
49
|
+
return f'eval "$({register_cmd} avrs 2>/dev/null || {register_cmd}3 avrs)"'
|
|
50
|
+
|
|
51
|
+
def install_completion():
|
|
52
|
+
"""Install shell completion for the avrs CLI."""
|
|
53
|
+
shell = get_shell_name()
|
|
54
|
+
config_file = get_shell_config_file()
|
|
55
|
+
completion_command = get_completion_command()
|
|
56
|
+
|
|
57
|
+
print(f"Installing shell completion for {shell}...")
|
|
58
|
+
|
|
59
|
+
# Check if completion already installed
|
|
60
|
+
if os.path.exists(config_file):
|
|
61
|
+
with open(config_file, 'r') as f:
|
|
62
|
+
content = f.read()
|
|
63
|
+
if 'register-python-argcomplete' in content and 'avrs' in content:
|
|
64
|
+
print(f"✓ Completion already installed in {config_file}")
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
# Ensure config file exists
|
|
68
|
+
Path(config_file).parent.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
|
|
70
|
+
# Append completion command
|
|
71
|
+
try:
|
|
72
|
+
with open(config_file, 'a') as f:
|
|
73
|
+
f.write('\n\n# avrs CLI completion\n')
|
|
74
|
+
f.write(completion_command + '\n')
|
|
75
|
+
print(f"✓ Completion installed successfully!")
|
|
76
|
+
print(f"✓ Added to {config_file}")
|
|
77
|
+
print(f"\nTo activate completion in current shell, run:")
|
|
78
|
+
print(f" source {config_file}")
|
|
79
|
+
return True
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print(f"✗ Error installing completion: {e}")
|
|
82
|
+
print(f"\nManually add this line to {config_file}:")
|
|
83
|
+
print(f" {completion_command}")
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
def uninstall_completion():
|
|
87
|
+
"""Remove shell completion for the avrs CLI."""
|
|
88
|
+
shell = get_shell_name()
|
|
89
|
+
config_file = get_shell_config_file()
|
|
90
|
+
|
|
91
|
+
print(f"Uninstalling shell completion from {config_file}...")
|
|
92
|
+
|
|
93
|
+
if not os.path.exists(config_file):
|
|
94
|
+
print("Config file not found.")
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
with open(config_file, 'r') as f:
|
|
99
|
+
lines = f.readlines()
|
|
100
|
+
|
|
101
|
+
# Filter out avrs completion lines
|
|
102
|
+
new_lines = [
|
|
103
|
+
line for line in lines
|
|
104
|
+
if 'register-python-argcomplete' not in line or 'avrs' not in line
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
# Also remove the comment line if it's there
|
|
108
|
+
filtered_lines = []
|
|
109
|
+
for i, line in enumerate(new_lines):
|
|
110
|
+
if line.strip() == '# avrs CLI completion':
|
|
111
|
+
continue
|
|
112
|
+
filtered_lines.append(line)
|
|
113
|
+
|
|
114
|
+
with open(config_file, 'w') as f:
|
|
115
|
+
f.writelines(filtered_lines)
|
|
116
|
+
|
|
117
|
+
print(f"✓ Completion uninstalled successfully!")
|
|
118
|
+
return True
|
|
119
|
+
except Exception as e:
|
|
120
|
+
print(f"✗ Error uninstalling completion: {e}")
|
|
121
|
+
return False
|
avrs/simconfig.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import stat
|
|
3
|
+
import json
|
|
4
|
+
import http.client
|
|
5
|
+
from avrs.cfg import *
|
|
6
|
+
from avrs.launcher_util import *
|
|
7
|
+
from avrs.simconfig_util import *
|
|
8
|
+
|
|
9
|
+
class AvrsSimConfig:
|
|
10
|
+
def __init__(self, parent_parser, cfg):
|
|
11
|
+
self.cfg = cfg
|
|
12
|
+
sim_config_parser = parent_parser.add_parser(
|
|
13
|
+
'sim-config',
|
|
14
|
+
help='utilities for easily configuring the simulator\n\n')
|
|
15
|
+
|
|
16
|
+
sps = sim_config_parser.add_subparsers(required=True, help='sim-config options')
|
|
17
|
+
|
|
18
|
+
compare_parser = sps.add_parser(
|
|
19
|
+
'compare-configs',
|
|
20
|
+
help='compare two sets of configuration files')
|
|
21
|
+
compare_parser.add_argument(
|
|
22
|
+
'a',
|
|
23
|
+
help='the path to the first set of config files')
|
|
24
|
+
compare_parser.add_argument(
|
|
25
|
+
'b',
|
|
26
|
+
help='the path to the second set of config files')
|
|
27
|
+
compare_parser.set_defaults(func=self.compare_configs)
|
|
28
|
+
|
|
29
|
+
apply_preset_parser = sps.add_parser(
|
|
30
|
+
'apply-preset',
|
|
31
|
+
help='apply a preset configuration for a certain use-case')
|
|
32
|
+
apply_preset_parser.add_argument(
|
|
33
|
+
'preset_name',
|
|
34
|
+
choices=['default', 'lightweight', 'a2rl'],
|
|
35
|
+
help='the name of the preset to apply')
|
|
36
|
+
apply_preset_parser.add_argument(
|
|
37
|
+
'--sim-path',
|
|
38
|
+
default='',
|
|
39
|
+
help='''
|
|
40
|
+
the path to the simulator installation having the intended config to modify, or the
|
|
41
|
+
index of a known installation. if there is only one known installation, it will be used as
|
|
42
|
+
the target
|
|
43
|
+
''')
|
|
44
|
+
apply_preset_parser.set_defaults(func=self.apply_preset)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def apply_preset(self, args):
|
|
48
|
+
sim_path = args.sim_path
|
|
49
|
+
if sim_path == '':
|
|
50
|
+
if 'installs' in self.cfg and len(self.cfg['installs']) > 0:
|
|
51
|
+
if len(self.cfg['installs']) > 1:
|
|
52
|
+
print('multiple known installs. specify path or index')
|
|
53
|
+
for i in range(len(self.cfg['installs'])):
|
|
54
|
+
print('({}) {}'.format(i, self.cfg['installs'][i]))
|
|
55
|
+
return
|
|
56
|
+
else:
|
|
57
|
+
sim_path = self.cfg['installs'][0]
|
|
58
|
+
else:
|
|
59
|
+
print('sim_path not specified and no known existing installations')
|
|
60
|
+
return
|
|
61
|
+
try:
|
|
62
|
+
sim_path_index = int(sim_path)
|
|
63
|
+
if 'installs' in self.cfg and len(self.cfg['installs']) > sim_path_index:
|
|
64
|
+
sim_path = self.cfg['installs'][sim_path_index]
|
|
65
|
+
except Exception as e:
|
|
66
|
+
pass
|
|
67
|
+
if not is_installed_sim(sim_path):
|
|
68
|
+
print('{} is not a valid sim installation'.format(sim_path))
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
print('applying preset {} to sim install at {}'.format(args.preset_name, sim_path))
|
|
72
|
+
apply_simconfig_preset(get_sim_saved_dir(sim_path), args.preset_name)
|
|
73
|
+
|
|
74
|
+
def compare_configs(self, args):
|
|
75
|
+
compare_simconfig_defaults(args.a, args.b)
|