1 /** default console commands */ 2 3 module re.ng.diag.default_commands; 4 5 import std.range; 6 import std.array; 7 import std.algorithm; 8 import std.string; 9 import std.conv; 10 11 import re.core; 12 import re.ecs; 13 14 debug static class DefaultCommands { 15 alias log = Core.log; 16 alias scenes = Core.scenes; 17 alias dbg = Core.debugger; 18 alias con = dbg.console; 19 20 static void c_help(string[] args) { 21 auto sb = appender!string(); 22 sb ~= "available commmands:\n"; 23 auto command_names = con.commands.keys.sort(); 24 foreach (command_name; command_names) { 25 auto command = con.commands[command_name]; 26 sb ~= format("%s - %s\n", command.name, command.help); 27 } 28 log.info(sb.data); 29 } 30 31 static void c_entities(string[] args) { 32 auto sb = appender!string(); 33 sb ~= "entity list:\n"; 34 foreach (i, scene; scenes) { 35 // print scene header 36 sb ~= format("▶ Scene[%d]: %s ¬\n", i, typeid(scene).name); 37 foreach (entity; scene.ecs.entities) { 38 // get list of components 39 auto component_types = entity.get_all_components().map!(x => x.classinfo.name); 40 // sb ~= format(" ▷ %s: pos(%s) components[%d] {%s}\n", entity.name, 41 // entity.position, entity.components.length, component_types); 42 sb ~= format(" ▷ %s: pos(%s) components[%s]\n", entity.name, entity.position, component_types 43 .length); 44 for (int j = 0; j < component_types.length; j++) { 45 sb ~= format(" ■ [%s] %s\n", j, component_types[j]); 46 } 47 } 48 } 49 log.info(sb.data); 50 } 51 52 private static bool pick_entity(string name, out Entity entity) { 53 // find entities in all scenes 54 foreach (scene; scenes) { 55 if (scene.ecs.has_entity(name)) { 56 entity = scene.get_entity(name); 57 log.info(format("selected entity '%s' in scene %s", 58 entity.name, typeid(scene).name)); 59 return true; 60 } 61 } 62 63 log.err(format("entity '%s' not found", name)); 64 return false; 65 } 66 67 private static bool pick_component(string[] args, out Component comp) { 68 if (args.length < 2) { 69 log.err("usage: <entity> <component>"); 70 return false; 71 } 72 Entity entity; 73 if (!pick_entity(args[0], entity)) 74 return false; 75 auto comp_sel = args[1]; 76 auto all_comps = entity.get_all_components(); 77 // check if we can parse component selector as int 78 try { 79 auto comp_ix = comp_sel.to!int; 80 81 // select component at this index 82 comp = all_comps[comp_ix]; 83 } catch (ConvException) { 84 // not an int, try to find component by name 85 auto comp_search = comp_sel.toLower; 86 // find matching component 87 auto matches = all_comps 88 .find!(x => x.classinfo.name.toLower.indexOf(comp_search) > 0); 89 if (matches.length == 0) { 90 log.err(format("no matching component for '%s'", comp_search)); 91 return false; 92 } 93 comp = matches.front; 94 } 95 96 return true; 97 } 98 99 static void c_dump(string[] args) { 100 Component comp; 101 if (!pick_component(args, comp)) 102 return; 103 // dump this component 104 auto sb = appender!(string); 105 auto comp_class = comp.getMetaType; 106 // log.info(format("dumping: %s", comp_class.getName)); 107 sb ~= format("dump: %s\n", comp_class.getName); 108 foreach (field; comp_class.getFields) { 109 sb ~= format(" %s = %s\n", field.getName, field.get(comp)); 110 } 111 log.info(sb.data); 112 } 113 114 static void c_inspect(string[] args) { 115 if (args.length == 0) { 116 if (dbg.inspector.open) { 117 // close inspector when run without args 118 dbg.inspector.close(); 119 } else { 120 // inspector isn't open, and no arg was given 121 log.err("usage: inspect <entity>"); 122 } 123 return; 124 } 125 Entity entity; 126 if (!pick_entity(args[0], entity)) 127 return; 128 if (dbg.inspector.open) 129 dbg.inspector.close(); // close the existing inspector 130 131 // attach the inspector to this entity 132 dbg.inspector.inspect(entity); 133 } 134 }