luv

Workshop wiki

terrain.lisp

luvcraft/terrain.lisp

system luvcraft/core · 26 definitions · on GitHub

The little world: deterministic terrain, landmarks, and recorded edits.

A little-world-source is a pure function of its seed. Terrain heights and biome materials come from stable value noise, landmarks (rocks and trees) from coordinate hashes, and player edits from a sparse replayable overlay, so any chunk can be regenerated bit-identically on any thread.

in-package#:luvcraft
defclasslittle-world-source
seed:initarg:seed:initform121:readerlittle-world-source-seed
edits:initarg:edits:initform:readerlittle-world-source-edits
defunlittle-world-hash
sourcexz&optional
salt0

A stable coordinate hash for terrain readings and discrete features.

let
value
logand#xffffffff
+
little-world-source-seedsource
*x374761393
*z668265263
*salt2246822519
setfvalue
logand#xffffffff
*
logxorvalue
ashvalue-13
1274126177
logand#xffffffff
logxorvalue
ashvalue-16
defunlittle-world-hash-reading
sourcexzsalt
-
*2.0d0
/
little-world-hashsourcexzsalt
#xffffffff
1.0d0
defunsmooth-little-world-reading
reading
*readingreading
-3.0d0
*2.0d0reading
defuninterpolate-little-world-reading
leftrightamount
+left
*
-rightleft
amount
defunlittle-world-value-noise
sourcexzperiod&optional
salt0

Sample deterministic smooth value noise at integer world position X,Z.

check-typeperiod
real
0
*
let*
sample-x
/x
coerceperiod'double-float
sample-z
/z
coerceperiod'double-float
cell-x
floorsample-x
cell-z
floorsample-z
far
defunlittle-world-surface-height
sourcexzheight
let
reading
+5.5d0
max2
min
roundreading
defunlittle-world-surface-material
sourcexzsurfaceheight

Choose a visible biome material from height, moisture, and local slope.

let*
moisture
slope
loopfor
dxdz
in'
-10
10
0-1
01
maximize
cond
>=surface9
*snow-block*
or
<=surface3
<moisture-0.48d0
*sand-block*
>=slope2
*stone-block*
t*grass-block*
defgenericmaterialize-block-world-chunk
sourceworldchunk-xchunk-ychunk-z
defgenericpopulate-block-world-chunk
sourceworldchunk-xchunk-ychunk-z
defgenericapply-block-world-source-edits
sourceworldchunk-xchunk-ychunk-z
defgenericedit-block-world-source
sourceworldblockxyz
defunmaterialize-little-world-chunk
sourceworldchunk-xchunk-z

Materialize one deterministic terrain chunk at vertical layer zero.

check-typesourcelittle-world-source
with-world-change-transaction
world
let*
chunk
ensure-world-chunkworldchunk-x0chunk-z
shape
voxel-space-chunk-shape
block-world-spaceworld
width
chunk-shape-widthshape
height
chunk-shape-heightshape
depth
chunk-shape-depthshape
origin
chunk-domain-origin
block-chunk-domainchunk
dotimes
local-zdepth
dotimes
local-xwidth
let*
x
+
world-coordinate-xorigin
local-x
z
+
world-coordinate-zorigin
local-z
surface-material
dotimes
y
1+surface
setf
cond
=ysurface
surface-material
or
zeropy
<y
-surface2
*stone-block*
eqsurface-material*sand-block*
*sand-block*
t*dirt-block*
chunk
defmethodmaterialize-block-world-chunk
chunk-xchunk-ychunk-z
unless
zeropchunk-y
error"The little world currently materializes only chunk layer zero."
materialize-little-world-chunksourceworldchunk-xchunk-z
defunpopulate-little-world-chunk
sourceworldchunk-xchunk-z

Place deterministic, sparse landmarks after neighboring terrain exists.

with-world-change-transaction
world
let*
shape
voxel-space-chunk-shape
block-world-spaceworld
width
chunk-shape-widthshape
height
chunk-shape-heightshape
depth
chunk-shape-depthshape
origin-x
*chunk-xwidth
origin-z
*chunk-zdepth
hash
little-world-hashsourcechunk-xchunk-z
rock-x
+origin-x2
rock-z
+origin-z2
mod
ashhash-8
-depth4
rock-y
setf
world-block-atworldrock-xrock-yrock-z
*stone-block*
when
zerop
modhash2
setf
world-block-atworld
1+rock-x
rock-yrock-z
*stone-block*
when
and
<
mod
ashhash-16
5
4
>
little-world-value-noisesourcerock-xrock-z4829
-0.35d0
let*
tree-x
+origin-x3
mod
ashhash-3
tree-z
+origin-z3
mod
ashhash-11
-depth6
surface
surface-material
little-world-surface-materialsourcetree-xtree-zsurfaceheight
trunk-height
+3
mod
ashhash-23
2
crown
+surfacetrunk-height
when
and
eqsurface-material*grass-block*
<
+crown2
height
loopforyfrom
1+surface
tocrowndo
setf
world-block-atworldtree-xytree-z
*wood-block*

A broad, clipped lower crown and a small bright upper crown make silhouettes much less like identical green boxes.

loopforxfrom
-tree-x2
to
+tree-x2
do
loopforzfrom
-tree-z2
to
+tree-z2
when
<=
+
abs
-xtree-x
abs
-ztree-z
3
do
setf
world-block-atworldxcrownz
*leaf-block*
loopforxfrom
1-tree-x
to
1+tree-x
do
loopforzfrom
1-tree-z
to
1+tree-z
do
setf
world-block-atworldx
1+crown
z
*leaf-block*
setf
world-block-atworldtree-x
+crown2
tree-z
*leaf-block*
defmethodpopulate-block-world-chunk
chunk-xchunk-ychunk-z
unless
zeropchunk-y
error"The little world currently populates only chunk layer zero."
populate-little-world-chunksourceworldchunk-xchunk-z
defmethodapply-block-world-source-edits
chunk-xchunk-ychunk-z
multiple-value-bind
chunkpresent-p
world-chunk-atworldchunk-xchunk-ychunk-z
unlesspresent-p
error"Cannot apply edits to absent chunk (~D ~D ~D)."chunk-xchunk-ychunk-z
apply-block-edits-to-chunk
little-world-source-editssource
worldchunk
defmethodedit-block-world-source
record-block-edit
little-world-source-editssource
blockxyz
setfblock
defmethodedit-block-world-source
sourcet
blockxyz
setfblock
defunedit-block-at
blockworldxyz

Edit one resident site, recording it in world's source when supported.

edit-block-world-source
block-world-sourceworld
worldblockxyz
defunrematerialize-little-world-chunk
sourceworldchunk-xchunk-z

Regenerate one chunk from source, then replay its explicit edits.

with-world-change-transaction
world
remove-world-chunkworldchunk-x0chunk-z
materialize-block-world-chunksourceworldchunk-x0chunk-z
populate-block-world-chunksourceworldchunk-x0chunk-z
apply-block-world-source-editssourceworldchunk-x0chunk-z
defunblock-chunk-key
chunk
let
coordinate
chunk-domain-coordinate
block-chunk-domainchunk
chunk-key
chunk-coordinate-xcoordinate
chunk-coordinate-ycoordinate
chunk-coordinate-zcoordinate
defuncenter-little-world-residency
sourceworldcenter-xcenter-z&key
radius4

Materialize a square resident window and evict everything outside it.

Return the entering and leaving chunk-coordinate keys. Entering chunks are created as one staged transaction: establish all desired domains, materialize terrain, populate landmarks, then replay sparse edits.

check-typesourcelittle-world-source
check-typeradius
integer0
let
desired
make-hash-table:test#'equal
enteringnil
leavingnil
loopforchunk-xfrom
-center-xradius
to
+center-xradius
do
loopforchunk-zfrom
-center-zradius
to
+center-zradius
forkey=
chunk-keychunk-x0chunk-z
do
setf
gethashkeydesired
t
unless
nth-value1
world-chunk-atworldchunk-x0chunk-z
pushkeyentering
dolist
let
unless
gethashkeydesired
pushkeyleaving
setfentering
nreverseentering
leaving
nreverseleaving
with-world-change-transaction
world

Establish the whole neighborhood first so every later stage observes resident air rather than confusing a not-yet-created neighbor with it.

maphash
lambda
keypresent-p
declare
ignorepresent-p
destructuring-bind
xyz
key
desired
dolist
keyentering
destructuring-bind
xyz
key
dolist
keyentering
destructuring-bind
xyz
key
dolist
keyentering
destructuring-bind
xyz
key
dolist
keyleaving
destructuring-bind
xyz
key
valuesenteringleaving
defunmake-little-block-world
&key
chunk-width16
chunk-height16
chunk-depth16
seed121

Make a deterministic square of resident terrain chunks and landmarks.

check-typechunk-radius
integer0
check-typechunk-width
integer8
check-typechunk-height
integer8
check-typechunk-depth
integer8
let*
source
make-instance'little-world-source:seedseed
world
make-block-world:id
list:little-worldseed
:chunk-widthchunk-width:chunk-heightchunk-height:chunk-depthchunk-depth:sourcesource
world
defunmake-empty-little-block-world
&key
chunk-width16
chunk-height16
chunk-depth16
seed121

Make a sourced block world whose resident set is initially empty.

make-block-world:id
list:little-worldseed
:chunk-widthchunk-width:chunk-heightchunk-height:chunk-depthchunk-depth:source
make-instance'little-world-source:seedseed
defunlittle-world-landmarks-for-chunk
sourceworldkey

Capture deterministic landmarks whose owned sites lie inside key.

This retains the current visual generator while making chunk production independent: cross-boundary canopy sites are attributed to their destination chunk and do not require neighboring live mutation.

destructuring-bind
chunk-xchunk-ychunk-z
key
unless
zeropchunk-y
let*
shape
voxel-space-chunk-shape
block-world-spaceworld
width
chunk-shape-widthshape
height
chunk-shape-heightshape
depth
chunk-shape-depthshape
minimum-x
*chunk-xwidth
minimum-z
*chunk-zdepth
maximum-x
+minimum-xwidth
maximum-z
+minimum-zdepth
landmarksnil
flet
emit
blockxyz
when
and
<=minimum-xx
<xmaximum-x
<=minimum-zz
<zmaximum-z
<=0y
push
listblockxyz
landmarks

A destination chunk can receive a two-cell canopy overhang from a landmark rooted in an immediate neighbor.

loopforowner-xfrom
1-chunk-x
to
1+chunk-x
do
loopforowner-zfrom
1-chunk-z
to
1+chunk-z
do
let*
origin-x
*owner-xwidth
origin-z
*owner-zdepth
hash
little-world-hashsourceowner-xowner-z
rock-x
+origin-x2
rock-z
+origin-z2
mod
ashhash-8
-depth4
rock-y
emit*stone-block*rock-xrock-yrock-z
when
zerop
modhash2
emit*stone-block*
1+rock-x
rock-yrock-z
when
and
<
mod
ashhash-16
5
4
>
little-world-value-noisesourcerock-xrock-z4829
-0.35d0
let*
tree-x
+origin-x3
mod
ashhash-3
tree-z
+origin-z3
mod
ashhash-11
-depth6
surface
surface-material
little-world-surface-materialsourcetree-xtree-zsurfaceheight
trunk-height
+3
mod
ashhash-23
2
crown
+surfacetrunk-height
when
and
eqsurface-material*grass-block*
<
+crown2
height
loopforyfrom
1+surface
tocrowndo
emit*wood-block*tree-xytree-z
loopforxfrom
-tree-x2
to
+tree-x2
do
loopforzfrom
-tree-z2
to
+tree-z2
when
<=
+
abs
-xtree-x
abs
-ztree-z
3
do
emit*leaf-block*xcrownz
loopforxfrom
1-tree-x
to
1+tree-x
do
loopforzfrom
1-tree-z
to
1+tree-z
do
emit*leaf-block*x
1+crown
z
emit*leaf-block*tree-x
+crown2
tree-z
nreverselandmarks