Update groveStreams.groovy
[smartapps.git] / official / smartblock-notifier.groovy
1 /**
2  *  Copyright 2015 SmartThings
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  *  in compliance with the License. You may obtain a copy of the License at:
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
10  *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
11  *  for the specific language governing permissions and limitations under the License.
12  *
13  *  SmartBlock Notifier
14  *
15  *  Author: Steve Vlaminck
16  *
17  *  Date: 2013-12-27
18  */
19
20 definition(
21     name: "SmartBlock Notifier",
22     namespace: "vlaminck/Minecraft",
23     author: "SmartThings",
24     description: "A SmartApp that notifies you when things are happening around your SmartBlocks",
25     iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
26     iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
27 )
28
29 preferences {
30         page(name: "firstPage")
31         page(name: "redstonePage")
32         page(name: "neighborBlockPage")
33         page(name: "messageBuilderPage")
34         page(name: "destroyedPage")
35 }
36
37 def firstPage() {
38
39         def defaultLabelValue = smartBlock ? (smartBlock.label ?: smartBlock.name) : null
40
41
42         def destroyedPageName = "destroyedPage"
43         def destroyedComplete = pageStateComplete(destroyedPageName)
44         def destroyedState = destroyedComplete ? "complete" : null
45         def destroyedDescription = destroyedComplete ? messageDescriptionForPage(destroyedPageName) : null
46
47         def redstonePageName = "redstonePage"
48         def redstoneComplete = pageStateComplete(redstonePageName)
49         def redstoneState = redstoneComplete ? "complete" : null
50         def redstoneDescription = redstoneComplete ? messageDescriptionForPage(redstonePageName) : null
51
52         def neighborPageName = "neighborBlockPage"
53         def neighborComplete = pageStateComplete(neighborPageName)
54         def neighborState = neighborComplete ? "complete" : null
55         def neighborDescription = neighborComplete ? messageDescriptionForPage(neighborPageNamePageName) : null
56
57         dynamicPage(name: "firstPage", title: "Setup your notifications", install: true, uninstall: true) {
58
59                 section("Get notifications for this SmartBlock") {
60                         input(name: "smartBlock", type: "capability.switch", title: "Which SmartBlock would you like to monitor?", multiple: false)
61                         // TODO: type: "device.smartBlock",
62                 }
63
64                 section("Why would you like to be notified?") {
65                         href(name: "toDestroyedPage", page: destroyedPageName, title: "Because it was destroyed", description: destroyedDescription, state: destroyedState)
66
67                         href(name: "toRedstonePage", page: redstonePageName, title: "Because its redstone signal changed", description: redstoneDescription, state: redstoneState)
68                         href(name: "toNeighborPage", page: neighborPageName, title: "Because a block next to it changed", description: neighborDescription, state: neighborState)
69                 }
70
71                 section("Other Options") {
72                         label(title: "Label this notification", description: app.name, required: false, defaultValue: defaultLabelValue)
73                         mode(title: "Only send notifications when in one of these modes", description: "All modes")
74                 }
75         }
76 }
77
78 def destroyedPage() {
79         def pageName = "destroyedPage"
80         dynamicPage(name: pageName, title: "For when your block is destroyed") {
81                 smartPhoneNotificationSection(pageName)
82                 chatSection(pageName)
83                 messageBuilderSection(pageName)
84                 chatClosestPlayerSection(pageName)
85         }
86 }
87
88 def redstonePage() {
89         def pageName = "redstonePage"
90         dynamicPage(name: pageName, title: "Get Notified For Redstone Changes") {
91                 section("When Redstone Is") {
92                         input(name: "redstoneGreaterThan", type: "enum", required: false, title: "Greater Than", options: (0..15).collect {
93                                 "${it}"
94                         })
95                         input(name: "redstoneLessThan", type: "enum", required: false, title: "Less than", options: (0..15).collect {
96                                 "${it}"
97                         })
98                         input(name: "redstoneEqualTo", type: "enum", required: false, title: "Equal to", options: (0..15).collect {
99                                 "${it}"
100                         })
101                 }
102                 smartPhoneNotificationSection(pageName)
103                 chatSection(pageName)
104                 messageBuilderSection(pageName)
105         }
106 }
107
108 def neighborBlockPage() {
109         def pageName = "neighborBlockPage"
110         dynamicPage(name: pageName, title: "Get Notified When a neighbor block updates") {
111                 section("Not all blocks send updates, but Chests definitely do") {
112                         input(type: "enum", name: "neighborBlockParsed", title: "When any of these blocks are updated", required: false, multiple: true, options: allBlocksParsed())
113                 }
114
115                 smartPhoneNotificationSection(pageName)
116                 chatSection(pageName)
117                 messageBuilderSection(pageName)
118                 chatClosestPlayerSection(pageName)
119
120                 section(title: "More Info", hideable: true, hidden: true) {
121                         href(name: "allIds", title: "A full list of blocks and items can be found here", url: "http://minecraft.gamepedia.com/Ids", style: "external", description: null)
122                 }
123         }
124 }
125
126 def messageBuilderPage(params) {
127
128         def pageName = params.pageName
129         def size = messageBuilderOptions().size() * 2
130
131         dynamicPage(name: "messageBuilderPage", title: "Build your message") {
132                 section("These will be combined to form the final message.") {
133                         (0..size).each {
134                                 input(
135                                         name: "${pageName}MessagePart${it}",
136                                         type: (it % 2) ? "enum" : "text",
137                                         defaultValue: messagePartDefaultValue(pageName, it),
138                                         options: (it % 2) ? messageBuilderOptions() : null,
139                                         title: null, description: null, required: false, multiple: false
140                                 )
141                         }
142                 }
143         }
144 }
145
146 def smartPhoneNotificationSection(pageName) {
147         section("SmartPhone notifications") {
148         input("recipients", "contact", title: "Send notifications to") {
149             input(name: "${pageName}WantsPush", title: "Push Notification", description: null, type: "bool", required: false, defaultValue: "false")
150             input(name: "${pageName}WantsSms", title: "Text Message", description: "phone number", type: "phone", required: false)
151         }
152                 input(name: "${pageName}WantsHH", title: "Hello Home only", description: null, type: "bool", required: false)
153         }
154 }
155
156 def chatSection(pageName) {
157         section("Minecraft Chat Message") {
158                 input(name: "${pageName}ChatAllUsers", title: "Chat all users", type: "bool", required: false)
159                 input(name: "${pageName}ChatUsername", title: "Or chat to a specific username", type: "text", required: false)
160         }
161 }
162
163 def messageBuilderSection(pageName) {
164         section("What should your message say?") {
165                 messageBuilderHref(pageName)
166         }
167 }
168
169 def messageBuilderHref(pageName) {
170         def partsAreSet = messagePartsSet(pageName)
171         def messageState = partsAreSet ? "complete" : ""
172         def messageDescription = partsAreSet ? messageDescriptionForPage(pageName) : defaultMessageDescription(pageName)
173
174         href(
175                 name: "toBuilder",
176                 page: "messageBuilderPage",
177                 title: null,
178                 description: messageDescription ?: "Construct your message",
179                 state: messageState,
180                 params: [pageName: pageName]
181         )
182 }
183
184 def chatClosestPlayerSection(pageName) {
185         section("Chat the closest player to the block. (usually the player that destroyed it)") {
186                 messageBuilderHref("${pageName}ClosestPlayer")
187         }
188 }
189
190 def pageStateComplete(pageName) {
191
192         if (pageName == "redstonePage") {
193                 if (redstoneGreaterThan) return true
194                 if (redstoneLessThan) return true
195                 if (redstoneEqualTo) return true
196                 return false
197         }
198
199         if (pageName == "neighborBlockPage") {
200                 if (neighborBlockParsed) return true
201                 return false
202         }
203
204         if (app."${pageName}WantsPush") return true
205         if (app."${pageName}WantsSms") return true
206         if (app."${pageName}WantsHH") return true
207         if (app."${pageName}ChatAllUsers") return true
208         if (app."${pageName}ChatUsername") return true
209         if (app."${pageName}ClosestPlayer") return true
210
211         return false
212 }
213
214 /*
215 * INITIALIZE
216 */
217
218 def installed() {
219         log.debug "Installed with settings: ${settings}"
220
221         initialize()
222 }
223
224 def updated() {
225         log.debug "Updated with settings: ${settings}"
226
227         unsubscribe()
228         initialize()
229 }
230
231 def initialize() {
232         log.debug "initializing"
233         subscribe(smartBlock, "redstoneSignalStrength", redstoneSignalStrengthHandler)
234         subscribe(smartBlock, "smartBlockNeighborChanged", smartBlockNeighborChangedHandler, [filterEvents: false])
235         subscribe(smartBlock, "smartBlockNeighborChanged", smartBlockNeighborChangedHandler, [filterEvents: false])
236         subscribe(smartBlock, "blockDestroyed.true", smartBlockDestroyedHandler, [filterEvents: false])
237 }
238
239 /*
240 * EVENT HANDLERS
241 */
242
243 def smartBlockDestroyedHandler(evt) {
244         log.debug "smartBlockDestroyedHandler evt.value: ${evt.value}"
245
246         def pageName = "destroyedPage"
247         def message = message(pageName)
248         notifyUser(pageName, message)
249 }
250
251 def smartBlockNeighborChangedHandler(evt) {
252         log.debug "smartBlockNeighborChangedHandler evt.value: ${evt.value}"
253         log.debug "neighborBlockParsed: ${neighborBlockParsed}"
254
255         if (neighborBlockParsed?.contains(evt.value)) {
256                 notifyUserOfNeighborChange(evt.value)
257         }
258 }
259
260 def redstoneSignalStrengthHandler(evt) {
261         log.debug "redstoneSignalStrengthHandler: ${evt.value}"
262
263         int newValue = evt.value as int
264         int lastValue = smartBlock.latestState("redstoneSignalStrength").value as int
265
266         if (redstoneGreaterThan) {
267                 int gt = redstoneGreaterThan as int
268 //              log.debug "$newValue > $gt"
269                 if (newValue > gt) {
270                         log.debug "greater than ${gt}. send notification"
271                         notifyUserOfRedstoneChange(newValue)
272                 }
273         }
274
275         if (redstoneLessThan) {
276                 int lt = redstoneLessThan as int
277 //              log.debug "$newValue < $lt"
278                 if (newValue < lt) {
279                         log.debug "less than ${lt}. send notification"
280                         notifyUserOfRedstoneChange(newValue)
281                 }
282         }
283
284         if (redstoneEqualTo) {
285                 int et = redstoneEqualTo as int
286 //              log.debug "$newValue == $et"
287                 if (newValue == et) {
288                         log.debug "equal to ${et}. send notification"
289                         notifyUserOfRedstoneChange(newValue)
290                 }
291         }
292
293 }
294
295 /*
296 * NOTIFICATIONS
297 */
298
299 def notifyUserOfRedstoneChange(value) {
300         def msg = message("redstonePage")
301         log.debug "message: ${msg}"
302         def notificationMessage = msg ?: "${smartBlock} redstone signal is ${value}"
303         notifyUser(notificationMessage)
304 }
305
306 def notifyUserOfNeighborChange(value) {
307         def msg = message("neighborPage")
308         log.debug "message: ${msg}"
309         def notificationMessage = msg ?: "${smartBlock} was updated by ${value}"
310         notifyUser(notificationMessage)
311 }
312
313 def notifyUser(pageName, messageToSend) {
314         log.debug "notifyUser pageName: ${pageName}"
315
316         def closestPlayerMessage = message("${pageName}ClosestPlayer")
317         log.debug "closestPlayerMessage = ${closestPlayerMessage}"
318         def latestClosePlayer = getLatestClosePlayer()
319         log.debug "latestClosePlayer = ${latestClosePlayer}"
320         if (closestPlayerMessage && latestClosePlayer != "unknown") {
321                 log.debug "chatting closestPlayer"
322                 chatMessageToMC(closestPlayerMessage, latestClosePlayer)
323         }
324
325
326         def wantsHH = app."${pageName}WantsHH"
327         log.debug "wantsHH = ${wantsHH}"
328         if (wantsHH) {
329
330                 log.debug "sending HH"
331                 sendNotificationEvent(messageToSend)
332
333         } else {
334         if (location.contactBookEnabled) {
335             sendNotificationToContacts(messageToSend, recipients)
336         }
337         else {
338
339             def wantsPush = app."${pageName}WantsPush"
340             log.debug "wantsPush = ${wantsPush}"
341             if (wantsPush && wantsPush != "false") {
342                 log.debug "sending push"
343                 sendPush(messageToSend)
344             }
345
346             def wantsSms = app."${pageName}WantsSms"
347             log.debug "wantsSms = ${wantsSms}"
348             if (wantsSms) {
349                 log.debug "sending sms to: ${wantsSms}"
350                 sendSms(wantsSms, messageToSend)
351             }
352         }
353         }
354
355         def username = app."${pageName}ChatUsername"
356         def allUsers = app."${pageName}ChatAllUsers"
357
358         log.debug "username = ${username}"
359         log.debug "allUsers = ${allUsers}"
360
361         if (username && username != "") {
362                 log.debug "chatting username: ${username}"
363                 chatMessageToMC(messageToSend, username)
364         } else if (allUsers) {
365                 log.debug "chatting all users"
366                 chatMessageToMC(messageToSend, null)
367         }
368
369 }
370
371 def chatMessageToMC(message, username) {
372         log.debug "chatMessageToMC"
373
374         def url = "${app.getParent().getServerURL()}/chat?message=${message.encodeAsURL()}"
375         if (username) {
376                 url = "${url}&username=${username.encodeAsURL()}"
377         }
378
379         log.debug "POST to ${url}"
380
381         httpPost(url, "foo=bar") {}
382 }
383
384 def messageDescriptionPartsForPage(pageName) {
385         def size = messageBuilderOptions().size() * 2
386         (0..size).collect { app."${pageName}MessagePart${it}" }
387 }
388
389 def messagePartsSet(pageName) { // are any set?
390         messageDescriptionPartsForPage(pageName).collect { !it }.unique().contains(false)
391 }
392
393 def defaultMessageDescription(pageName) {
394         def description = ""
395
396         if (pageName == "destroyedPage" || pageName == "redstonePage" || pageName == "neighborBlockPage") {
397                 def second = messageBuilderOptions()[messagePartDefaultValue(pageName, 1)]
398                 if (second) description = "\${${second}}"
399
400                 def third = messagePartDefaultValue(pageName, 2)
401                 if (third) description = "${description} ${third}"
402
403                 def fourth = messageBuilderOptions()[messagePartDefaultValue(pageName, 3)]
404                 if (fourth) description = "${description} \${${fourth}}"
405         }
406
407         return description
408 }
409
410 def messageDescriptionForPage(pageName) {
411
412         def parts = messageDescriptionPartsForPage(pageName)
413         def messageParts = []
414         parts.eachWithIndex { part, idx ->
415                 if (part != null && part != "null") {
416                         if (idx % 2) {
417                                 messageParts << "\${${messageBuilderOptions()[part]}}"
418                         } else {
419                                 messageParts << part
420                         }
421                 }
422         }
423
424         if (messageParts) {
425                 return messageParts.join(" ").trim()
426         } else {
427                 return defaultMessageDescription()
428         }
429 }
430
431 def messagePartDefaultValue(pageName, part) {
432         if (pageName == "destroyedPage") {
433                 if (part == 1) return "name"
434                 if (part == 2) return "was destroyed by"
435                 if (part == 3) return "closestPlayer"
436         }
437
438         if (pageName == "neighborBlockPage") {
439                 if (part == 1) return "name"
440                 if (part == 2) return "has a redstone signal of"
441                 if (part == 3) return "redstoneSignalStrength"
442         }
443
444         if (pageName == "redstonePage") {
445                 if (part == 1) return "name"
446                 if (part == 2) return "was updated by"
447                 if (part == 3) return "closestPlayer"
448         }
449
450         return null
451 }
452
453 def message(pageName) {
454         log.debug "building message"
455         def messageParts = []
456
457         messageDescriptionPartsForPage(pageName).eachWithIndex { part, idx ->
458                 if (idx % 2) {
459 //                      def option = messageBuilderOptions()[part]
460                         def optionPart = getMessagePartFromOption(part)
461                         if (optionPart) messageParts << optionPart
462                 } else {
463                         if (part) messageParts << part
464                 }
465         }
466
467         def message = messageParts.join(" ").trim()
468         log.debug "message: ${message}"
469         return message
470 }
471
472 def messageBuilderOptions() {
473         return [
474                 "name": "SmartBlock name",
475                 "neighborBlockName": "Neighbor block name",
476                 "blockDestroyed": "Destroyed State ('destroyed' / 'OK')",
477                 "redstoneSignalStrength": "Redstone signal strength",
478                 "worldSeed": "World seed",
479                 "dimensionName": "Dimension name (World, Nether, End)",
480                 "coordinates": "Block coordinates",
481                 "closestPlayer": "Username of Closest player (within the past minute)",
482                 "placedBy": "Username of who placed the block"
483         ]
484 }
485
486 def getMessagePartFromOption(optionKey) {
487         log.debug "optionKey: ${optionKey}"
488         if (optionKey == "name") return smartBlock.label ?: smartBlock.name
489         if (optionKey == "closestPlayer") return getLatestClosePlayer()
490         if (optionKey == "blockDestroyed") return smartBlock.latestValue("blockDestroyed") ? "OK" : "destroyed"
491         return smartBlock.latestValue(optionKey)
492 }
493
494 def getLatestClosePlayer() {
495         def now = new Date()
496         def minusOne = new Date(minutes: now.minutes - 1)
497         def latestStates = smartBlock.statesSince("closestPlayer", minusOne)
498         if (latestStates.size) {
499                 return latestStates[0].value
500         }
501         return "unknown"
502 }
503
504 /*
505 * BLOCKS
506 */
507
508 def settingsAsIds() {
509         log.debug "settingsAsIds"
510         log.debug "neighborBlockParsed: $neighborBlockParsed"
511
512         def subscribedIds = []
513
514         neighborBlockParsed.each {
515                 subscribedIds << convertBlockSettingToBlockId(it)
516         }
517
518         return subscribedIds
519 }
520
521 def convertBlockSettingToBlockId(setting) {
522         def id = setting.substring(0, setting.indexOf(" "))
523         def name = allBlocks()[id]
524         log.debug "id: $id, name:${name}"
525         return id
526 }
527
528 def allBlocksParsed() {
529         allBlocks().collect { k, v -> "${k} ${v}" }
530 }
531
532 def allBlocks() {
533         [
534                 "0": "Air",
535                 "1": "Stone",
536                 "2": "Grass",
537                 "3": "Dirt",
538                 "4": "Cobblestone",
539                 "5": "Oak Wood Plank",
540                 "5:1": "Spruce Wood Plank",
541                 "5:2": "Birch Wood Plank",
542                 "5:3": "Jungle Wood Plank",
543                 "6": "Oak Sapling",
544                 "6:1": "Spruce Sapling",
545                 "6:2": "Birch Sapling",
546                 "6:3": "Jungle Sapling",
547                 "7": "Bedrock",
548                 "8": "Water",
549                 "9": "Stationary Water",
550                 "10": "Lava",
551                 "11": "Stationary Lava",
552                 "12": "Sand",
553                 "13": "Gravel",
554                 "14": "Gold Ore",
555                 "15": "Iron Ore",
556                 "16": "Coal Ore",
557                 "17": "Oak Wood",
558                 "17:1": "Spruce Wood",
559                 "17:2": "Birch Wood",
560                 "17:3": "Jungle Wood",
561                 "18": "Oak Leaves",
562                 "18:1": "Spruce Leaves",
563                 "18:2": "Birch Leaves",
564                 "18:3": "Jungle Leaves",
565                 "19": "Sponge",
566                 "20": "Glass",
567                 "21": "Lapis Lazuli Ore",
568                 "22": "Lapis Lazuli Block",
569                 "23": "Dispenser",
570                 "24": "Sandstone",
571                 "24:1": "Chiseled Sandstone",
572                 "24:2": "Smooth Sandstone",
573                 "25": "Note Block",
574                 "26": "Bed Block",
575                 "27": "Powered Rail",
576                 "28": "Detector Rail",
577                 "29": "Sticky Piston",
578                 "30": "Web",
579                 "31": "Dead Shrub",
580                 "31:1": "Grass",
581                 "31:2": "Fern",
582                 "32": "Dead Shrub",
583                 "33": "Piston",
584                 "34": "Piston Head",
585                 "35": "White Wool",
586                 "35:1": "Orange Wool",
587                 "35:2": "Magenta Wool",
588                 "35:3": "Light Blue Wool",
589                 "35:4": "Yellow Wool",
590                 "35:5": "Lime Wool",
591                 "35:6": "Pink Wool",
592                 "35:7": "Gray Wool",
593                 "35:8": "Light Gray Wool",
594                 "35:9": "Cyan Wool",
595                 "35:10": "Purple Wool",
596                 "35:11": "Blue Wool",
597                 "35:12": "Brown Wool",
598                 "35:13": "Green Wool",
599                 "35:14": "Red Wool",
600                 "35:15": "Black Wool",
601                 "37": "Dandelion",
602                 "38": "Rose",
603                 "39": "Brown Mushroom",
604                 "40": "Red Mushroom",
605                 "41": "Gold Block",
606                 "42": "Iron Block",
607                 "43": "Double Stone Slab",
608                 "43:1": "Double Sandstone Slab",
609                 "43:2": "Double Wooden Slab",
610                 "43:3": "Double Cobblestone Slab",
611                 "43:4": "Double Brick Slab",
612                 "43:5": "Double Stone Brick Slab",
613                 "43:6": "Double Nether Brick Slab",
614                 "43:7": "Double Quartz Slab",
615                 "44": "Stone Slab",
616                 "44:1": "Sandstone Slab",
617                 "44:2": "Wooden Slab",
618                 "44:3": "Cobblestone Slab",
619                 "44:4": "Brick Slab",
620                 "44:5": "Stone Brick Slab",
621                 "44:6": "Nether Brick Slab",
622                 "44:7": "Quartz Slab",
623                 "45": "Brick",
624                 "46": "TNT",
625                 "47": "Bookshelf",
626                 "48": "Mossy Cobblestone",
627                 "49": "Obsidian",
628                 "50": "Torch",
629                 "51": "Fire",
630                 "52": "Monster Spawner",
631                 "53": "Oak Wood Stairs",
632                 "54": "Chest",
633                 "55": "Redstone Wire",
634                 "56": "Diamond Ore",
635                 "57": "Diamond Block",
636                 "58": "Workbench",
637                 "59": "Wheat Crops",
638                 "60": "Soil",
639                 "61": "Furnace",
640                 "62": "Burning Furnace",
641                 "63": "Sign Post",
642                 "64": "Wooden Door Block",
643                 "65": "Ladder",
644                 "66": "Rails",
645                 "67": "Cobblestone Stairs",
646                 "68": "Wall Sign",
647                 "69": "Lever",
648                 "70": "Stone Pressure Plate",
649                 "71": "Iron Door Block",
650                 "72": "Wooden Pressure Plate",
651                 "73": "Redstone Ore",
652                 "74": "Glowing Redstone Ore",
653                 "75": "Redstone Torch(off)",
654                 "76": "Redstone Torch(on)",
655                 "77": "Stone Button",
656                 "78": "Snow",
657                 "79": "Ice",
658                 "80": "Snow Block",
659                 "81": "Cactus",
660                 "82": "Clay",
661                 "83": "Sugar Cane",
662                 "84": "Jukebox",
663                 "85": "Fence",
664                 "86": "Pumpkin",
665                 "87": "Netherrack",
666                 "88": "Soul Sand",
667                 "89": "Glowstone",
668                 "90": "Portal",
669                 "91": "Jack - O - Lantern",
670                 "92": "Cake Block",
671                 "93": "Redstone Repeater Block(off)",
672                 "94": "Redstone Repeater Block(on)",
673                 "95": "Locked Chest",
674                 "96": "Trapdoor",
675                 "97": "Stone(Silverfish)",
676                 "97:1": "Cobblestone(Silverfish)",
677                 "97:2": "Stone Brick(Silverfish)",
678                 "98": "Stone Brick",
679                 "98:1": "Mossy Stone Brick",
680                 "98:2": "Cracked Stone Brick",
681                 "98:3": "Chiseled Stone Brick",
682                 "99": "Red Mushroom Cap",
683                 "100": "Brown Mushroom Cap",
684                 "101": "Iron Bars",
685                 "102": "Glass Pane",
686                 "103": "Melon Block",
687                 "104": "Pumpkin Stem",
688                 "105": "Melon Stem",
689                 "106": "Vines",
690                 "107": "Fence Gate",
691                 "108": "Brick Stairs",
692                 "109": "Stone Brick Stairs",
693                 "110": "Mycelium",
694                 "111": "Lily Pad",
695                 "112": "Nether Brick",
696                 "113": "Nether Brick Fence",
697                 "114": "Nether Brick Stairs",
698                 "115": "Nether Wart",
699                 "116": "Enchantment Table",
700                 "117": "Brewing Stand",
701                 "118": "Cauldron",
702                 "119": "End Portal",
703                 "120": "End Portal Frame",
704                 "121": "End Stone",
705                 "122": "Dragon Egg",
706                 "123": "Redstone Lamp(inactive)",
707                 "124": "Redstone Lamp(active)",
708                 "125": "Double Oak Wood Slab",
709                 "125:1": "Double Spruce Wood Slab",
710                 "125:2": "Double Birch Wood Slab",
711                 "125:3": "Double Jungle Wood Slab",
712                 "126": "Oak Wood Slab",
713                 "126:1": "Spruce Wood Slab",
714                 "126:2": "Birch Wood Slab",
715                 "126:3": "Jungle Wood Slab",
716                 "127": "Cocoa Plant",
717                 "128": "Sandstone Stairs",
718                 "129": "Emerald Ore",
719                 "130": "Ender Chest",
720                 "131": "Tripwire Hook",
721                 "132": "Tripwire",
722                 "133": "Emerald Block",
723                 "134": "Spruce Wood Stairs",
724                 "135": "Birch Wood Stairs",
725                 "136": "Jungle Wood Stairs",
726                 "137": "Command Block",
727                 "138": "Beacon Block",
728                 "139": "Cobblestone Wall",
729                 "139:1": "Mossy Cobblestone Wall",
730                 "140": "Flower Pot",
731                 "141": "Carrots",
732                 "142": "Potatoes",
733                 "143": "Wooden Button",
734                 "144": "Mob Head",
735                 "145": "Anvil",
736                 "146": "Trapped Chest",
737                 "147": "Weighted Pressure Plate(light)",
738                 "148": "Weighted Pressure Plate(heavy)",
739                 "149": "Redstone Comparator(inactive)",
740                 "150": "Redstone Comparator(active)",
741                 "151": "Daylight Sensor",
742                 "152": "Redstone Block",
743                 "153": "Nether Quartz Ore",
744                 "154": "Hopper",
745                 "155": "Quartz Block",
746                 "155:1": "Chiseled Quartz Block",
747                 "155:2": "Pillar Quartz Block",
748                 "156": "Quartz Stairs",
749                 "157": "Activator Rail",
750                 "158": "Dropper",
751                 "159": "White Stained Clay",
752                 "159:1": "Orange Stained Clay",
753                 "159:2": "Magenta Stained Clay",
754                 "159:3": "Light Blue Stained Clay",
755                 "159:4": "Yellow Stained Clay",
756                 "159:5": "Lime Stained Clay",
757                 "159:6": "Pink Stained Clay",
758                 "159:7": "Gray Stained Clay",
759                 "159:8": "Light Gray Stained Clay",
760                 "159:9": "Cyan Stained Clay",
761                 "159:10": "Purple Stained Clay",
762                 "159:11": "Blue Stained Clay",
763                 "159:12": "Brown Stained Clay",
764                 "159:13": "Green Stained Clay",
765                 "159:14": "Red Stained Clay",
766                 "159:15": "Black Stained Clay",
767                 "170": "Hay Bale",
768                 "171": "White Carpet",
769                 "171:1": "Orange Carpet",
770                 "171:2": "Magenta Carpet",
771                 "171:3": "Light Blue Carpet",
772                 "171:4": "Yellow Carpet",
773                 "171:5": "Lime Carpet",
774                 "171:6": "Pink Carpet",
775                 "171:7": "Gray Carpet",
776                 "171:8": "Light Gray Carpet",
777                 "171:9": "Cyan Carpet",
778                 "171:10": "Purple Carpet",
779                 "171:11": "Blue Carpet",
780                 "171:12": "Brown Carpet",
781                 "171:13": "Green Carpet",
782                 "171:14": "Red Carpet",
783                 "171:15": "Black Carpet",
784                 "172": "Hardened Clay",
785                 "173": "Block of Coal",
786                 "256": "Iron Shovel",
787                 "257": "Iron Pickaxe",
788                 "258": "Iron Axe",
789                 "259": "Flint and Steel",
790                 "260": "Apple",
791                 "261": "Bow",
792                 "262": "Arrow",
793                 "263": "Coal",
794                 "263:1": "Charcoal",
795                 "264": "Diamond",
796                 "265": "Iron Ingot",
797                 "266": "Gold Ingot",
798                 "267": "Iron Sword",
799                 "268": "Wooden Sword",
800                 "269": "Wooden Shovel",
801                 "270": "Wooden Pickaxe",
802                 "271": "Wooden Axe",
803                 "272": "Stone Sword",
804                 "273": "Stone Shovel",
805                 "274": "Stone Pickaxe",
806                 "275": "Stone Axe",
807                 "276": "Diamond Sword",
808                 "277": "Diamond Shovel",
809                 "278": "Diamond Pickaxe",
810                 "279": "Diamond Axe",
811                 "280": "Stick",
812                 "281": "Bowl",
813                 "282": "Mushroom Soup",
814                 "283": "Gold Sword",
815                 "284": "Gold Shovel",
816                 "285": "Gold Pickaxe",
817                 "286": "Gold Axe",
818                 "287": "String",
819                 "288": "Feather",
820                 "289": "Sulphur",
821                 "290": "Wooden Hoe",
822                 "291": "Stone Hoe",
823                 "292": "Iron Hoe",
824                 "293": "Diamond Hoe",
825                 "294": "Gold Hoe",
826                 "295": "Wheat Seeds",
827                 "296": "Wheat",
828                 "297": "Bread",
829                 "298": "Leather Helmet",
830                 "299": "Leather Chestplate",
831                 "300": "Leather Leggings",
832                 "301": "Leather Boots",
833                 "302": "Chainmail Helmet",
834                 "303": "Chainmail Chestplate",
835                 "304": "Chainmail Leggings",
836                 "305": "Chainmail Boots",
837                 "306": "Iron Helmet",
838                 "307": "Iron Chestplate",
839                 "308": "Iron Leggings",
840                 "309": "Iron Boots",
841                 "310": "Diamond Helmet",
842                 "311": "Diamond Chestplate",
843                 "312": "Diamond Leggings",
844                 "313": "Diamond Boots",
845                 "314": "Gold Helmet",
846                 "315": "Gold Chestplate",
847                 "316": "Gold Leggings",
848                 "317": "Gold Boots",
849                 "318": "Flint",
850                 "319": "Raw Porkchop",
851                 "320": "Cooked Porkchop",
852                 "321": "Painting",
853                 "322": "Golden Apple",
854                 "322:1": "Enchanted Golden Apple",
855                 "323": "Sign",
856                 "324": "Wooden Door",
857                 "325": "Bucket",
858                 "326": "Water Bucket",
859                 "327": "Lava Bucket",
860                 "328": "Minecart",
861                 "329": "Saddle",
862                 "330": "Iron Door",
863                 "331": "Redstone",
864                 "332": "Snowball",
865                 "333": "Boat",
866                 "334": "Leather",
867                 "335": "Milk Bucket",
868                 "336": "Clay Brick",
869                 "337": "Clay Balls",
870                 "338": "Sugarcane",
871                 "339": "Paper",
872                 "340": "Book",
873                 "341": "Slimeball",
874                 "342": "Storage Minecart",
875                 "343": "Powered Minecart",
876                 "344": "Egg",
877                 "345": "Compass",
878                 "346": "Fishing Rod",
879                 "347": "Clock",
880                 "348": "Glowstone Dust",
881                 "349": "Raw Fish",
882                 "350": "Cooked Fish",
883                 "351": "Ink Sack",
884                 "351:1": "Rose Red",
885                 "351:2": "Cactus Green",
886                 "351:3": "Coco Beans",
887                 "351:4": "Lapis Lazuli",
888                 "351:5": "Purple Dye",
889                 "351:6": "Cyan Dye",
890                 "351:7": "Light Gray Dye",
891                 "351:8": "Gray Dye",
892                 "351:9": "Pink Dye",
893                 "351:10": "Lime Dye",
894                 "351:11": "Dandelion Yellow",
895                 "351:12": "Light Blue Dye",
896                 "351:13": "Magenta Dye",
897                 "351:14": "Orange Dye",
898                 "351:15": "Bone Meal",
899                 "352": "Bone",
900                 "353": "Sugar",
901                 "354": "Cake",
902                 "355": "Bed",
903                 "356": "Redstone Repeater",
904                 "357": "Cookie",
905                 "358": "Map",
906                 "359": "Shears",
907                 "360": "Melon",
908                 "361": "Pumpkin Seeds",
909                 "362": "Melon Seeds",
910                 "363": "Raw Beef",
911                 "364": "Steak",
912                 "365": "Raw Chicken",
913                 "366": "Cooked Chicken",
914                 "367": "Rotten Flesh",
915                 "368": "Ender Pearl",
916                 "369": "Blaze Rod",
917                 "370": "Ghast Tear",
918                 "371": "Gold Nugget",
919                 "372": "Nether Wart Seeds",
920                 "373": "Potion",
921                 "374": "Glass Bottle",
922                 "375": "Spider Eye",
923                 "376": "Fermented Spider Eye",
924                 "377": "Blaze Powder",
925                 "378": "Magma Cream",
926                 "379": "Brewing Stand",
927                 "380": "Cauldron",
928                 "381": "Eye of Ender",
929                 "382": "Glistering Melon",
930                 "383:50": "Spawn Creeper",
931                 "383:51": "Spawn Skeleton",
932                 "383:52": "Spawn Spider",
933                 "383:54": "Spawn Zombie",
934                 "383:55": "Spawn Slime",
935                 "383:56": "Spawn Ghast",
936                 "383:57": "Spawn Pigman",
937                 "383:58": "Spawn Enderman",
938                 "383:59": "Spawn Cave Spider",
939                 "383:60": "Spawn Silverfish ",
940                 "383:61": "Spawn Blaze",
941                 "383:62": "Spawn Magma Cube ",
942                 "383:65": "Spawn Bat",
943                 "383:66": "Spawn Witch",
944                 "383:90": "Spawn Pig",
945                 "383:91": "Spawn Sheep",
946                 "383:92": "Spawn Cow",
947                 "383:93": "Spawn Chicken",
948                 "383:94": "Spawn Squid",
949                 "383:95": "Spawn Wolf",
950                 "383:96": "Spawn Mooshroom",
951                 "383:98": "Spawn Ocelot",
952                 "383:100": "Spawn Horse",
953                 "383:120": "Spawn Villager",
954                 "384": "Bottle o' Enchanting",
955                 "385": "Fire Charge",
956                 "386": "Book and Quill",
957                 "387": "Written Book",
958                 "388": "Emerald",
959                 "389": "Item Frame",
960                 "390": "Flower Pot",
961                 "391": "Carrots",
962                 "392": "Potato",
963                 "393": "Baked Potato",
964                 "394": "Poisonous Potato",
965                 "395": "Map",
966                 "396": "Golden Carrot",
967                 "397": "Mob Head (Skeleton)",
968                 "397:1": "Mob Head (Wither Skeleton)",
969                 "397:2": "Mob Head (Zombie)",
970                 "397:3": "Mob Head (Human)",
971                 "397:4": "Mob Head (Creeper)",
972                 "398": "Carrot on a Stick",
973                 "399": "Nether Star",
974                 "400": "Pumpkin Pie",
975                 "401": "Firework Rocket",
976                 "402": "Firework Star",
977                 "403": "Enchanted Book",
978                 "404": "Redstone Comparator",
979                 "405": "Nether Brick",
980                 "406": "Nether Quartz",
981                 "407": "Minecart with TNT",
982                 "408": "Minecart with Hopper",
983                 "417": "Iron Horse Armor",
984                 "418": "Gold Horse Armor",
985                 "419": "Diamond Horse Armor",
986                 "420": "Lead",
987                 "421": "Name Tag"
988         ]
989 }