Add script to parse Minetweaker output

This commit is contained in:
Andrew Miner
2016-08-21 14:41:23 -07:00
parent aed8b15738
commit cbb3940360
7 changed files with 1494 additions and 9 deletions
+1
View File
@@ -4,3 +4,4 @@ build
dist dist
node_modules node_modules
data/modpack.cg data/modpack.cg
tmp.cg
+814
View File
@@ -0,0 +1,814 @@
item: Advanced Crafting Table
recipe:
input: Chest, Crafting Table, Obsidian, Redstone Chipset
pattern: 212 202 232
item: Architect Table
recipe:
input: Blueprint, Crafting Table, Dandelion Yellow, Diamond Gear, Ink Sac, Land Mark
pattern: 454 212 303
item: Assembly Table
recipe:
input: Diamond, Diamond Gear, Obsidian, Redstone
pattern: 232 202 212
item: Auto Workbench
recipe:
input: Crafting Table, Wood Gear
pattern: .1. 101 .1.
item: Basic Gate
gatherable: true
item: Basic Gate (Autarchic Pulsar)
gatherable: true
item: Basic Gate (Clock Timer)
gatherable: true
item: Basic Gate (Redstone Fader)
gatherable: true
item: Blue Pipe Wire
gatherable: true
item: Blueprint
recipe:
input: Lapis Lazuli, Paper
pattern: 111 101 111
item: Blueprint Library
recipe:
input: Blueprint, Bookshelf
pattern: 000 010 000
item: Builder
recipe:
input: Chest, Crafting Table, Dandelion Yellow, Diamond Gear, Ink Sac, Land Mark
pattern: 454 212 303
item: Charging Table
recipe:
input: Gold Gear, Obsidian, Redstone, Redstone Chipset
pattern: 121 131 101
item: Chute
recipe:
input: Chest, Iron Ingot, Stone Gear
pattern: 101 121 .1.
item: Clay Transport Pipe
recipe:
input: Clay, Glass
pattern: 010 ... ...
item: Cobblestone Fluid Pipe
gatherable: true
item: Cobblestone Kinesis Pipe
gatherable: true
item: Cobblestone Structure Pipe
gatherable: true
item: Cobblestone Transport Pipe
recipe:
input: Cobblestone, Glass
pattern: 010 ... ...
item: Combustion Engine
recipe:
input: Glass, Iron Gear, Iron Ingot, Piston
pattern: 222 .0. 131
item: Construction Mark
recipe:
input: Gold Gear, Redstone Torch
pattern: 0.1 ... ...
item: Creative Engine
gatherable: true
item: Daizuli Transport Pipe
recipe:
input: Diamond, Glass, Lapis Lazuli Block
pattern: 210 ... ...
item: Diamond AND Gate
gatherable: true
item: Diamond AND Gate (Autarchic Pulsar)
gatherable: true
item: Diamond AND Gate (Clock Timer)
gatherable: true
item: Diamond AND Gate (Redstone Fader)
gatherable: true
item: Diamond Chipset
gatherable: true
item: Diamond Fluid Pipe
gatherable: true
item: Diamond Gear
recipe:
input: Diamond, Gold Gear
pattern: .0. 010 .0.
item: Diamond Kinesis Pipe
gatherable: true
item: Diamond OR Gate
gatherable: true
item: Diamond OR Gate (Autarchic Pulsar)
gatherable: true
item: Diamond OR Gate (Clock Timer)
gatherable: true
item: Diamond OR Gate (Redstone Fader)
gatherable: true
item: Diamond Transport Pipe
recipe:
input: Diamond, Glass
pattern: 010 ... ...
item: Docking Station
recipe:
input: Golden Chipset, Iron Ingot
pattern: ... .1. 101
item: Emerald AND Gate
gatherable: true
item: Emerald AND Gate (Autarchic Pulsar)
gatherable: true
item: Emerald AND Gate (Clock Timer)
gatherable: true
item: Emerald AND Gate (Redstone Fader)
gatherable: true
item: Emerald Chipset
gatherable: true
item: Emerald Fluid Pipe
gatherable: true
item: Emerald Kinesis Pipe
gatherable: true
item: Emerald OR Gate
gatherable: true
item: Emerald OR Gate (Autarchic Pulsar)
gatherable: true
item: Emerald OR Gate (Clock Timer)
gatherable: true
item: Emerald OR Gate (Redstone Fader)
gatherable: true
item: Emerald Transport Pipe
recipe:
input: Emerald, Glass
pattern: 010 ... ...
item: Emzuli Transport Pipe
recipe:
input: Emerald, Glass, Lapis Lazuli Block
pattern: 210 ... ...
item: End Stone Facade
gatherable: true
item: End Stone Hollow Facade
gatherable: true
item: Filler
recipe:
input: Chest, Crafting Table, Dandelion Yellow, Gold Gear, Ink Sac, Land Mark
pattern: 454 212 303
item: Filter (Black)
gatherable: true
item: Filter (Blue)
gatherable: true
item: Filter (Brown)
gatherable: true
item: Filter (Cyan)
gatherable: true
item: Filter (Gray)
gatherable: true
item: Filter (Green)
gatherable: true
item: Filter (Light Blue)
gatherable: true
item: Filter (Light Gray)
gatherable: true
item: Filter (Lime)
gatherable: true
item: Filter (Magenta)
gatherable: true
item: Filter (Orange)
gatherable: true
item: Filter (Pink)
gatherable: true
item: Filter (Purple)
gatherable: true
item: Filter (Red)
gatherable: true
item: Filter (White)
gatherable: true
item: Filter (Yellow)
gatherable: true
item: Filtered Buffer
recipe:
input: Chest, Diamond Transport Pipe, Oak Wood Planks, Piston
pattern: 212 202 232
item: Flood Gate
recipe:
input: Iron Bars, Iron Gear, Iron Ingot, Tank
pattern: 212 030 202
item: Frame
gatherable: true
item: Fuel
gatherable: true
item: Fuel Bucket
gatherable: true
item: Gate Copier
gatherable: true
item: Gold AND Gate
gatherable: true
item: Gold AND Gate (Autarchic Pulsar)
gatherable: true
item: Gold AND Gate (Clock Timer)
gatherable: true
item: Gold AND Gate (Redstone Fader)
gatherable: true
item: Gold Gear
recipe:
input: Gold Ingot, Iron Gear
pattern: .0. 010 .0.
item: Gold OR Gate
gatherable: true
item: Gold OR Gate (Autarchic Pulsar)
gatherable: true
item: Gold OR Gate (Clock Timer)
gatherable: true
item: Gold OR Gate (Redstone Fader)
gatherable: true
item: Golden Chipset
gatherable: true
item: Golden Fluid Pipe
gatherable: true
item: Golden Kinesis Pipe
gatherable: true
item: Golden Transport Pipe
recipe:
input: Glass, Gold Ingot
pattern: 101 ... ...
item: Green Pipe Wire
gatherable: true
item: Integration Table
recipe:
input: Diamond Gear, Obsidian, Redstone, Redstone Chipset
pattern: 121 131 101
item: Iron AND Gate
gatherable: true
item: Iron AND Gate (Autarchic Pulsar)
gatherable: true
item: Iron AND Gate (Clock Timer)
gatherable: true
item: Iron AND Gate (Redstone Fader)
gatherable: true
item: Iron Chipset
gatherable: true
item: Iron Fluid Pipe
gatherable: true
item: Iron Gear
recipe:
input: Iron Ingot, Stone Gear
pattern: .0. 010 .0.
item: Iron Kinesis Pipe
gatherable: true
item: Iron OR Gate
gatherable: true
item: Iron OR Gate (Autarchic Pulsar)
gatherable: true
item: Iron OR Gate (Clock Timer)
gatherable: true
item: Iron OR Gate (Redstone Fader)
gatherable: true
item: Iron Transport Pipe
recipe:
input: Glass, Iron Ingot
pattern: 101 ... ...
item: Land Mark
recipe:
input: Lapis Lazuli, Redstone Torch
pattern: 0.1 ... ...
item: Laser
recipe:
input: Diamond, Obsidian, Redstone
pattern: 122 002 122
item: Lazuli Transport Pipe
recipe:
input: Glass, Lapis Lazuli Block
pattern: 101 ... ...
item: Lens (Black)
gatherable: true
item: Lens (Blue)
gatherable: true
item: Lens (Brown)
gatherable: true
item: Lens (Cyan)
gatherable: true
item: Lens (Gray)
gatherable: true
item: Lens (Green)
gatherable: true
item: Lens (Light Blue)
gatherable: true
item: Lens (Light Gray)
gatherable: true
item: Lens (Lime)
gatherable: true
item: Lens (Magenta)
gatherable: true
item: Lens (Orange)
gatherable: true
item: Lens (Pink)
gatherable: true
item: Lens (Purple)
gatherable: true
item: Lens (Red)
gatherable: true
item: Lens (White)
gatherable: true
item: Lens (Yellow)
gatherable: true
item: List
recipe:
input: Cactus Green, Paper
pattern: 111 101 111
item: Map Location
recipe:
input: Dandelion Yellow, Paper
pattern: 111 101 111
item: Mining Pipe
gatherable: true
item: Mining Well
recipe:
input: Iron Gear, Iron Ingot, Iron Pickaxe, Redstone
pattern: 131 101 121
item: Moss Stone Facade
gatherable: true
item: Moss Stone Hollow Facade
gatherable: true
item: Obsidian Transport Pipe
recipe:
input: Glass, Obsidian
pattern: 101 ... ...
item: Oil
gatherable: true
item: Oil Bucket
gatherable: true
item: Path Mark
recipe:
input: Cactus Green, Redstone Torch
pattern: 0.1 ... ...
item: Pipe Plug
gatherable: true
item: Pipe Sealant
gatherable: true
item: Programming Table
recipe:
input: Diamond Gear, Emerald, Obsidian, Redstone
pattern: 232 212 202
item: Pulsating Chipset
gatherable: true
item: Pump
recipe:
input: Mining Well, Tank
pattern: 10. ... ...
item: Quarry
recipe:
input: Diamond Gear, Diamond Pickaxe, Gold Gear, Iron Gear, Redstone
pattern: 343 232 010
item: Quartz AND Gate
gatherable: true
item: Quartz AND Gate (Autarchic Pulsar)
gatherable: true
item: Quartz AND Gate (Clock Timer)
gatherable: true
item: Quartz AND Gate (Redstone Fader)
gatherable: true
item: Quartz Chipset
gatherable: true
item: Quartz Fluid Pipe
gatherable: true
item: Quartz Kinesis Pipe
gatherable: true
item: Quartz OR Gate
gatherable: true
item: Quartz OR Gate (Autarchic Pulsar)
gatherable: true
item: Quartz OR Gate (Clock Timer)
gatherable: true
item: Quartz OR Gate (Redstone Fader)
gatherable: true
item: Quartz Transport Pipe
recipe:
input: Block of Quartz, Glass
pattern: 010 ... ...
item: Red Pipe Wire
gatherable: true
item: Redstone Board (Bomber)
recipe:
input: Paper, Redstone
pattern: 000 010 000
item: Redstone Board (Builder)
gatherable: true
item: Redstone Board (Butcher)
gatherable: true
item: Redstone Board (Carrier)
gatherable: true
item: Redstone Board (Crafter)
gatherable: true
item: Redstone Board (Delivery)
gatherable: true
item: Redstone Board (Farmer)
gatherable: true
item: Redstone Board (Harvester)
gatherable: true
item: Redstone Board (Knight)
gatherable: true
item: Redstone Board (Leaf Cutter)
gatherable: true
item: Redstone Board (Lumberjack)
gatherable: true
item: Redstone Board (Miner)
gatherable: true
item: Redstone Board (Picker)
gatherable: true
item: Redstone Board (Planter)
gatherable: true
item: Redstone Board (Pump)
gatherable: true
item: Redstone Board (Shovelman)
gatherable: true
item: Redstone Board (Stripes)
gatherable: true
item: Redstone Board (Tank)
gatherable: true
item: Redstone Chipset
gatherable: true
item: Redstone Comp Chipset
gatherable: true
item: Redstone Crystal
gatherable: true
item: Redstone Engine
recipe:
input: Glass, Oak Wood Planks, Piston, Wood Gear
pattern: 111 .0. 323
item: Refinery
recipe:
input: Diamond Gear, Redstone Torch, Tank
pattern: 121 202 ...
item: Requester
recipe:
input: Chest, Iron Gear, Iron Ingot, Piston, Redstone
pattern: 232 101 242
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot
gatherable: true
item: Robot (Bomber)
recipe:
input: Diamond Chipset, Iron Ingot, Redstone Crystal
pattern: 111 121 0.0
item: Robot (Builder)
gatherable: true
item: Robot (Butcher)
gatherable: true
item: Robot (Carrier)
gatherable: true
item: Robot (Crafter)
gatherable: true
item: Robot (Delivery)
gatherable: true
item: Robot (Farmer)
gatherable: true
item: Robot (Harvester)
gatherable: true
item: Robot (Knight)
gatherable: true
item: Robot (Leaf Cutter)
gatherable: true
item: Robot (Lumberjack)
gatherable: true
item: Robot (Miner)
gatherable: true
item: Robot (Picker)
gatherable: true
item: Robot (Planter)
gatherable: true
item: Robot (Pump)
gatherable: true
item: Robot (Shovelman)
gatherable: true
item: Robot (Stripes)
gatherable: true
item: Robot (Tank)
gatherable: true
item: Sandstone Fluid Pipe
gatherable: true
item: Sandstone Kinesis Pipe
gatherable: true
item: Sandstone Transport Pipe
recipe:
input: Glass, Sandstone
pattern: 101 ... ...
item: Stirling Engine
recipe:
input: Cobblestone, Glass, Piston, Stone Gear
pattern: 000 .1. 323
item: Stone Facade
gatherable: true
item: Stone Fluid Pipe
gatherable: true
item: Stone Gear
recipe:
input: Cobblestone, Wood Gear
pattern: .0. 010 .0.
item: Stone Hollow Facade
gatherable: true
item: Stone Kinesis Pipe
gatherable: true
item: Stone Transport Pipe
recipe:
input: Glass, Stone
pattern: 101 ... ...
item: Stripes Transport Pipe
recipe:
input: Glass, Gold Gear
pattern: 101 ... ...
item: Tank
recipe:
input: Glass
pattern: 000 0.0 000
item: Template
recipe:
input: Ink Sac, Paper
pattern: 111 101 111
item: Void Fluid Pipe
gatherable: true
item: Void Transport Pipe
recipe:
input: Glass, Ink Sac, Redstone
pattern: 102 ... ...
item: Wood Gear
recipe:
input: Stick
pattern: .0. 0.0 .0.
item: Wooden Fluid Pipe
gatherable: true
item: Wooden Kinesis Pipe
gatherable: true
item: Wooden Transport Pipe
recipe:
input: Glass, Oak Wood Planks
pattern: 101 ... ...
item: Wrench
recipe:
input: Iron Ingot, Stone Gear
pattern: 0.0 .1. .0.
item: Yellow Pipe Wire
gatherable: true
item: Zone Planner
recipe:
input: Diamond Gear, Empty Map, Gold Gear, Iron Ingot, Redstone
pattern: 343 212 303
+1
View File
@@ -30,6 +30,7 @@
"coffee-script": "^1.9.2", "coffee-script": "^1.9.2",
"crafting-guide": "^3.0.0", "crafting-guide": "^3.0.0",
"crafting-guide-common": "^1.3.0", "crafting-guide-common": "^1.3.0",
"fs-extra": "^0.30.0",
"grunt": "^0.4.5", "grunt": "^0.4.5",
"grunt-contrib-clean": "^1.0.0", "grunt-contrib-clean": "^1.0.0",
"grunt-contrib-compress": "^1.2.0", "grunt-contrib-compress": "^1.2.0",
+526
View File
@@ -0,0 +1,526 @@
#!/usr/bin/env coffee
_ = require 'underscore'
fs = require 'fs-extra'
path = require 'path'
util = require 'util'
# Global Data ##########################################################################################################
DEBUG = false
MOD = null
MOD_SCRIPT = null
WORLD_DIR = null
INDENT = 0
# Constants ############################################################################################################
MINETWEAKER_LOG = 'minetweaker.log'
ICON_DIR = path.join 'dumps', 'itempanel_icons'
ITEMPANEL_CSV = path.join 'dumps', 'itempanel.csv'
# Process Arguments ####################################################################################################
process.argv.shift() # coffee
process.argv.shift() # script file
while process.argv.length > 0
switch process.argv[0]
when '--world'
process.argv.shift()
WORLD_DIR = process.argv[0]
when '--mod'
process.argv.shift()
MOD_SCRIPT = process.argv[0]
process.argv.shift()
if not WORLD_DIR? then throw new Error '--world is required'
if not MOD_SCRIPT? then throw new Error '--mod is required'
# Classes ##############################################################################################################
class MinecraftId
constructor: (@mod, @name, @meta=null, @variant=null)->
@meta = null if not @meta or @meta in ['0', '*']
@meta = parseInt @meta
@meta = null if Number.isNaN @meta
compareTo: (other)->
return -1 unless other?
if @mod isnt other.mod
return if @mod < other.mod then -1 else +1
if @name isnt other.name
return if @name < other.name then -1 else +1
if @meta isnt other.meta
if not @meta? then return -1
if not other.meta? then return +1
return if @meta < other.meta then -1 else +1
if @variant isnt other.variant
if not @variant? then return -1
if not other.variant? then return +1
return if @variant < other.variant then -1 else +1
return 0
createVariant: (variant)->
return new MinecraftId @mod, @name, @meta, variant
equals: (other)->
return @compareTo(other) is 0
matches: (other)->
return false unless other?
return false unless @mod is other.mod
return false unless @name is other.name
return true if other.meta is null
return false unless @meta is other.meta
return true
toString: ->
if not @_string
@_string = "#{@mod}:#{@name}"
if @meta? then @_string += ":#{@meta}"
if @variant? then @_string += ":#{@variant}"
return @_string
# Helper Functions #####################################################################################################
addItem = (item)->
if not item? then throw new Error "cannot add null item"
MOD.items.push item
computePattern = (recipe, inputGrid)->
pattern = [['.', '.', '.'], ['.', '.', '.'], ['.', '.', '.']]
cells = _.compact _.flatten inputGrid
recipe.inputNames = (_.uniq (cell.item.displayName for cell in cells)).sort()
for row, rowIndex in inputGrid
for gridCell, columnIndex in row
continue unless gridCell?
itemNumber = recipe.inputNames.indexOf gridCell.item.displayName
if itemNumber >= 0
pattern[rowIndex][columnIndex] = "#{itemNumber}"
p = pattern
recipe.pattern = "#{p[0][0]}#{p[0][1]}#{p[0][2]} #{p[1][0]}#{p[1][1]}#{p[1][2]} #{p[2][0]}#{p[2][1]}#{p[2][2]}"
computeGridSize = (grid)->
grid.width = grid.height = 0
grid.rawHeight = grid.length
grid.rawWidth = 0
for row, rowIndex in grid
grid.rawWidth = Math.max grid.rawWidth, row.length
for cell, colIndex in row
continue unless cell?
grid.height = Math.max grid.height, rowIndex + 1
grid.width = Math.max grid.width, colIndex + 1
grid.isLarge = grid.width > 2 or grid.height > 2
computeSlug = (text)->
return null unless text?
result = text.toLowerCase()
result = result.replace /[^a-zA-Z0-9_]/g, '_'
result = result.replace /__+/g, '_'
result = result.replace /^_/, ''
result = result.replace /_$/, ''
return result
debugLog = (text)->
return unless DEBUG
console.error text
findItem = (search)->
for item in MOD.items
matches = true
for field, value of search
if field is 'minecraftId'
if not item.minecraftId.equals(search.minecraftId)
matches = false
break
else if item[field] isnt value
matches = false
break
return item if matches
return null
lookUpItems = (itemIds)->
for row in itemIds
for gridCell in row
continue unless gridCell?
item = findItem minecraftId:gridCell.minecraftId
if not item?
console.error "could not find an item for id: #{gridCell.minecraftId}"
return null
gridCell.item = item
normalizeMinecraftId = (minecraftId)->
return minecraftId unless minecraftId.mod is 'ore'
entries = MOD.oreDict[minecraftId.toString()]
return minecraftId unless entries?
return minecraftId unless entries.length > 0
return entries[0]
normalizeRecipeGrid = (grid)->
result = grid
if grid.rawWidth is 2 and grid.rawHeight is 3
result = [
[ grid[0][0], grid[0][1], grid[1][0] ],
[ grid[1][1], grid[2][0], grid[2][1] ],
[ null, null, null ]
]
else if grid.rawWidth is 1 and grid.rawHeight is 3
result = [
[ grid[0][0], grid[1][0], grid[2][0] ],
[ null, null, null ]
[ null, null, null ]
]
else if grid.rawWidth is 1 and grid.rawHeight is 2
result = [
[ grid[0][0], grid[1][0], null ],
[ null, null, null ]
[ null, null, null ]
]
computeGridSize result
return result
parseMinecraftId = (minecraftId)->
match = /^([^:]*):([^:]*)(:([0-9*]*))?$/.exec minecraftId
return null unless match?
return new MinecraftId match[1], match[2], match[4]
parseRecipeInputs = (recipeType, text)->
allRows = []
currentRow = null
currentItem = ''
completeCurrentItem = ->
currentItem = currentItem.trim()
if currentItem isnt 'null'
match = currentItem.match /^ *([^ ]*)( \* ([0-9]+))?/
quantity = parseInt match[3]
if _.isNaN(quantity) then quantity = 1
if match?
currentRow.push(
minecraftId: normalizeMinecraftId parseMinecraftId match[1]
quantity: quantity
)
else
currentRow.push null
currentItem = ''
inputText = if recipeType is 'Shapeless' then text[0..text.length] else text[1..text.length - 2]
for c in inputText.split ''
if c is '['
currentRow = []
else if c is ']'
completeCurrentItem()
allRows.push currentRow
currentRow = null
else if c is ','
if currentRow?
completeCurrentItem()
else if c in ['<', '>']
# do nothing
else
if currentItem?
currentItem += c
if recipeType is 'Shapeless'
a = _.flatten allRows
allRows = [
[ a[0], a[1], a[4] ]
[ a[2], a[3], a[5] ]
[ a[6], a[7], a[8] ]
]
computeGridSize allRows
return allRows
# Stage Functions ######################################################################################################
copyImages = ->
for item in MOD.items
continue unless item.iconFile?
itemPath = path.join 'data', MOD.slug, 'items', item.slug
fs.ensureDir itemPath
fs.copySync item.iconFile, path.join(itemPath, 'icon.png'), clobber:true
discardNonModItems = ->
result = []
for item in MOD.items
if MOD.contains item
result.push item
MOD.items = result
loadModHelper = ->
MOD = require "./mods/#{MOD_SCRIPT}"
MOD.slug ?= MOD_SCRIPT
MOD.version ?= '1.0'
MOD.items ?= []
MOD.oreDict ?= {}
MOD.adjustRecipe ?= (recipe)-> return recipe
MOD.contains ?= (id)-> return true
MOD.correctItem ?= (item)-> # do nothing
MOD.makeCorrections ?= -> # do nothing
MOD.normalizeName ?= (item, index=1)-> return item.gameName
MOD.shouldNormalizeGrid ?= (item, grid)-> return false
makeCorrections = ->
for item in MOD.items
MOD.correctItem item
MOD.makeCorrections()
removeDuplicates = ->
result = []
lastDisplayName = null
for item in MOD.items
continue if item.displayName is lastDisplayName
result.push item
lastDisplayName = item.displayName
MOD.items = result
scanFurnaceRecipes = ->
fileText = fs.readFileSync path.join(WORLD_DIR, MINETWEAKER_LOG), 'utf-8'
for line in fileText.split '\n'
match = line.match /furnace.addRecipe\(<([^>]*)>, <([^>]*)>/
continue unless match?
outputId = parseMinecraftId match[1]
outputItem = findItem minecraftId:outputId
if not outputItem?
console.error "Skipping furnace recipe for #{match[1]} because no matching item could be found"
continue
inputId = parseMinecraftId match[2]
inputItem = findItem minecraftId:inputId
if not inputItem?
console.error "Skipping furnace recipe for #{match[1]} because input item #{match[2]} could not be found"
continue
recipe =
inputNames: [ inputItem.gameName, 'furnace fuel' ]
quantity: 1
extras: []
tools: [ 'Furnace' ]
pattern: '.0. ... .1.'
outputItem.recipes ?= []
outputItem.recipes.push recipe
scanIconFiles = ->
iconFiles = fs.readdirSync path.join WORLD_DIR, ICON_DIR
for fileName in iconFiles
match = fileName.match /^(.*?)(_([0-9]+))?\.png$/
continue unless match?
baseItem = findItem iconFileName:match[1]
if not baseItem?
console.error "Could not find item for icon file: #{fileName}"
continue
index = parseInt match[3]
index = if Number.isNaN(index) then 1 else index
if index is 1
item = baseItem
item.displayName = MOD.normalizeName baseItem, index
else
displayName = MOD.normalizeName baseItem, index
if displayName
item =
minecraftId: baseItem.minecraftId.createVariant index
gameName: baseItem.gameName
displayName: displayName
iconFileName: fileName
slug: computeSlug displayName
addItem item
else
console.error "Could not find item for icon file: #{fileName}"
item.iconFile = path.join WORLD_DIR, ICON_DIR, fileName
scanItemPanelCsv = ->
fileText = fs.readFileSync path.join(WORLD_DIR, ITEMPANEL_CSV), 'utf-8'
lines = fileText.split '\n'
lines.sort()
priorLine = null
for line, lineNumber in lines
continue if lineNumber is 0
continue if priorLine is line
match = line.match /^([^,]*),([^,]*),([^,]*),([^,]*),([^,]*)$/
continue unless match
item =
minecraftId: parseMinecraftId "#{match[1]}:#{match[3]}"
gameName: match[5]
iconFileName: match[5].replace(/:/g, '_')
item.displayName = MOD.normalizeName item
item.slug = computeSlug item.displayName
addItem item
priorLine = line
scanOreDict = ->
fileText = fs.readFileSync path.join(WORLD_DIR, MINETWEAKER_LOG), 'utf-8'
lines = fileText.split '\n'
index = 0
while true
break if index >= lines.length
line = lines[index]
index += 1
match = line.match /^Ore entries for <([^>]*)> :$/
continue unless match?
genericIdText = match[1]
while true
break if index >= lines.length
line = lines[index]
match = line.match /^ <([^>]*)>$/
break unless match?
index += 1
MOD.oreDict[genericIdText] ?= []
MOD.oreDict[genericIdText].push parseMinecraftId match[1]
scanRecipes = ->
fileText = fs.readFileSync path.join(WORLD_DIR, MINETWEAKER_LOG), 'utf-8'
for line in fileText.split '\n'
match = line.match /recipes.add(Shaped|Shapeless)\(<([^>]*)>( \* ([0-9]+))?, (.*)\);/
continue unless match?
recipeType = match[1]
outputId = parseMinecraftId match[2]
outputItem = findItem minecraftId:outputId
if not outputItem?
console.error "Ignoring recipe because there's no matching item: #{line}"
continue
quantity = parseInt match[4]
quantity = if _.isNaN(quantity) then 1 else quantity
inputGrid = parseRecipeInputs recipeType, match[5]
if MOD.shouldNormalizeGrid outputItem, inputGrid
inputGrid = normalizeRecipeGrid inputGrid
continue if inputGrid is null
recipe =
inputNames: []
quantity: quantity
extras: []
tools: if inputGrid.isLarge then ['Crafting Table'] else []
lookUpItems inputGrid
computePattern recipe, inputGrid
recipe = MOD.adjustRecipe recipe
if recipe?
outputItem.recipes ?= []
outputItem.recipes.push recipe
sortItems = ->
MOD.items.sort (a, b)->
if a.displayName isnt b.displayName
return if a.displayName < b.displayName then -1 else +1
return a.minecraftId.compareTo b.minecraftId
writeModVersionFile = ->
lines = ['schema: 1', '']
indent = 0
write = (lineText)->
for i in [0...indent]
lineText = ' ' + lineText
lines.push lineText
for item in MOD.items
write "item: #{item.displayName}"
indent++
if (not item.isGatherable? and not item.recipes?) or item.isGatherable
write 'gatherable: yes'
if item.recipes?
for recipe in item.recipes
write 'recipe:'
indent++
write "input: #{recipe.inputNames.join(', ')}"
write "pattern: #{recipe.pattern}"
if recipe.quantity isnt 1
write "quantity: #{recipe.quantity}"
if recipe.tools.length > 0
write "tools: #{recipe.tools.join(', ')}"
indent--
indent--
write ''
versionPath = path.join 'data', MOD.slug, 'versions', MOD.version
fs.ensureDirSync versionPath
fs.writeFileSync path.join(versionPath, 'mod-version.cg'), lines.join('\n'), encoding:'utf-8'
writeJsonDump = ->
versionPath = path.join 'data', MOD.slug, 'versions', MOD.version
fs.ensureDirSync versionPath
fs.writeFileSync path.join(versionPath, 'mod-version.json'), JSON.stringify(MOD.items, null, 4), encoding:'utf-8'
########################################################################################################################
loadModHelper()
scanItemPanelCsv()
scanIconFiles()
scanOreDict()
scanRecipes()
scanFurnaceRecipes()
discardNonModItems()
sortItems()
removeDuplicates()
makeCorrections()
writeModVersionFile()
writeJsonDump()
copyImages()
+26 -9
View File
@@ -1,23 +1,40 @@
#!/bin/bash #!/bin/bash
read -d '' USAGE <<END read -d '' USAGE <<END
USAGE: convert-nei-dump <source> <mod_slug> <mod_version> USAGE: convert-dump <source> <mod_slug> <mod_version>
Converts output from NEI dump files into a format which can be used by Converts output from various dump files into a format which can be used by
Crafting Guide. In particlar, this script looks for the "Item Panel" dump Crafting Guide. BEFORE RUNNING THIS SCRIPT, YOU MUST FIRST CREATE THE
both in PNG and CSV formats and assumes they contain all the data for the NECESSARY DUMP FILES.
target mod.
Unfortunate, NEI doesn't generate enough information to fill in all the First, set up your Minecraft profile with the mod you want to dump as well
recipes for each item: only their names. Once this script has converted the as NEI and MineTweaker 3. Then, launch the game into a single player world
data, you will need to manually enter the missing content. and run the following console commands:
/mt oredict
/mt recipes
/mt recipes furnace
Then, open your inventory and click the "NEI Subsets" button at the top.
Right-click the "Mod" menu, and then left-click the one mod you want to
dump. This should change the icons displayed on the right to just those
belonging to that mod.
Now, click the "Options" button in the lower-right corner. Then click
"Tools" followed by "Data Dumps". Next to "Item Panel", click the center
button until it says "PNG" and then the left hand button until it says
"48x48". Finally, click the "Dump" button.
Next, click the center button on the "Item Panel" row until it says "CSV",
and then click "Dump" again.
You have now created all the dump files needed by this script.
<source> : the "dumps" directory where NEI dropped its content <source> : the "dumps" directory where NEI dropped its content
<mod_slug> : the slug of the mod being converted <mod_slug> : the slug of the mod being converted
<mod_version> : the version of the mod being converted <mod_version> : the version of the mod being converted
END END
SOURCE_DIR="$1"; shift SOURCE_DIR="$1"; shift
MOD_SLUG="$1"; shift MOD_SLUG="$1"; shift
MOD_VERSION="$1"; shift MOD_VERSION="$1"; shift
+73
View File
@@ -0,0 +1,73 @@
FACADE_PATTERN = /^Facade: ([^(]*)$/
GATE_PATTERN = /^.*(OR|AND|Basic) Gate$/
HOLLOW_FACADE_PATTERN = /^Facade: ([^(]*) \(item.Facade.state_hollow\)/
exports.contains = (item)->
return false if item.minecraftId.mod.indexOf('BuildCraft') is -1
return false if item.displayName.match /^tile/
return true if item.displayName.match /Stone( Hollow)? Facade/
return false if item.displayName.match /Facade/
return false if item.displayName.match /(Water|Oil) Spring$/
return true
exports.normalizeName = (item, index=1)->
name = item.gameName
if match = name.match FACADE_PATTERN
return "#{match[1]} Facade"
if match = name.match GATE_PATTERN
switch index
when 2 then return "#{name} (Autarchic Pulsar)"
when 3 then return "#{name} (Clock Timer)"
when 4 then return "#{name} (Redstone Fader)"
if match = name.match HOLLOW_FACADE_PATTERN
return "#{match[1]} Hollow Facade"
if name is 'Redstone Board'
switch index
when 1 then return "Redstone Board (Bomber)"
when 2 then return "Redstone Board (Builder)"
when 3 then return "Redstone Board (Butcher)"
when 4 then return "Redstone Board (Carrier)"
when 5 then return "Redstone Board (Crafter)"
when 6 then return "Redstone Board (Delivery)"
when 7 then return "Redstone Board (Farmer)"
when 8 then return "Redstone Board (Knight)"
when 9 then return "Redstone Board (Harvester)"
when 10 then return "Redstone Board (Leaf Cutter)"
when 11 then return "Redstone Board (Lumberjack)"
when 12 then return "Redstone Board (Miner)"
when 13 then return "Redstone Board (Picker)"
when 14 then return "Redstone Board (Planter)"
when 15 then return "Redstone Board (Pump)"
when 16 then return "Redstone Board (Shovelman)"
when 17 then return "Redstone Board (Stripes)"
when 18 then return "Redstone Board (Tank)"
if name is 'Robot'
switch index
when 1 then return "Robot (Bomber)"
when 2 then return "Robot (Builder)"
when 3 then return "Robot (Butcher)"
when 4 then return "Robot (Carrier)"
when 5 then return "Robot (Crafter)"
when 6 then return "Robot (Delivery)"
when 7 then return "Robot (Farmer)"
when 8 then return "Robot (Knight)"
when 9 then return "Robot (Harvester)"
when 10 then return "Robot (Leaf Cutter)"
when 11 then return "Robot (Lumberjack)"
when 12 then return "Robot (Miner)"
when 13 then return "Robot (Picker)"
when 14 then return "Robot (Planter)"
when 15 then return "Robot (Pump)"
when 16 then return "Robot (Shovelman)"
when 17 then return "Robot (Stripes)"
when 18 then return "Robot (Tank)"
return name
+53
View File
@@ -0,0 +1,53 @@
WOOD_TYPES = [ 'Oak Wood', 'Birch', 'Spruce', 'Jungle', 'Acacia Wood', 'Dark Oak' ]
exports.slug = 'minecraft'
exports.version = '1.7.10'
exports.contains = (item)->
return false if item.minecraftId.mod.indexOf('minecraft') is -1
return false if item.minecraftId.name in [ 'end_portal', 'portal', 'mob_spawner', 'monster_egg', 'spawn_egg' ]
return true
exports.correctItem = (item)->
item.isGatherable = true if item.gameName in [
'Coal', 'Diamond', 'Emerald', 'Lapis Lazuli', 'Nether Quartz', 'Redstone', 'Stone', 'Wheat', 'Wool'
]
item.isGatherable = true if item.minecraftId.name in [
'melon_block'
]
item.isGatherable = false if item.gameName in [
'Bottle o\' Enchanting', 'Command Block', 'Farmland', 'Lava', 'Water', 'Written Book'
]
exports.normalizeName = (item)->
name = item.gameName
switch item.minecraftId.name
when 'clay' then name = 'Clay (block)'
when 'clay_ball' then name = 'Clay (item)'
when 'filled_map' then name = 'Map (filled)'
when 'melon_block' then name = 'Melon (block)'
when 'netherbrick' then name = 'Nether Brick (item)'
when 'nether_brick' then name = 'Nether Brick (block)'
when 'planks'
index = item.minecraftId.meta || 0
name = "#{WOOD_TYPES[index]} Planks"
when 'stone_button' then name = 'Button (stone)'
when 'stone_pressure_plate' then name = 'Pressure Plate (stone)'
when 'wooden_button' then name = 'Button (wooden)'
when 'wooden_pressure_plate' then name = 'Pressure Plate (wooden)'
when 'wooden_slab'
index = item.minecraftId.meta || 0
name = "#{WOOD_TYPES[index]} Slab"
return name
exports.shouldNormalizeGrid = (item, grid)->
return true if item.gameName in [
'Bed', 'Bowl', 'Boat', 'Brewing Stand', 'Bucket', 'Cobblestone Slab', 'Diamond Boots', 'Diamond Helmet',
'Minecart', 'Oak Wood Slab', 'Stone Slab', 'Trapdoor', 'Weighted Pressure Plate (Heavy)',
'Weighted Pressure Plate (Light)'
]
return false