diff options
author | Dan Lake | 2011-11-23 16:11:17 -0800 |
---|---|---|
committer | Dan Lake | 2011-11-23 16:11:17 -0800 |
commit | 5485e3da460ae954acb225f1b7988b576226fb3a (patch) | |
tree | 7755fd14d85264ea8deac2a1d73e3b8eeb627673 /OpenSim/Tools/pCampBot | |
parent | Line endings (diff) | |
parent | Print out what behaviours are active when pCampBot starts up (diff) | |
download | opensim-SC-5485e3da460ae954acb225f1b7988b576226fb3a.zip opensim-SC-5485e3da460ae954acb225f1b7988b576226fb3a.tar.gz opensim-SC-5485e3da460ae954acb225f1b7988b576226fb3a.tar.bz2 opensim-SC-5485e3da460ae954acb225f1b7988b576226fb3a.tar.xz |
Merge branch 'master' of git://opensimulator.org/git/opensim
Diffstat (limited to 'OpenSim/Tools/pCampBot')
-rw-r--r-- | OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs | 2 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | 2 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs | 75 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/Bot.cs | 35 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/BotManager.cs | 100 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs | 9 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/pCampBot.cs | 2 |
7 files changed, 201 insertions, 24 deletions
diff --git a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs index 7084ab4..0a6d5d2 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs | |||
@@ -41,6 +41,8 @@ namespace pCampBot | |||
41 | /// </remarks> | 41 | /// </remarks> |
42 | public class GrabbingBehaviour : IBehaviour | 42 | public class GrabbingBehaviour : IBehaviour |
43 | { | 43 | { |
44 | public string Name { get { return "Grabbing"; } } | ||
45 | |||
44 | public void Action(Bot bot) | 46 | public void Action(Bot bot) |
45 | { | 47 | { |
46 | Dictionary<UUID, Primitive> objects = bot.Objects; | 48 | Dictionary<UUID, Primitive> objects = bot.Objects; |
diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs index 3ce08bf..f782bb5 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | |||
@@ -42,6 +42,8 @@ namespace pCampBot | |||
42 | /// </remarks> | 42 | /// </remarks> |
43 | public class PhysicsBehaviour : IBehaviour | 43 | public class PhysicsBehaviour : IBehaviour |
44 | { | 44 | { |
45 | public string Name { get { return "Physics"; } } | ||
46 | |||
45 | private string[] talkarray; | 47 | private string[] talkarray; |
46 | 48 | ||
47 | public PhysicsBehaviour() | 49 | public PhysicsBehaviour() |
diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs new file mode 100644 index 0000000..fc2ed2c --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using OpenMetaverse; | ||
34 | using pCampBot.Interfaces; | ||
35 | |||
36 | namespace pCampBot | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// Teleport to a random region on the grid. | ||
40 | /// </summary> | ||
41 | public class TeleportBehaviour : IBehaviour | ||
42 | { | ||
43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
44 | |||
45 | public string Name { get { return "Teleport"; } } | ||
46 | |||
47 | public void Action(Bot bot) | ||
48 | { | ||
49 | Random rng = bot.Manager.Rng; | ||
50 | GridRegion[] knownRegions; | ||
51 | |||
52 | lock (bot.Manager.RegionsKnown) | ||
53 | { | ||
54 | if (bot.Manager.RegionsKnown.Count == 0) | ||
55 | { | ||
56 | m_log.DebugFormat( | ||
57 | "[TELEPORT BEHAVIOUR]: Ignoring teleport action for {0} since no regions are known yet", bot.Name); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | knownRegions = bot.Manager.RegionsKnown.Values.ToArray(); | ||
62 | } | ||
63 | |||
64 | Simulator sourceRegion = bot.Client.Network.CurrentSim; | ||
65 | GridRegion destRegion = knownRegions[rng.Next(knownRegions.Length)]; | ||
66 | Vector3 destPosition = new Vector3(rng.Next(255), rng.Next(255), 50); | ||
67 | |||
68 | m_log.DebugFormat( | ||
69 | "[TELEPORT BEHAVIOUR]: Teleporting {0} from {1} {2} to {3} {4}", | ||
70 | bot.Name, sourceRegion.Name, bot.Client.Self.SimPosition, destRegion.Name, destPosition); | ||
71 | |||
72 | bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition); | ||
73 | } | ||
74 | } | ||
75 | } \ No newline at end of file | ||
diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 7f941a4..7a73e3f 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs | |||
@@ -49,8 +49,15 @@ namespace pCampBot | |||
49 | 49 | ||
50 | public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events | 50 | public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events |
51 | 51 | ||
52 | public BotManager BotManager { get; private set; } | 52 | /// <summary> |
53 | private IConfig startupConfig; // bot config, passed from BotManager | 53 | /// Bot manager. |
54 | /// </summary> | ||
55 | public BotManager Manager { get; private set; } | ||
56 | |||
57 | /// <summary> | ||
58 | /// Bot config, passed from BotManager. | ||
59 | /// </summary> | ||
60 | private IConfig startupConfig; | ||
54 | 61 | ||
55 | /// <summary> | 62 | /// <summary> |
56 | /// Behaviours implemented by this bot. | 63 | /// Behaviours implemented by this bot. |
@@ -132,7 +139,7 @@ namespace pCampBot | |||
132 | Password = password; | 139 | Password = password; |
133 | LoginUri = loginUri; | 140 | LoginUri = loginUri; |
134 | 141 | ||
135 | BotManager = bm; | 142 | Manager = bm; |
136 | startupConfig = bm.Config; | 143 | startupConfig = bm.Config; |
137 | readconfig(); | 144 | readconfig(); |
138 | 145 | ||
@@ -218,7 +225,19 @@ namespace pCampBot | |||
218 | { | 225 | { |
219 | MakeDefaultAppearance(wear); | 226 | MakeDefaultAppearance(wear); |
220 | } | 227 | } |
228 | |||
221 | Client.Self.Jump(true); | 229 | Client.Self.Jump(true); |
230 | |||
231 | // Extract nearby region information. | ||
232 | Client.Grid.GridRegion += Manager.Grid_GridRegion; | ||
233 | uint xUint, yUint; | ||
234 | Utils.LongToUInts(Client.Network.CurrentSim.Handle, out xUint, out yUint); | ||
235 | ushort minX, minY, maxX, maxY; | ||
236 | minX = (ushort)Math.Min(0, xUint - 5); | ||
237 | minY = (ushort)Math.Min(0, yUint - 5); | ||
238 | maxX = (ushort)(xUint + 5); | ||
239 | maxY = (ushort)(yUint + 5); | ||
240 | Client.Grid.RequestMapBlocks(GridLayerType.Terrain, minX, minY, maxX, maxY, false); | ||
222 | } | 241 | } |
223 | else | 242 | else |
224 | { | 243 | { |
@@ -472,13 +491,13 @@ namespace pCampBot | |||
472 | 491 | ||
473 | private void GetTexture(UUID textureID) | 492 | private void GetTexture(UUID textureID) |
474 | { | 493 | { |
475 | lock (BotManager.AssetsReceived) | 494 | lock (Manager.AssetsReceived) |
476 | { | 495 | { |
477 | // Don't request assets more than once. | 496 | // Don't request assets more than once. |
478 | if (BotManager.AssetsReceived.ContainsKey(textureID)) | 497 | if (Manager.AssetsReceived.ContainsKey(textureID)) |
479 | return; | 498 | return; |
480 | 499 | ||
481 | BotManager.AssetsReceived[textureID] = false; | 500 | Manager.AssetsReceived[textureID] = false; |
482 | Client.Assets.RequestImage(textureID, ImageType.Normal, Asset_TextureCallback_Texture); | 501 | Client.Assets.RequestImage(textureID, ImageType.Normal, Asset_TextureCallback_Texture); |
483 | } | 502 | } |
484 | } | 503 | } |
@@ -490,8 +509,8 @@ namespace pCampBot | |||
490 | 509 | ||
491 | public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset) | 510 | public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset) |
492 | { | 511 | { |
493 | lock (BotManager.AssetsReceived) | 512 | lock (Manager.AssetsReceived) |
494 | BotManager.AssetsReceived[asset.AssetID] = true; | 513 | Manager.AssetsReceived[asset.AssetID] = true; |
495 | 514 | ||
496 | // if (wear == "save") | 515 | // if (wear == "save") |
497 | // { | 516 | // { |
diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index f5dd5e0..29cb1ba 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using System.Threading; | 32 | using System.Threading; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
@@ -48,9 +49,24 @@ namespace pCampBot | |||
48 | { | 49 | { |
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | 51 | ||
52 | /// <summary> | ||
53 | /// Command console | ||
54 | /// </summary> | ||
51 | protected CommandConsole m_console; | 55 | protected CommandConsole m_console; |
56 | |||
57 | /// <summary> | ||
58 | /// Created bots, whether active or inactive. | ||
59 | /// </summary> | ||
52 | protected List<Bot> m_lBot; | 60 | protected List<Bot> m_lBot; |
53 | protected Random somthing = new Random(Environment.TickCount); | 61 | |
62 | /// <summary> | ||
63 | /// Random number generator. | ||
64 | /// </summary> | ||
65 | public Random Rng { get; private set; } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Overall configuration. | ||
69 | /// </summary> | ||
54 | public IConfig Config { get; private set; } | 70 | public IConfig Config { get; private set; } |
55 | 71 | ||
56 | /// <summary> | 72 | /// <summary> |
@@ -59,11 +75,18 @@ namespace pCampBot | |||
59 | public Dictionary<UUID, bool> AssetsReceived { get; private set; } | 75 | public Dictionary<UUID, bool> AssetsReceived { get; private set; } |
60 | 76 | ||
61 | /// <summary> | 77 | /// <summary> |
78 | /// The regions that we know about. | ||
79 | /// </summary> | ||
80 | public Dictionary<ulong, GridRegion> RegionsKnown { get; private set; } | ||
81 | |||
82 | /// <summary> | ||
62 | /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data | 83 | /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data |
63 | /// </summary> | 84 | /// </summary> |
64 | public BotManager() | 85 | public BotManager() |
65 | { | 86 | { |
87 | Rng = new Random(Environment.TickCount); | ||
66 | AssetsReceived = new Dictionary<UUID, bool>(); | 88 | AssetsReceived = new Dictionary<UUID, bool>(); |
89 | RegionsKnown = new Dictionary<ulong, GridRegion>(); | ||
67 | 90 | ||
68 | m_console = CreateConsole(); | 91 | m_console = CreateConsole(); |
69 | MainConsole.Instance = m_console; | 92 | MainConsole.Instance = m_console; |
@@ -93,8 +116,13 @@ namespace pCampBot | |||
93 | "Shutdown bots and exit", | 116 | "Shutdown bots and exit", |
94 | HandleShutdown); | 117 | HandleShutdown); |
95 | 118 | ||
96 | m_console.Commands.AddCommand("bot", false, "show status", | 119 | m_console.Commands.AddCommand("bot", false, "show regions", |
97 | "show status", | 120 | "show regions", |
121 | "Show regions known to bots", | ||
122 | HandleShowRegions); | ||
123 | |||
124 | m_console.Commands.AddCommand("bot", false, "show bots", | ||
125 | "show bots", | ||
98 | "Shows the status of all bots", | 126 | "Shows the status of all bots", |
99 | HandleShowStatus); | 127 | HandleShowStatus); |
100 | 128 | ||
@@ -123,19 +151,26 @@ namespace pCampBot | |||
123 | Array.ForEach<string>( | 151 | Array.ForEach<string>( |
124 | cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); | 152 | cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); |
125 | 153 | ||
154 | List<IBehaviour> behaviours = new List<IBehaviour>(); | ||
155 | |||
156 | // Hard-coded for now | ||
157 | if (behaviourSwitches.Contains("p")) | ||
158 | behaviours.Add(new PhysicsBehaviour()); | ||
159 | |||
160 | if (behaviourSwitches.Contains("g")) | ||
161 | behaviours.Add(new GrabbingBehaviour()); | ||
162 | |||
163 | if (behaviourSwitches.Contains("t")) | ||
164 | behaviours.Add(new TeleportBehaviour()); | ||
165 | |||
166 | MainConsole.Instance.OutputFormat( | ||
167 | "[BOT MANAGER]: Bots configured for behaviours {0}", | ||
168 | string.Join(",", behaviours.ConvertAll<string>(b => b.Name).ToArray())); | ||
169 | |||
126 | for (int i = 0; i < botcount; i++) | 170 | for (int i = 0; i < botcount; i++) |
127 | { | 171 | { |
128 | string lastName = string.Format("{0}_{1}", lastNameStem, i); | 172 | string lastName = string.Format("{0}_{1}", lastNameStem, i); |
129 | 173 | ||
130 | List<IBehaviour> behaviours = new List<IBehaviour>(); | ||
131 | |||
132 | // Hard-coded for now | ||
133 | if (behaviourSwitches.Contains("p")) | ||
134 | behaviours.Add(new PhysicsBehaviour()); | ||
135 | |||
136 | if (behaviourSwitches.Contains("g")) | ||
137 | behaviours.Add(new GrabbingBehaviour()); | ||
138 | |||
139 | StartBot(this, behaviours, firstName, lastName, password, loginUri); | 174 | StartBot(this, behaviours, firstName, lastName, password, loginUri); |
140 | } | 175 | } |
141 | } | 176 | } |
@@ -240,17 +275,33 @@ namespace pCampBot | |||
240 | }); | 275 | }); |
241 | } | 276 | } |
242 | 277 | ||
278 | private void HandleShowRegions(string module, string[] cmd) | ||
279 | { | ||
280 | string outputFormat = "{0,-30} {1, -20} {2, -5} {3, -5}"; | ||
281 | MainConsole.Instance.OutputFormat(outputFormat, "Name", "Handle", "X", "Y"); | ||
282 | |||
283 | lock (RegionsKnown) | ||
284 | { | ||
285 | foreach (GridRegion region in RegionsKnown.Values) | ||
286 | { | ||
287 | MainConsole.Instance.OutputFormat( | ||
288 | outputFormat, region.Name, region.RegionHandle, region.X, region.Y); | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
243 | private void HandleShowStatus(string module, string[] cmd) | 293 | private void HandleShowStatus(string module, string[] cmd) |
244 | { | 294 | { |
245 | string outputFormat = "{0,-30} {1,-14}"; | 295 | string outputFormat = "{0,-30} {1, -30} {2,-14}"; |
246 | MainConsole.Instance.OutputFormat(outputFormat, "Name", "Status"); | 296 | MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status"); |
247 | 297 | ||
248 | lock (m_lBot) | 298 | lock (m_lBot) |
249 | { | 299 | { |
250 | foreach (Bot pb in m_lBot) | 300 | foreach (Bot pb in m_lBot) |
251 | { | 301 | { |
252 | MainConsole.Instance.OutputFormat( | 302 | MainConsole.Instance.OutputFormat( |
253 | outputFormat, pb.Name, (pb.IsConnected ? "Connected" : "Disconnected")); | 303 | outputFormat, |
304 | pb.Name, pb.Client.Network.CurrentSim.Name, pb.IsConnected ? "Connected" : "Disconnected"); | ||
254 | } | 305 | } |
255 | } | 306 | } |
256 | } | 307 | } |
@@ -274,5 +325,24 @@ namespace pCampBot | |||
274 | // if (newbots > 0) | 325 | // if (newbots > 0) |
275 | // addbots(newbots); | 326 | // addbots(newbots); |
276 | // } | 327 | // } |
328 | |||
329 | internal void Grid_GridRegion(object o, GridRegionEventArgs args) | ||
330 | { | ||
331 | lock (RegionsKnown) | ||
332 | { | ||
333 | GridRegion newRegion = args.Region; | ||
334 | |||
335 | if (RegionsKnown.ContainsKey(newRegion.RegionHandle)) | ||
336 | { | ||
337 | return; | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | m_log.DebugFormat( | ||
342 | "[BOT MANAGER]: Adding {0} {1} to known regions", newRegion.Name, newRegion.RegionHandle); | ||
343 | RegionsKnown[newRegion.RegionHandle] = newRegion; | ||
344 | } | ||
345 | } | ||
346 | } | ||
277 | } | 347 | } |
278 | } | 348 | } |
diff --git a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs index d4ae0f0..912216f 100644 --- a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs | |||
@@ -31,6 +31,15 @@ namespace pCampBot.Interfaces | |||
31 | { | 31 | { |
32 | public interface IBehaviour | 32 | public interface IBehaviour |
33 | { | 33 | { |
34 | /// <summary> | ||
35 | /// Name of this behaviour. | ||
36 | /// </summary> | ||
37 | string Name { get; } | ||
38 | |||
39 | /// <summary> | ||
40 | /// Action to take when this behaviour is invoked. | ||
41 | /// </summary> | ||
42 | /// <param name="bot"></param> | ||
34 | void Action(Bot bot); | 43 | void Action(Bot bot); |
35 | } | 44 | } |
36 | } \ No newline at end of file | 45 | } \ No newline at end of file |
diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index 4d3b06d..e7288d5 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs | |||
@@ -111,7 +111,7 @@ namespace pCampBot | |||
111 | " -firstname first name for the bots\n" + | 111 | " -firstname first name for the bots\n" + |
112 | " -lastname lastname for the bots. Each lastname will have _<bot-number> appended, e.g. Ima Bot_0\n" + | 112 | " -lastname lastname for the bots. Each lastname will have _<bot-number> appended, e.g. Ima Bot_0\n" + |
113 | " -password password for the bots\n" + | 113 | " -password password for the bots\n" + |
114 | " -b, behaviours behaviours for bots. Current options p (physics), g (grab). Comma separated, e.g. p,g. Default is p", | 114 | " -b, behaviours behaviours for bots. Current options p (physics), g (grab), t (teleport). Comma separated, e.g. p,g. Default is p", |
115 | " -wear set appearance folder to load from (default: no)\n" + | 115 | " -wear set appearance folder to load from (default: no)\n" + |
116 | " -h, -help show this message" | 116 | " -h, -help show this message" |
117 | ); | 117 | ); |