Skip to content

Commit a1888fd

Browse files
authored
v1.1 (#8)
* v1.1 init commit: - indent now 2 when using -i - added optional crafting recipe - replace HotV librarian reward * Switch to config system. Bump version, fixes... * more * tweaks * readme update * Re-organise directories, add pack.png to data pack output, replace exe builder with icon, catch more errors, readme images + tweaks * New build script and readme changes
1 parent feb689b commit a1888fd

29 files changed

+527
-229
lines changed

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,8 @@ dmypy.json
128128
# Pyre type checker
129129
.pyre/
130130

131-
# Babel output file
132-
babel.zip
131+
# VSCode
132+
*.code-workspace
133+
134+
# Babel output zips
135+
*.zip

README.md

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,58 @@
1-
# Babel Book Loot v1.0
2-
## A customisable pre-written book loot datapack for Minecraft
1+
![Logo](readme_images/logo.png)
32

4-
Babel Book Loot adds over 100 pre-written books to various loot tables in Minecraft. The default library of books is a collection of public domain fairy tales. You can customise the library by adding your own text files.
3+
![Demo](readme_images/babel.gif)
4+
5+
# Babel Book Loot v1.1
6+
## A customizable pre-written book loot data pack for Minecraft
7+
8+
Babel Book Loot adds over 100 pre-written books to various loot tables in Minecraft. The default library of books is a collection of public domain fairy tales. You can customize the library by adding your own books.
59

610
It was last updated for Minecraft 1.21.
711

812
## Quick-start
913

10-
Download [babel_v1.0.zip](https://github.com/JiFish/babel/releases/download/v1.0/babel_v1.0.zip) and place it in your Minecraft world's datapack directory.
11-
12-
If you don't want zombies dropping books, download [babel-no-zombie-loot_v1.0.zip](https://github.com/JiFish/babel/releases/download/v1.0/babel-no-zombie-loot_v1.0.zip) instead.
14+
Download [babel_v1.1.zip](https://github.com/JiFish/babel/releases/download/v1.1/babel_v1.1.zip) and place it in your Minecraft world's `datapacks` directory.
1315

14-
## How the datapack works in-game
16+
## How the data pack works in-game
1517

1618
Written books can be dropped by zombies if killed by a player, or fished up with a fishing rod. They can also be found in villages, stronghold libraries and woodland mansions in chests.
1719

1820
The generation of the book is determined randomly:
19-
- 69% Tattered Book
20-
- 30% Copy of a copy
21+
- 33% Tattered Book (not copyable)
22+
- 65% Copy of a copy (not copyable)
2123
- 1% Copy of original
2224
- <1% Original
2325

24-
## Customising Books
26+
If you are hero of the village, librarians throw a guaranteed copyable book.
27+
28+
## Pre-customized options
29+
30+
These data packs are variations with tweaked rules for obtaining the books:
31+
32+
- [babel-no-copying_v1.1.zip](https://github.com/JiFish/babel/releases/download/v1.1/babel-no-copying_v1.1.zip) - All books are "copy of a copy" and can't be duplicated. Also disables hero of the village reward.
33+
- [babel-no-zombie-loot_v1.1.zip](https://github.com/JiFish/babel/releases/download/v1.1/babel-no-zombie-loot_v1.1.zip) - Zombies don't drop books.
34+
- [babel-only-chests_v1.1.zip](https://github.com/JiFish/babel/releases/download/v1.1/babel-only-chests_v1.1.zip) - Books can only be found in chests. No zombie drops, fishing, or hero of the village reward.
35+
- [babel-recipe_v1.1.zip](https://github.com/JiFish/babel/releases/download/v1.1/babel-recipe_v1.1.zip) - Includes the below recipe to craft random books.
2536

26-
First get babel-builder-windows_v1.0.zip or babel-builder-python_v1.0.zip from the [releases page](https://github.com/JiFish/babel/releases).
37+
#### Optional recipe
2738

28-
Run `py babel.py` (or `babel.exe` in windows.) this will output `babel.zip`. Put that file in your Minecraft world's datapack directory. Run `babel.py -h` to see more options.
39+
If you got the version with the crafting recipe. Just combine 1 Book and Quill, 1 Soul Sand Block, 1 Chest, and 1 Emerald. (The recipe is shapeless.) This gives a chest which once placed will have a single random book inside.
40+
41+
![Recipe Image](readme_images/optional_recipe.png)
42+
43+
## Advanced customization using Babel Builder Tool
44+
45+
First get babel-builder-windows_v1.1.zip or babel-builder-python_v1.1.zip from the [releases page](https://github.com/JiFish/babel/releases).
46+
47+
Run `py babel.py` (or `babel.exe` in windows.) this will output `babel.zip`. Put that file in your Minecraft world's `datapacks` directory.
48+
49+
### Changing included books
2950

3051
Any books in the `books` directory will be included. You can add and remove books as you wish.
3152

32-
Book can be in JSON or YAML formats. Here is a simple example:
53+
Books can be in JSON or YAML formats. Here are some simple examples:
3354

34-
**sample_book.yaml**
55+
#### sample_book.yaml
3556
```
3657
title: Sample Book
3758
author: Some Author
@@ -41,7 +62,7 @@ pages:
4162
- This is page three.
4263
```
4364

44-
**sample_book.json:**
65+
#### sample_book.json
4566
```
4667
{
4768
"title": "Sample Book",
@@ -56,13 +77,13 @@ pages:
5677

5778
Minecraft accepts strictly non-valid JSON, so babel tries to too. Babel does it's best to read the books, but if it's having issues your best bet is to ensure the file is valid JSON.
5879

59-
### Advanced Books
80+
**Important note**: There is no easy way to find out how much text will fit on a page and Minecraft will allow pages longer than it can display. The simplest way to figure out the correct page lengths is to write the pages in minecraft itself, then copy the text out. [Text2Book](https://thewilley.github.io/Text2Book/) can assist you with splitting up your text.
6081

61-
You can do more advanced stuff with books if you need it.
82+
**If you've made book files and the text is in the public domain, please consider submitting them back here!**
6283

6384
#### Colors, formatting, etc.
6485

65-
Your pages can be in [Raw JSON text format](https://minecraft.wiki/w/Raw_JSON_text_format) e.g.
86+
Your book pages can be in [Raw JSON text format](https://minecraft.wiki/w/Raw_JSON_text_format) e.g.
6687

6788
```
6889
{
@@ -74,7 +95,7 @@ Your pages can be in [Raw JSON text format](https://minecraft.wiki/w/Raw_JSON_te
7495
}
7596
```
7697

77-
#### Optional parameters
98+
#### Optional book parameters
7899

79100
Book files can contain the following optional parameters:
80101
- `weight` - The chance this book will be selected vs others in the table. Default is `1`, so a value of `2` would mean the book is twice as likely to be selected.
@@ -104,62 +125,47 @@ An example using all optional parameters:
104125
}
105126
```
106127

107-
### Submitting books
108-
If you've made some books and the text is in the public domain, please consider submitting them back here!
109-
110-
### Default library
111-
The default collection of books was sourced from Project Gutenberg. https://www.gutenberg.org/
112-
113-
### Updating books from v0.5
128+
#### Updating books from v0.5
114129
If you already have books in the v0.5 format, you can update them by running `update_books.py`. The books directory must only contain v0.5 format books. The script will also overwrite the originals, so keep a backup.
115130

116-
## Advanced Customisation
117-
### Altering where books will be found
118-
You can disable various book drops using command line options. Use `babel.py -h` to see the complete list. An example where zombies do not drop books:
119-
```
120-
babel.py -d zombie
121-
````
122-
123-
You can add books to other loot tables using type `minecraft:loot_table` and value `babel:books`.
124-
125-
### Dealing with datapack conflicts
126-
If any of your other datapacks modify loot tables used by babel, it might be possible to create a compatible pack. To do this, replace the loot tables in the `base_loot_tables` with the ones from the conflicting datapack. This isn't guaranteed to work, and won't if the tables are much different from expected.
131+
### Changing other pack settings
127132

128-
### For use making your own datapacks
129-
If you just want to generate the loot table without the surrounding files, try:
130-
```
131-
build_loottable.py > books.json
132-
```
133+
You can disable various loot drops, change generation chances, and make other customizations by editing `config.yaml`.
133134

134135
### Full argument list:
135136
```
136-
usage: babel.py [-h] [-v] [-d {fishing,village,mansion,stronghold,zombie}]
137-
[-i] [-!] [filename]
137+
usage: babel.py [-h] [-v] [-!] [-i] [-a] [filename]
138138
139139
positional arguments:
140-
filename Optional output zip filename. (default: babel.zip)
140+
filename Configuration filename. (default: config.yaml)
141141
142142
optional arguments:
143143
-h, --help show this help message and exit
144144
-v, --version show program's version number and exit
145-
-d {fishing,village,mansion,stronghold,zombie}
146-
Disable adding books to the given loot tables. Can be
147-
repeated to disable more than one.
148-
-i, --indent Indent output JSON files.
149-
-!, --no-wait Don't wait for user input when finished. Triggered
150-
automatically by using any other argument. (Windows
151-
version only.)
145+
-!, --no-wait Don't wait for user input when finished. (Windows version only.)
146+
-i, --indent Indent output json files. Overrides config field.
147+
-a, --append-version Append babel version number to output filename.
152148
```
153149

150+
## Use with other data packs
151+
152+
### Using as part of your own data packs
153+
You can add books to other loot tables using type `minecraft:loot_table` and value `babel:books`.
154+
155+
If you just want to generate the loot table without the surrounding files, try running: `py build_loottable.py > books.json`
156+
157+
### Dealing with data pack conflicts
158+
If any of your other data packs modify loot tables used by babel, it might be possible to create a compatible pack. To do this, replace the loot tables in the `data/base_loot_tables` with the versions from the conflicting data pack. Then make sure this data pack is loaded before the conflicting one. This isn't guaranteed to work, and won't if the tables are much different from expected.
159+
154160
## Comments, suggestions or contributions?
155161
Please use the Issue Tracker on GitHub, or send me a tweet [@JiFish](https://twitter.com/intent/tweet?text=.@JiFish) or Toot [@joe@social.jifish.co.uk](https://social.jifish.co.uk/@joe).
156162

157-
## Copyright & use in your own datapacks
158-
Assuming the books are your own work, loot tables outputted by babel belong to you. You can use them freely in your own datapack. A credit is very appreciated, but not required.
163+
## Copyright & use in your own data packs
164+
Assuming the books are your own work, loot tables outputted by babel belong to you. You can use them freely in your own data pack. A credit is very appreciated, but not required.
159165

160-
Books in the `books` directory are in the public domain. The `books.json` file created from them is also in the public domain.
166+
Books in the `books` directory are in the public domain, sourced from [Project Gutenberg](https://www.gutenberg.org/). The `books.json` file created from them is also in the public domain.
161167

162-
The babel tool and datapack is copyright Joseph Fowler.
168+
The babel tool and data pack is copyright Joseph Fowler.
163169

164170
## Disclaimer
165171

babel.gif

5.75 MB
Loading

babel.ico

66.1 KB
Binary file not shown.

babel.py

Lines changed: 85 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,106 @@
1+
# By Joseph "JiFish" Fowler. All rights reserved.
2+
13
import argparse
24
import sys
5+
import yaml;
6+
import os;
37
from build_datapack import *
8+
from build_loottable import *
49

5-
isCompiled = getattr(sys, 'frozen', False)
6-
isUsingDefaults = (len(sys.argv) < 2)
7-
validLootTableList = ['fishing', 'village', 'mansion', 'stronghold', 'zombie']
8-
greeting = "Babel Book Loot Generator, v1.0%s" % (' (Windows)' if isCompiled else '')
9-
10-
def restricted_float(x):
11-
error = "%r not a value between 0.0 and 1.0"
12-
try:
13-
x = float(x)
14-
except ValueError:
15-
raise argparse.ArgumentTypeError(error % x)
10+
def loadAndValidateYaml(yamlFilePath):
11+
# Load the YAML file
12+
with open(yamlFilePath, 'r') as file:
13+
data = yaml.safe_load(file)
14+
15+
# Define the required fields and their types
16+
requiredFields = {
17+
'output-filename': str,
18+
'books-path': str,
19+
'add-crafting-recipe': bool,
20+
'add-fishing-loot': bool,
21+
'add-village-loot': bool,
22+
'add-mansion-loot': bool,
23+
'add-stronghold-loot': bool,
24+
'add-zombie-drop': bool,
25+
'replace-hero-of-the-village-gift': bool,
26+
'indent-output': bool,
27+
'copy-of-copy-chance': float,
28+
'copy-of-original-chance': float,
29+
'original-chance': float,
30+
}
31+
32+
# Check for unrecognized fields
33+
for field in data:
34+
if field not in requiredFields:
35+
raise ValueError(f"Unrecognized field: {field}")
36+
37+
# Validate the fields
38+
for field, fieldType in requiredFields.items():
39+
if field not in data:
40+
raise ValueError(f"Missing required field: {field}")
41+
42+
# Floats can also be ints, convert now
43+
if type(data[field]) == int:
44+
data[field] = float(data[field])
45+
46+
value = data[field]
47+
if not isinstance(value, fieldType):
48+
raise TypeError(f"Incorrect type for field '{field}'. Expected {fieldType.__name__}, got {type(value).__name__}.")
49+
50+
# For float fields, ensure they are between 0 and 1
51+
if fieldType is float and not (0 <= value <= 1):
52+
raise ValueError(f"Field '{field}' must be between 0 and 1. Got {value}.")
53+
54+
return data
1655

17-
if x < 0.0 or x > 1.0:
18-
raise argparse.ArgumentTypeError(error % x)
19-
return x
56+
isCompiled = getattr(sys, 'frozen', False)
57+
version = "v1.1%s" % (' (Windows)' if isCompiled else '')
2058

2159
parser = argparse.ArgumentParser()
22-
parser.add_argument('filename', help='Optional output zip filename. (default: %(default)s)', nargs='?', default='babel.zip')
23-
parser.add_argument('-v', '--version', action='version', version=greeting)
24-
parser.add_argument('-d', dest="loottable", default=[], action='append', choices=validLootTableList,
25-
help='Disable adding books to the given loot tables. Can be repeated to disable more than one.')
26-
# parser.add_argument('--gen2', action='store', type=restricted_float, default=0.3, metavar="CHANCE",
27-
# help="Chance a book will be marked as a 'Copy of a copy', between 0.0 and 1.0. (default: %(default)s)")
28-
# parser.add_argument('--gen1', action='store', type=restricted_float, default=0.01, metavar="CHANCE",
29-
# help="Chance a book will be marked as a 'Copy of original', between 0.0 and 1.0. (default: %(default)s)")
30-
# parser.add_argument('--gen0', action='store', type=restricted_float, default=0.003, metavar="CHANCE",
31-
# help="Chance a book will be marked as an 'Original', between 0.0 and 1.0. (default: %(default)s)")
32-
#parser.add_argument('-l', '--loottable', action='store_true',
33-
# help="Don't build the datapack, instead just output the loot table. The default filename is books.json.")
34-
parser.add_argument('-i', '--indent', help='Indent output JSON files.', action='store_true')
60+
parser.add_argument('filename', help='Optional config filename. (default: %(default)s)', nargs='?', default='config.yaml')
61+
parser.add_argument('-v', '--version', action='version', version=version)
62+
parser.add_argument('-i', '--indent', action='store_true', help="Indent output json files. Overrides config field.")
63+
parser.add_argument('-a', '--append-version', action='store_true', help="Append babel version number to output filename.")
64+
3565
if isCompiled:
3666
parser.add_argument('-!', '--no-wait', action='store_true',
37-
help="Don't wait for user input when finished. Triggered automatically by using any other argument.")
38-
args = parser.parse_args()
67+
help="Don't wait for user input when finished.")
68+
# Handle windows style help arg
69+
if len(sys.argv) == 2 and sys.argv[1] == '/?':
70+
sys.argv[1] = '--help'
3971

40-
if args.indent:
41-
indent = 4
42-
else:
43-
indent = None
72+
args = parser.parse_args()
4473

45-
print("\n"+greeting)
46-
print("="*len(greeting)+"\n")
74+
print("")
75+
print("░█▀▄░█▀█░█▀▄░█▀▀░█░░░░░█▀▄░█▀█░█▀█░█░█░░░█░░░█▀█░█▀█░▀█▀")
76+
print("░█▀▄░█▀█░█▀▄░█▀▀░█░░░░░█▀▄░█░█░█░█░█▀▄░░░█░░░█░█░█░█░░█░")
77+
print("░▀▀░░▀░▀░▀▀░░▀▀▀░▀▀▀░░░▀▀░░▀▀▀░▀▀▀░▀░▀░░░▀▀▀░▀▀▀░▀▀▀░░▀░ " + version)
78+
print('By JiFish. email: %s' % 'ku.oc.hsifij@eoj'[::-1])
79+
print("")
4780

48-
if isUsingDefaults:
49-
print("Using default configuration, for more options try %s -h\n" % sys.argv[0])
81+
print("Using configuration: %s.\n" % args.filename)
5082

5183
try:
52-
from build_loottable import loottable
53-
print ("Found %d books." % len(loottable['pools'][0]['entries']))
84+
config = loadAndValidateYaml(args.filename)
85+
86+
# indent arg overrides config field
87+
if args.indent:
88+
config['indent-output'] = True
89+
90+
# Append version alters 'output-filename'
91+
if args.append_version:
92+
filename, extension = os.path.splitext(config['output-filename'])
93+
config['output-filename'] = filename + '_' + version + extension
94+
95+
loottable = buildLootTable(config)
5496

55-
print ("Building datapack...")
56-
buildDatapack(args.filename, args.loottable, loottable, indent=indent)
57-
print ("\nDatapack build complete! Copy %s to your world's datapack directory." % args.filename)
97+
print ("\nBuilding data pack...")
98+
buildDatapack(config, loottable, version)
99+
print ("Data pack build complete!\n\nCopy %s to your world's 'datapacks' directory." % config['output-filename'])
58100

59101
except Exception as e:
60102
print("\nError: "+str(e))
61103

62104
finally:
63-
if isCompiled and isUsingDefaults:
105+
if isCompiled and not args.no_wait:
64106
input("\nPress ENTER or close this window.")

0 commit comments

Comments
 (0)