The DevTool Commands¶
Every /lcdev command, what each argument means, and what it does to your world.
This page documents the companion mod, not Lost Cities
/lcdev comes from The Lost Cities - DevTool, described here as of 3.1.2-7.5, the file for Lost Cities 7.5.1 to 7.5.6. 3.0.0, the file for 7.4.12, is no longer updated. Lost Cities' own commands are on Testing and Debugging Commands. Nothing here is a claim about Lost Cities' behaviour, so it carries no verification chips: it describes a tool this wiki ships.
Everything at a glance¶
Every /lcdev command needs permission level 2. That is the operator level, which
a single-player world gets with cheats enabled and a server gives with op. It is a
tool for building a pack, not a feature for players: it teleports between dimensions,
writes tens of thousands of blocks, and reads and writes files beside your world.
| Command | What it is for |
|---|---|
/lcdev report |
What the generator chose for the chunk you are standing in |
/lcdev key <name> |
What a profile key means, its section, type, range and default |
/lcdev char <character> |
What a palette character resolves to here |
/lcdev block <id> |
Which characters produce a given block here |
/lcdev in <asset> char <character> |
The same lookup inside one named asset |
/lcdev in <asset> block <id> |
The same, in reverse, inside one named asset |
/lcdev conditions |
Every Condition loaded, and how many entries each holds |
/lcdev condition <name> |
One Condition in full: each entry's value, share and test |
/lcdev workshop go |
Teleport to the workshop dimension |
/lcdev workshop leave |
Go back where you ran go, or to world spawn if nothing was recorded |
/lcdev workshop rows |
Every catalogue row, each one a place to click |
/lcdev workshop here |
Which plot you are standing on and what it compiles into |
/lcdev workshop build |
Lay the catalogue out, or repaint it |
/lcdev workshop grow <row> <plots> |
Make a row longer, or lay out one that is empty |
/lcdev workshop sync |
Find settings files the catalogue has no plot for, and stray keys |
/lcdev workshop clear [confirm [anyway]] |
Empty every plot, after a backup |
/lcdev plot get [key] |
What this plot's settings say |
/lcdev plot keys |
Every setting this plot accepts, and what each does |
/lcdev plot file |
Where this plot's settings file is, click to copy |
/lcdev plot resolve <dx> <dz> <level> |
The settings that apply to one chunk on one level |
/lcdev plot set <key> <value> |
Set a value for the whole plot |
/lcdev plot setchunk <dx> <dz> <key> <value> |
Set it for one chunk of the plot |
/lcdev plot setlevel <level> <key> <value> |
Set it for one level of the plot |
/lcdev plot clear <key> |
Remove a key from this plot |
/lcdev plot show |
Draw where each level starts, on the walkway |
/lcdev plot hide |
Rub those markers out |
/lcdev mark <key> <value> |
Attach a palette key to the block you are looking at |
/lcdev export <name> [plot] [notags] [-f] |
Compile the workshop, or one plot, into a datapack |
/lcdev import <worldstyle> [keep] [run] |
Paste a loaded pack into the workshop |
On a server¶
Safe to use, with three caveats.
| A client does not need the mod | The mod declares IGNORE_ALL_VERSION, so a vanilla client can join a server running it. Only the Lost Cities menu fixes are client-side, and those are guarded to the client, so a dedicated server never loads them |
| Output goes to whoever asked | Command replies are not broadcast to other operators, so two people can work without filling each other's chat |
| Two people editing one plot | The settings are files, written per command with no locking, so the last write wins. Different plots are fine; the same plot at the same moment is not |
build, export and import do their work in one go on the server thread, so a
large catalogue is a visible pause rather than a hang. The workshop is one shared
dimension like any other, so two people building in it see each other's work.
The three words that are not obvious¶
These three appear across plot resolve, plot setchunk and plot setlevel, and
none of them mean what a coordinate usually means.
| Argument | It is not | It is | Example |
|---|---|---|---|
dx |
A world X coordinate | Chunks east from this plot's own corner, starting at 0 | On a 2x3 plot, dx is 0 or 1 |
dz |
A world Z coordinate | Chunks south from this plot's own corner, starting at 0 | On a 2x3 plot, dz is 0, 1 or 2 |
level |
A Y coordinate | A building level. 0 is the ground floor, -1 is the first cellar, 2 is the second floor above ground |
-32 to 128 are accepted |
A plot's corner is its lowest x and lowest z chunk, which is the corner nearest the
origin for the building rows and the far corner for the infrastructure rows, since
those grow west. /lcdev workshop here prints the corner so you never have to work
it out.
So the command that prompted this page:
/lcdev plot resolve 1 1 1
reads as "on the plot I am standing on, show me the settings that apply to the chunk one east and one south of its corner, on the first floor above ground". It changes nothing. It answers the question "which of my four overlapping settings actually wins here".
How settings fold together¶
A plot can say something once and have it apply everywhere, or say it again for one chunk or one level. Four scopes, and the most specific wins:
plot every chunk, every level
plot.levels[n] every chunk, that level
chunks[dx,dz] that chunk, every level
chunks[dx,dz].levels[n] that chunk, that level
Each scope stores only what differs from the one above it, so the common case, every building in a 2x2 block sharing a floor count so the whole thing generates as one structure, is what you get by saying it once.
| To say | Use |
|---|---|
| This building is 4 storeys | /lcdev plot set floors 4 |
| The north-east chunk of it is 6 | /lcdev plot setchunk 1 0 floors 6 |
| The ground floor everywhere uses a different palette | /lcdev plot setlevel 0 palette part |
| Which of those applies to chunk 1,0 on the ground floor | /lcdev plot resolve 1 0 0 |
One setting does not fold this way
conversions is a table rather than a value, so a narrower scope adds to it
instead of replacing it, and the pack sits underneath the plot as a fifth scope.
See conversions, and the scope it belongs to.
The workshop¶
Getting there¶
/lcdev workshop build
/lcdev workshop go
build paints the catalogue floors and is safe to run repeatedly: the same
catalogue produces the same plots in the same colours, so it repaints rather than
duplicating. go teleports you in.
/lcdev workshop leave brings you back. It returns you to where you ran go,
recorded on the player before the teleport, so it survives a logout. Running go
again while already in the workshop does not overwrite that, which means you cannot
strand yourself by using it twice. With nothing recorded, because you reached the
workshop some other way, it sends you to world spawn rather than to a respawn point:
a respawn point is a bed that may have been broken since.
Finding your way around¶
/lcdev workshop rows lists every row that is laid out, grouped by family, each one
a clickable teleport to its first plot. /lcdev workshop here describes the plot
under your feet: its corner, which variation of its row it is, how many variations
that row allows, and whether it compiles into a city style or the world style.
Adding plots¶
There is nothing to add. Every type of plot the format supports already has a row, generated from the codec keys the target version declares, so a type you cannot find is a type Lost Cities does not have. What you add is more plots of a type you already have:
/lcdev workshop grow building/1x1 24
/lcdev workshop grow multibuilding/4x6 6
Rows start at eight plots. Growing one lays out more and repaints, and an import grows whatever it needs by itself. Rows only ever get longer, because shortening one would move every plot after it and orphan whatever was built there.
Two rows behave differently on purpose:
| Row | Behaviour | Why |
|---|---|---|
The three monorail/ rows |
Stay at one plot, and grow refuses |
Their codec takes a single name. A list there is not a longer row: Lost Cities reads it as no value and uses its own default part |
multibuilding/ above 3x3 |
Declared with no plots until grown | A row reserves its band whether or not it holds plots, so growing one moves nothing that already exists. What an empty row does not have is a painted floor, and laying out every footprint up to 10x10 would paint several thousand chunks of it for shapes most packs never use |
Settings files the catalogue cannot see¶
/lcdev workshop sync
Values never need syncing. Every command loads a plot's settings off disk when it is asked, so a number changed in a text editor is already what the next export compiles. Nothing has to be run first.
What can disagree is whether the workshop can see the file at all. A settings file
names a plot, a plot belongs to a row, and a row lays out a fixed number of plots.
Write building/1x1/20.json5 into a row holding eight and nothing is wrong with the
file: it describes a plot the catalogue does not lay out, so every command walking the
catalogue steps past it, and the export writes a pack without it in silence.
Sync walks the files rather than the plots, which is the only direction that can see one the other does not have. It grows rows to cover what it finds, repaints only if something grew, and reports four things:
| Reported | What is said about it |
|---|---|
| A file naming a plot its row had no room for | How far that row grew to cover it |
| A file naming a row the catalogue does not have | The file, and the row is left alone |
| A file that could not be read | The parse error |
| A key the plot has no use for | The key, at whatever depth it sits |
That last one is reported nowhere else. floor where floors was meant is ignored
everywhere and complained about by nothing, so it gives a one-storey building and no
error. Sync finds it inside a chunk or level scope as well as beside them.
A monorail row stays at one plot however many files name it, since a list where the
codec takes a single name is dropped for the default part rather than read as a longer row. No row grows past
512 plots either way, so a stray building/1x1/99999.json5 reports the file instead of
laying out a hundred thousand plots and painting a floor for each.
How large a multibuilding can be¶
Ten chunks square, and that is Lost Cities' limit rather than the DevTool's. The
world style tiles the world into squares of areasize chunks and places each
multibuilding inside one, using random(areasize - dimx + 1). A footprint wider
than its area makes that bound zero or negative and the mod throws, so
areasize is the ceiling. The shipped world style uses 10, which is where the
catalogue stops.
multisettings on the World Style page
has the full table. Two of its keys are easy to misread: minimum and maximum are
how many multibuildings are attempted per area, not how large one may be, so
raising them puts more buildings in the world and does nothing about their size.
An export whose largest footprint is wider than the default area widens areasize
in the world style it writes. With the catalogue stopping at 10 that never triggers
today, and it is there so a larger catalogue cannot quietly produce a pack that
throws.
Starting again¶
An import fills the plots its pack needs and leaves every other plot alone, because somebody may have built on those by hand. That has a consequence: importing a second city on top of a first leaves the first one's plots where they were, so the workshop holds both and an export writes both into one pack. The import counts those plots and says so.
/lcdev workshop clear
On its own this reports what emptying would cost, in plots and blocks, and changes
nothing. Adding confirm writes a full backup pack to
config/lostcitiesdevtool/backups/<timestamp>/ and then empties every plot.
What counts as a plot worth emptying is what is standing on it, read from the world rather than from its settings file. A plot holding blocks and no settings is still cleared, and a build taller than its settings describe is cleared to the top of the build rather than to the top of the asset.
The backup is a real pack, so /lcdev import puts it back once it is installed as a
datapack. If the backup cannot be written, the wipe stops rather than going ahead
without one; clear confirm anyway is the way past that, and it is two words deep
on purpose.
Two things survive a wipe. The core settings, because the namespace and pack name are yours rather than any imported city's, and the palette ledger, so the next export letters the same blocks the same way instead of producing a whole-file diff. Rows an import grew go back to their catalogue size.
Settings on a plot¶
Every plot command, mark and export <name> plot acts on the plot under you in
the workshop dimension, and refuses anywhere else.
/lcdev plot keys is the one to remember: it lists every setting that plot
accepts with an explanation of each, and the list differs by plot. A street plot has
no factor, because the codec behind it picks uniform random and has nowhere to put
a weight. A monorail plot has no variation index worth setting. The same text is
what tab completion shows and what is written as a comment into the settings file,
so the three cannot drift apart.
/lcdev plot set name tower
/lcdev plot set floors 3
/lcdev plot set tops 4,6
/lcdev plot set citystyles mycity,othercity
/lcdev plot clear tops
A list value is comma separated. /lcdev plot get with no key prints everything the
plot has; with a key it prints that one. /lcdev plot file gives you the path to the
file, which is the truth and is safe to edit by hand.
name is the one setting every plot has, because it names every file that plot
compiles into. Two plots cannot share it, and an export says so rather than
letting the second quietly replace the first. An import keeps the namespace off the
name, so mypack:tower becomes tower, unless two packs both call something
tower: then both keep their namespace, as mypack_tower and otherpack_tower,
and the import says which ones it had to rename.
The three settings a help line cannot hold¶
/lcdev plot keys explains every setting, and that text is deliberately not copied
here: it is generated from the same declarations that write the settings file's
comments and drive tab completion, so a fourth copy is a fourth thing that can drift.
Three settings carry behaviour a help line has no room for.
tagkeys, which of a block's NBT reaches the pack¶
An export reads what a block entity is carrying, because for some blocks that is the
whole asset: a command block without its command is nothing. It also reads what was
never meant to ship. A chest opened while building carries its inventory, and a chest
meant to generate loot carries a LootTableSeed, which pins one roll into every copy
in every world.
| Value | Kept |
|---|---|
| unset | Everything the block carries |
CustomName |
Only CustomName |
!Items |
Everything except Items |
Base.Color |
Only that key, reached inside the Base compound |
One bare path anywhere makes the whole list a keep-list, and ! then only subtracts
from it. Cancelling the last keep-rule leaves a list that keeps nothing, rather than
flipping into a drop-list that keeps everything.
Set on the front desk it is the pack's rule, and a plot naming the same key again
overrides it. That is the opposite way round from conversions below, because a filter
is a policy a plot has good reason to make an exception to.
/lcdev export mypack notags drops all of it for one export without changing a
setting. A backup written by clear confirm keeps tags whatever the last export was
told, because a backup exists to put things back as they were.
conversions, and the scope it belongs to¶
A conversion turns a block placed in the workshop into a different block in the pack. It is how you build with wool where the asset wants a command block: placing the command block would fire it, so a placeholder stands in and the export swaps it.
Conversions layer rather than replace, which is the one exception to how settings fold together above. They resolve pack, then plot, then level, then chunk, then that chunk's level, and each scope adds to what came before or overrides one entry of it. A chunk wanting one extra mapping does not have to restate the plot's whole table to keep it.
The pack is the base and the narrower scope wins. A pack-wide mapping nothing can override would not be a default.
tagkeys deliberately does not layer. It resolves, so the narrowest list is the one
that reads. Concatenating a plot's list with a chunk's would put !Items at one scope
and Items at another, fighting in an order nobody can see.
A single block is /lcdev mark, not a conversion.
source, the namespace a plot came from¶
Written by an import, holding the namespace that plot's asset was read from. Nothing reads it but the export, which carries that namespace's licence statement into the pack it writes. A plot built by hand has none, and clearing the key stops an export saying the content came from there. See Licences in a Pack.
Seeing where the compiler will cut¶
/lcdev plot show
/lcdev plot hide
Levels are stacked, and the roof variations are stacked above them, which saves a
great deal of room and hides where one thing ends and the next begins. show draws
that in stained glass on the walkway around the plot, never inside it, so a
preview can never overwrite what you built. hide removes it.
Marking a single block¶
/lcdev mark loot chestloot
Attaches a palette key to the block you are looking at, so that one position becomes
its own palette entry. Accepts damaged, torch, variant, loot, mob and
frompalette.
loot and mob name a Condition, not a loot table and not an entity
/lcdev mark loot minecraft:chests/simple_dungeon is the natural guess and it is
wrong. Both keys name an asset under lostcities/conditions/, and Lost Cities ships
three: chestloot, easymobs and hardmobs.
Tab completion offers the loaded Condition names for these two keys, so the working value is there without having to know the word Condition at all. The other four marks take a block or a character, which you can see in front of you.
The load-time asset check refuses a value containing a slash, which catches a loot
table path. It cannot catch minecraft:zombie under mob: no slash, equally wrong.
See Conditions below for reading what one holds.
Marks do not survive a round trip yet
An export writes them. An import does not read them back into settings, so a
marked block returns from /lcdev import as the plain block.
Compiling and opening¶
/lcdev export mypack
/lcdev export mypack plot
/lcdev export mypack notags -f
Writes a complete datapack to config/lostcitiesdevtool/exports/<name>/, with the
profile beside it rather than inside it, because a profile is config and not
datapack. The name has to be one folder directly inside exports/ and may not start
with a dot. A settings value the export cannot read, such as "factor": "lots", stops
the export with the plot and the key named.
| Flag | Meaning |
|---|---|
-f |
Overwrite an existing export of the same name. Without it, that is an error |
plot |
Compile only the plot you are standing on, and leave the rest of the workshop out |
notags |
Ship no block NBT anywhere in the pack, whatever tagkeys says |
All three are optional and combine in any order, because the command tree carries a child for every flag not yet given rather than spelling out the six orderings by hand.
Nothing is written until the whole pack has passed the same checks the mod runs on a datapack at load time, so a pack that would fail in a world fails here instead, where the message can name the plot.
An export also writes the licence statements it is holding into
lostcities/license.txt in the pack it compiles. See Licences in a Pack.
Exporting one plot¶
export <name> plot is for lifting one building into a pack you are already writing.
It writes a fragment, not a pack. The plot's assets and the palette their characters resolve through, and no city style, no world style and no profile. A pack carrying a world style is installable, and installing a one-building world style generates a world made of that building, which is not what somebody exporting a single plot wanted. The command says as much when it finishes.
Standing off a plot is refused rather than quietly exporting everything, because a whole workshop written out under a name that says one plot is worse than an error.
The plot's own licence statement is carried, which is exactly the moment attribution should follow.
/lcdev import lostcities:standard
/lcdev import mypack:main keep
Pastes a loaded pack into the workshop. The pack has to be loaded with the world, which is what makes this work with nothing to point at: the mod's own content and every datapack in the world are equally importable.
| Argument | Meaning |
|---|---|
<worldstyle> |
A world style name. A bare name is looked for under lostcities: first, then in any single pack that has it. /lcdev import with no argument lists what is loaded |
keep |
Leave block conversions alone. Without it they run backwards, so a placeholder an export turned into a real block comes back as the placeholder |
run |
Let pasted command blocks fire. Without it they arrive holding their command but unable to run |
Both flags may be given together, in either order.
An import also reports what each namespace it read said about reuse, and records the namespace on every plot it fills so an export can carry that statement back out. See Licences in a Pack.
Blocks that carry NBT¶
A palette entry may hold a tag, a raw NBT compound, and Lost Cities places the
block already carrying it. That is the mechanism behind the command-block technique:
the block arrives holding its command and, with auto set, runs where it lands and
turns itself into whatever it was there to place. A pack built that way is mostly
command blocks.
An import carries the tag, and so does an export, so a command block keeps its command, a chest keeps its loot table and a spawner keeps its mob.
A pasted command block is left unable to fire unless you ask. A workshop is not a
world, and forty spawn commands going off while you are looking at a building is not
useful. run pastes them live.
A building whose middle repeats¶
A building may name several parts for the same level, and a band written as
range: "9,12" twice is the pack asking the generator to pick between them on every
level in that band. An import cannot roll dice, so it steps through the candidates by
level. That shows what the building is made of, and does the same thing every time,
so a pack always imports the same way.
What an import will not claim
Street parts that no city style names are pasted so you can see the roads, and
marked skip so an export leaves them out. A pack falling back to an asset is
not a pack containing it, and writing them back out would copy Lost Cities' own
roads into your namespace.
Asking about characters and blocks¶
/lcdev report
/lcdev char #
/lcdev block minecraft:gold_block
/lcdev in lostcities:building1 char #
report describes the chunk you are standing in: profile, world style, city style,
building, floor and cellar counts, and the part used on each level. char and
block look a palette up in both directions, after the merge, so the answer is what
the world will actually place rather than what one file says.
char and block search every asset the server has loaded, so on a modpack they
can match a great many. They print the first twelve and count the rest, and name up
to five assets that could not be built before counting those too. in <asset> is
how you ask about one of them on its own.
in <asset> asks the same question of one named asset instead of your surroundings,
which is how you check a building you are not standing in.
The asset comes before the character
/lcdev in <asset> char <c>, not the other way round. The character argument is
greedy so that a character can be anything, including a space, which means it has
to be the last thing on the line.
Conditions¶
/lcdev conditions
/lcdev condition lostcities:chestloot
loot and mob in a palette entry name a Condition: an asset under
lostcities/conditions/ holding a weighted list of values, each entry carrying its own
test for where it applies. Nothing in the game lists them, so before these two commands
the only way to learn a name was to open somebody else's pack and copy one out.
| Command | Prints |
|---|---|
/lcdev conditions |
Every Condition loaded, with how many entries each holds |
/lcdev condition <name> |
One in full: each entry's value, its weight as a share of the whole, and the test deciding where it applies |
The share is worked out rather than printed raw. A factor is a weight against its
siblings and not a chance, so a bare 8 beside a bare 20 invites the wrong reading.
Write the namespace, or take the completion
/lcdev condition reads its argument as a resource location, and an unqualified one
defaults to minecraft:. So condition chestloot looks for minecraft:chestloot
and answers No condition by that name, while condition lostcities:chestloot
finds it. Tab completion offers the qualified names, so taking one is the short way.
/lcdev mark loot chestloot is not affected. That argument is plain text and a bare
name there means lostcities:, the way every other asset reference does.
See Condition Reference for the format itself.
Palette characters, and how many there are¶
A pack needs one palette character per distinct block state. An export letters them out of a fixed pool and records what it gave to what in a ledger beside the world, so a second export letters the same block the same way instead of producing a whole-file diff.
The pool holds about 40,000 characters, against the roughly 26,000 block states Minecraft ships, so it is no longer the limit on anything. It keeps its old beginning, six ASCII punctuation marks then Greek then Cyrillic, so a ledger written by an earlier build carries on where it left off and nothing already lettered moves.
Nothing above U+FFFF is ever handed out, and that ceiling is Lost Cities' rather than
a preference. A palette is keyed by a single Java character and a slice row is read one
character at a time, so a code point above the plane would collapse every character in
its block of 1024 onto one key, and would take two positions inside a row and shift the
rest of the layer along.
The pool refuses five more things, each for a reason a row makes obvious:
| Refused | Why |
|---|---|
| Blanks | A row is positional, so a space that is not the air character is a cell nobody can see |
| Control, format and private use | No glyph |
| Combining marks | They attach to the cell before them |
| Right-to-left characters | The row renders in an order that is not the order of the blocks |
| Anything a normaliser would rewrite | NFD turns one character into two, and a row expects one |
Undefined code points are refused too, which is not theoretical: the Greek capitals run
straight through U+03A2, a reserved hole.
Running out is an error rather than a warning, and the message says what the count is made of. Writing air for a character that does not exist would ship a pack with holes in its buildings and mention it in one line among the others.
A tag is part of a cell's key
Filtering NBT re-keys every tagged block, so exporting once plainly and once with
notags claims two of the pool's characters for each of them, and the ledger never
gives one back. Against 40,000 that no longer matters, and it is why the ledger can
grow faster than the pack does.
See Palette: what counts as a valid character for the same rules from Lost Cities' side.
Why completion is fast on a big pack¶
Completing an asset or a world style name means listing what is loaded, and a client asks for that after every character typed. Doing the listing per keystroke on a server holding 911 Lost Cities assets cost 99 ms each time, which is close to two seconds to type one name.
The listing is read once per datapack load and reused, so the same completion costs
a fraction of a millisecond. It is tied to the load rather than to a timer, so
editing a file and running /reload rebuilds it and completion sees the change
immediately.
Profile keys¶
/lcdev key cityChance
Prints the section the key belongs to, its type, its range, its default and what it
does, read out of the mod's own config declarations. The section matters: a
profile key written in the wrong section is not an error and is not reported, it is
simply never read, and the setting silently does nothing. cityChance lives in
cities, not in lostcity.
See also¶
- Licences in a Pack, where the file goes and what an import and an export do with it
- Testing and Debugging Commands, for Lost Cities' own
/lostcities - Editing and Tooling, for the in-world part editor
- Condition Reference, for what
lootandmobname - Error Messages