Skip to content
GAMPEONCreate
New project
Preview: this works today, but details can still change.

Block worlds

A block world is terrain made of 1 m blocks. Players dig with the left mouse button and build with the right one; GAMPEON draws the world, sends changes to everyone nearby and saves them. Your scripts decide the game: what digging gives, what players may place, prices, recipes, rules.

Every server can have one block world. You switch it on from a server script:

server.lua
EnableBlockWorld({
seed = 20261106, -- the terrain: same seed, same world
save = 'main', -- keep changed blocks between restarts (Saved/VoxelWorlds/main.gpvox)
zones = {
-- a flat area without blocks, for example a city. Nobody digs or builds here, scripts neither.
{ minX = -48, minY = -48, maxX = 48, maxY = 48, groundZ = 8 },
},
})

Call it when your resource starts, before players spawn. Players then spawn on the surface, in the middle of the first zone (or at 0, 0 without zones). Calling it again with the same options does nothing, so restarting your resource is safe. Other options need a server restart. Around each zone, the terrain slopes smoothly into the flat ground over blend blocks (default 24).

Inside a zone, a hidden foundation that nobody can dig ends at groundZ - 2, in case someone falls through the city. If your own map has water or low ground inside the zone, set floorZ lower, for example below the sea floor, so the foundation does not cover it: { minX = -340, minY = -350, maxX = 280, maxY = 330, groundZ = 0, floorZ = -14 }. Players spawn at groundZ in a zone. See Bring your own map.

Blocks have whole-number coordinates, and 1 block is 1 m, like the meters of GetEntityCoords. Block (x, y, z) fills the space from x to x + 1 and so on; z is up. Decimals are rounded down, so GetBlock(GetEntityCoords(ped)) is the block the feet of a character are in.

The world reaches from -4096 to 4095 on x and y and from -64 to 63 on z. The bottom layer cannot change, so nobody falls out of the world.

GetBlockTypes() lists all blocks. The list only grows.

Block Players can dig Players can place
turf, soil, stone, sand, snow yes yes
planks, brick, clay yes yes
charstone, copper_vein, iron_vein, crystal yes no (ores)
deepstone no no

Scripts can set any block with SetBlock, also ores.

Players use built-in controls, you do not write input code:

Input Action
Left mouse button Dig the block under the crosshair (hold to repeat)
Right mouse button Place the selected hotbar block on the side the crosshair points at
Mouse wheel, 1 to 9 Pick a hotbar slot

The hotbar comes from your client script. Without one, players can only dig.

client.lua
-- Show what the player owns, with counts. The server still decides in blockPlace.
RegisterNetEvent('mygame:inventory', function(inv)
SetBlockHotbar({
{ block = 'stone', count = inv.stone or 0 },
{ block = 'planks', count = inv.planks or 0 },
})
end)

Every action goes to the server first. The server checks reach (6 m from the eyes), speed (10 actions per second), zones, block type, free space, a solid neighbor and that no character stands in the way. Then it asks your scripts:

server.lua
AddEventHandler('blockBreak', function(x, y, z, block)
-- source is the player. CancelEvent keeps the block.
if block == 'crystal' and not HasPickaxe(source) then
CancelEvent()
return
end
AddItem(source, block, 1)
end)
AddEventHandler('blockPlace', function(x, y, z, block)
if not RemoveItem(source, block, 1) then
CancelEvent() -- the player sees the block disappear again
end
end)

Call CancelEvent before any Wait. After the change, blockChanged arrives in the next server tick, for players and for SetBlock:

AddEventHandler('blockChanged', function(x, y, z, oldBlock, newBlock, player)
-- player is 0 when a script changed it
end)
  • SetBlockHudVisible(false) hides the built-in hotbar and the outline, for example when you draw your own hotbar with a web interface. The controls keep working; GetBlockHotbarSlot() and the event blockHotbarSelect tell you the selection.
  • SetBlockControlsEnabled(false) stops digging and building, for example while a menu is open. The controls also pause on their own while the mouse cursor is visible.
  • GetBlockTarget() returns the block under the crosshair and the side it points at, or nil.

With save, the server stores changed blocks and loads them on the next start. Unchanged terrain is never stored; it comes from the seed. If you change the seed but keep the save name, the server moves the old save aside (<save>.seed<old>.gpvox) and starts a new world.

Before the map has loaded (while your resource starts), GetBlock shows the generated terrain and your own SetBlock calls. Saved changes appear once the world is there.

Player data such as inventories is yours to save, for example with SaveResourceFile or the database.

gampeon-server has the same block world, without graphics. It keeps changed blocks only while it runs; save works on the game server. Fake players dig and build like with the mouse:

Command Effect
gp_fakeplayer break <id> [x y z] Dig, by default the block straight below the player’s eyes
gp_fakeplayer place <id> [x y z [block]] Place, by default the selected hotbar block
gp_fakeplayer slot <id> <n> Pick hotbar slot n
gp_block <x> <y> <z> Print the block and the surface height there

See Test without the game for the rest.

  • Your own block types with your own colors or textures.
  • Water and other liquids, falling blocks, blocks that give light.
  • More than one block world per server.

All functions with their arguments are in the Lua API reference.

Report a problem with this pageOther ways to give feedback