Repository: movingblocks/terasology
Issue: Harden 'search' command against malformed assets

### What you were trying to do

Search for stuff in the in-game console, like `search stone`

### What actually happened

Got a one-line error in the game console. Turned out an asset was misconfigured (was pointing to a template asset in the wrong module). After fixing that another similar case hit where the JSON in another asset was malformed, yet the error didn't give any clue _which _ asset.

Turns out I guess that to be able to search the engine goes and looks at every possible asset which means if it encounters even a single broken asset it'll error out and the search fails.

#1402 is a bigger goal to better validate assets (warnings at compile time somehow? Code scanning step?). But maybe we can harden `search` to better log what is breaking it?

#2874 also seems mildly similar

### How to reproduce

* Break an asset (like remove a comma or mess up a module name in a URI)
* Run the game and make sure the asset is within the active module set
* Run a `search` command for anything - get error!

### Example log 

`An error occurred while executing command 'search': Unable to resolve based block definition 'CoreBlocks:rock'`

(in that case the `rock` template actually lived in the CoreAssets module instead)

Changed files:
engine/src/main/java/org/terasology/logic/console/commands/CoreCommands.java

diff --git a/engine/src/main/java/org/terasology/logic/console/commands/CoreCommands.java b/engine/src/main/java/org/terasology/logic/console/commands/CoreCommands.java
index a566bf51a..3b8bd34a9 100644
--- a/engine/src/main/java/org/terasology/logic/console/commands/CoreCommands.java
+++ b/engine/src/main/java/org/terasology/logic/console/commands/CoreCommands.java
@@ -49,6 +49,7 @@
 import org.terasology.logic.console.suggesters.ScreenSuggester;
 import org.terasology.logic.console.suggesters.SkinSuggester;
 import org.terasology.logic.inventory.events.DropItemEvent;
+import org.terasology.logic.location.Location;
 import org.terasology.logic.location.LocationComponent;
 import org.terasology.logic.permission.PermissionManager;
 import org.terasology.math.Direction;
@@ -83,15 +84,15 @@
 
 import java.io.IOException;
 import java.net.UnknownHostException;
-import java.util.concurrent.Callable;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
 import java.util.List;
 import java.util.Set;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 /**
  * Adds a series of useful commands to the game. Likely these could be moved to more fitting places over time.
@@ -253,10 +254,27 @@ private List<String> findPrefabMatches(String searchLowercase) {
      * @return List of blocks that match searched string
      */
     private List<String> findBlockMatches(String searchLowercase) {
-        return assetManager.getAvailableAssets(BlockFamilyDefinition.class)
-                .stream().<Optional<BlockFamilyDefinition>>map(urn -> assetManager.getAsset(urn, BlockFamilyDefinition.class))
-                .filter(def -> def.isPresent() && def.get().isLoadable() && matchesSearch(searchLowercase, def.get()))
-                .map(r -> new BlockUri(r.get().getUrn()).toString()).collect(Collectors.toList());
+        ResourceUrn curUrn;
+        List<String> outputList=new ArrayList<String>();
+        for (ResourceUrn urn : assetManager.getAvailableAssets(BlockFamilyDefinition.class)) {
+            // Current urn for logging purposes to find the broken urn
+            curUrn = urn;
+            try{
+                Optional<BlockFamilyDefinition> def = assetManager.getAsset(urn, BlockFamilyDefinition.class);
+                if (def.isPresent() && def.get().isLoadable() && matchesSearch(searchLowercase, def.get())) {
+                    outputList.add(new BlockUri(def.get().getUrn()).toString());
+                }
+            }
+            // If a prefab is broken , it will throw an exception
+            catch(Exception e){
+                console.addMessage("Note : Search may not return results if invalid assets are present");
+                console.addMessage("Error parsing : "+curUrn.toString());
+                console.addMessage(e.toString());
+                continue;
+            }
+        }
+        return outputList;
+
     }
 
     /**