Craft README

The project's README from github.com/fogleman/Craft. As one markdown file: README.md.

Craft

Minecraft clone for Windows, Mac OS X and Linux. Just a few thousand lines of C using modern OpenGL (shaders). Online multiplayer support is included using a Python-based server.

http://www.michaelfogleman.com/craft/

Screenshot

Features

Download

Mac and Windows binaries are available on the website.

http://www.michaelfogleman.com/craft/

See below to run from source.

Install Dependencies

Mac OS X

Download and install CMake if you don't already have it. You may use Homebrew to simplify the installation:

brew install cmake

Linux (Ubuntu)

sudo apt-get install cmake libglew-dev xorg-dev libcurl4-openssl-dev
sudo apt-get build-dep glfw

Windows

Download and install CMake and MinGW. Add C:\MinGW\bin to your PATH.

Download and install cURL so that CURL/lib and CURL/include are in your Program Files directory.

Use the following commands in place of the ones described in the next section.

cmake -G "MinGW Makefiles"
mingw32-make

Compile and Run

Once you have the dependencies (see above), run the following commands in your terminal.

git clone https://github.com/fogleman/Craft.git
cd Craft
cmake .
make
./craft

Multiplayer

After many years, craft.michaelfogleman.com has been taken down. See the Server section for info on self-hosting.

Client

You can connect to a server with command line arguments...

./craft [HOST [PORT]]

Or, with the "/online" command in the game itself.

/online [HOST [PORT]]

Server

You can run your own server or connect to mine. The server is written in Python but requires a compiled DLL so it can perform the terrain generation just like the client.

gcc -std=c99 -O3 -fPIC -shared -o world -I src -I deps/noise deps/noise/noise.c src/world.c
python server.py [HOST [PORT]]

Controls

Chat Commands

/goto [NAME]

Teleport to another user. If NAME is unspecified, a random user is chosen.

/list

Display a list of connected users.

/login NAME

Switch to another registered username. The login server will be re-contacted. The username is case-sensitive.

/logout

Unauthenticate and become a guest user. Automatic logins will not occur again until the /login command is re-issued.

/offline [FILE]

Switch to offline mode. FILE specifies the save file to use and defaults to "craft".

/online HOST [PORT]

Connect to the specified server.

/pq P Q

Teleport to the specified chunk.

/spawn

Teleport back to the spawn point.

Screenshot

Screenshot

Implementation Details

Terrain Generation

The terrain is generated using Simplex noise - a deterministic noise function seeded based on position. So the world will always be generated the same way in a given location.

The world is split up into 32x32 block chunks in the XZ plane (Y is up). This allows the world to be “infinite” (floating point precision is currently a problem at large X or Z values) and also makes it easier to manage the data. Only visible chunks need to be queried from the database.

Rendering

Only exposed faces are rendered. This is an important optimization as the vast majority of blocks are either completely hidden or are only exposing one or two faces. Each chunk records a one-block width overlap for each neighboring chunk so it knows which blocks along its perimeter are exposed.

Only visible chunks are rendered. A naive frustum-culling approach is used to test if a chunk is in the camera’s view. If it is not, it is not rendered. This results in a pretty decent performance improvement as well.

Chunk buffers are completely regenerated when a block is changed in that chunk, instead of trying to update the VBO.

Text is rendered using a bitmap atlas. Each character is rendered onto two triangles forming a 2D rectangle.

“Modern” OpenGL is used - no deprecated, fixed-function pipeline functions are used. Vertex buffer objects are used for position, normal and texture coordinates. Vertex and fragment shaders are used for rendering. Matrix manipulation functions are in matrix.c for translation, rotation, perspective, orthographic, etc. matrices. The 3D models are made up of very simple primitives - mostly cubes and rectangles. These models are generated in code in cube.c.

Transparency in glass blocks and plants (plants don’t take up the full rectangular shape of their triangle primitives) is implemented by discarding magenta-colored pixels in the fragment shader.

Database

User changes to the world are stored in a sqlite database. Only the delta is stored, so the default world is generated and then the user changes are applied on top when loading.

The main database table is named “block” and has columns p, q, x, y, z, w. (p, q) identifies the chunk, (x, y, z) identifies the block position and (w) identifies the block type. 0 represents an empty block (air).

In game, the chunks store their blocks in a hash map. An (x, y, z) key maps to a (w) value.

The y-position of blocks are limited to 0 <= y < 256. The upper limit is mainly an artificial limitation to prevent users from building unnecessarily tall structures. Users are not allowed to destroy blocks at y = 0 to avoid falling underneath the world.

Multiplayer

Multiplayer mode is implemented using plain-old sockets. A simple, ASCII, line-based protocol is used. Each line is made up of a command code and zero or more comma-separated arguments. The client requests chunks from the server with a simple command: C,p,q,key. “C” means “Chunk” and (p, q) identifies the chunk. The key is used for caching - the server will only send block updates that have been performed since the client last asked for that chunk. Block updates (in realtime or as part of a chunk request) are sent to the client in the format: B,p,q,x,y,z,w. After sending all of the blocks for a requested chunk, the server will send an updated cache key in the format: K,p,q,key. The client will store this key and use it the next time it needs to ask for that chunk. Player positions are sent in the format: P,pid,x,y,z,rx,ry. The pid is the player ID and the rx and ry values indicate the player’s rotation in two different axes. The client interpolates player positions from the past two position updates for smoother animation. The client sends its position to the server at most every 0.1 seconds (less if not moving).

Client-side caching to the sqlite database can be performance intensive when connecting to a server for the first time. For this reason, sqlite writes are performed on a background thread. All writes occur in a transaction for performance. The transaction is committed every 5 seconds as opposed to some logical amount of work completed. A ring / circular buffer is used as a queue for what data is to be written to the database.

In multiplayer mode, players can observe one another in the main view or in a picture-in-picture view. Implementation of the PnP was surprisingly simple - just change the viewport and render the scene again from the other player’s point of view.

Collision Testing

Hit testing (what block the user is pointing at) is implemented by scanning a ray from the player’s position outward, following their sight vector. This is not a precise method, so the step rate can be made smaller to be more accurate.

Collision testing simply adjusts the player’s position to remain a certain distance away from any adjacent blocks that are obstacles. (Clouds and plants are not marked as obstacles, so you pass right through them.)

Sky Dome

A textured sky dome is used for the sky. The X-coordinate of the texture represents time of day. The Y-values map from the bottom of the sky sphere to the top of the sky sphere. The player is always in the center of the sphere. The fragment shaders for the blocks also sample the sky texture to determine the appropriate fog color to blend with based on the block’s position relative to the backing sky.

Ambient Occlusion

Ambient occlusion is implemented as described on this page:

http://0fps.wordpress.com/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/

Dependencies

Craft (fogleman/Craft)

Searching Database…

11.1K ·GitHub
这是什么?Craft 是一个用 C 语言和现代 OpenGL(着色器)编写的简易 Minecraft 克隆。它可以在 Windows、Mac OS X 和 Linux 上运行,并通过一个基于 Python 的服务器支持在线多人游戏。
这是一个能玩的完整游戏,还是一个用来读的代码库?它是一款真正可以玩的游戏,但刻意做得很小——只有几千行 C 代码——所以也可以当作 OpenGL 体素引擎的易读参考;README 里详细讲解了地形、渲染、网络和碰撞的内部实现。
怎么编译和运行它?先安装 CMake 和开发所需的库,然后 git clone 仓库,运行 cmake . 接着运行 make;用 ./craft 启动游戏。项目网站上也有现成的 Mac 和 Windows 二进制文件可以下载。
编译之前需要先装好哪些东西?需要 CMake,以及 OpenGL 和网络的开发库:Ubuntu 上是 cmake、libglew-dev、xorg-dev 和 libcurl4-openssl-dev;Windows 上是 CMake、MinGW 和 cURL;macOS 上用 brew install cmake。它链接了 GLEW、GLFW、cURL、lodepng、sqlite3 和 tinycthread。
现在还能在作者的官方服务器上玩多人模式吗?不能——craft.michaelfogleman.com 已经关闭了。想在线玩只能自己搭服务器:服务器是 Python 写的,还需要一个编译好的 DLL,这样它的地形生成才能和客户端保持一致。
在游戏里到底能做什么?可以破坏和放置方块——超过 10 种类型,包括植物(草、花、树)和透明的玻璃。你可以在走路和飞行之间切换,把方块标记为光源,在告示牌上写字,和其他玩家聊天,还可以使用 /spawn、/goto、/online、/offline 这类命令。
多人模式在底层是怎么实现的?走的是普通 socket,用一套简单的 ASCII、按行分割的协议:客户端请求区块(C,p,q,key),接收方块更新(B,...)和缓存键(K,...),玩家位置(P,...)最多每 0.1 秒发送一次,客户端再做插值让动画平滑。
我对世界的修改保存到哪里?保存在一个 sqlite3 数据库里。只存储相对默认生成世界的差异部分,加载时再应用回去;sqlite 的写入在后台线程执行,为了性能每 5 秒提交一次事务。
这么大的世界它是怎么处理的?世界被切分成 32x32 方块的区块,由 simplex 噪声确定性地生成,所以地形实际上是无限的。渲染时只画暴露在外的方块面,视野之外的区块则通过视锥剔除完全跳过。
Creator
fogleman
Size
14.3 MB
Stars
11.1K
Age
13y
Commits · 90 Days