mirror of
https://github.com/moparisthebest/minetest
synced 2024-11-10 11:25:07 -05:00
commit
f37a3a84fa
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
map/*
|
||||
world/*
|
||||
CMakeFiles/*
|
||||
src/CMakeFiles/*
|
||||
src/Makefile
|
||||
@ -17,4 +18,5 @@ Makefile
|
||||
cmake_install.cmake
|
||||
src/jthread/libjthread.a
|
||||
debug.txt
|
||||
bin/debug.txt
|
||||
minetestmapper/map.png
|
||||
|
7
.hgtags
7
.hgtags
@ -4,3 +4,10 @@ e3c3c8e27bbc8c9b61710517a78944deb1c61696 110211211322
|
||||
23880c78e40c50ad54fcd8844510f7a423b37f2a 110212200513
|
||||
20c49c98c92a62df457b773c562df41d4167492b 110214175330
|
||||
10be2b71f965585af90af96903e83b4ddff52bf9 20110424_0
|
||||
9b05d4bfee9312aef4182fa6f63b4237368cec34 0.2.20110529_0
|
||||
6fa0a8b40406aa567f8fa84b5e2045a7e3762c1d 0.2.20110529_1
|
||||
cf6dd618ef0b7514c81ae87749733b5a328fc763 0.2.20110529_2
|
||||
96efc17b4cd92aacbe947b520a6ba91727d42f03 0.2.20110602_0
|
||||
0000000000000000000000000000000000000000 0.2.20110602_0
|
||||
6f17cd3f6c5481e6abc906fc441980c764632cbc 0.2.20110602_0
|
||||
dd08a9b5cb84d55b7576bb3fde3068dd263bc3bc 0.2.20110618_0_dev
|
||||
|
@ -9,7 +9,7 @@ project(minetest)
|
||||
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 20110424_1_dev)
|
||||
set(VERSION_PATCH 20110618_0_dev)
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
|
||||
# Configuration options
|
||||
|
239
README.txt
Normal file
239
README.txt
Normal file
@ -0,0 +1,239 @@
|
||||
Minetest-c55
|
||||
---------------
|
||||
An InfiniMiner/Minecraft inspired game.
|
||||
Copyright (c) 2010-2011 Perttu Ahola <celeron55@gmail.com>
|
||||
(see source files for other contributors)
|
||||
|
||||
Further documentation:
|
||||
----------------------
|
||||
- Website: http://celeron.55.lt/~celeron55/minetest/
|
||||
- Wiki: http://celeron.55.lt/~celeron55/minetest/wiki/
|
||||
- Forum: http://celeron.55.lt/~celeron55/minetest/forum/
|
||||
- doc/ directory of source distribution
|
||||
|
||||
This game is not finished:
|
||||
--------------------------
|
||||
- Don't expect it to work as well as a finished game will.
|
||||
- Please report any bugs to me. debug.txt is useful.
|
||||
|
||||
Controls:
|
||||
---------
|
||||
- See the in-game pause menu
|
||||
- Settable in the configuration file, see the section below.
|
||||
|
||||
Map directory:
|
||||
--------------
|
||||
- Map is stored in a directory, which can be removed to generate a new map.
|
||||
- There is a command-line option for it: --map-dir
|
||||
- For a RUN_IN_PLACE build, it is located in:
|
||||
../map
|
||||
- Otherwise something like this:
|
||||
Windows: C:\Documents and Settings\user\Application Data\minetest\map
|
||||
Linux: ~/.minetest/map
|
||||
OS X: ~/Library/Application Support/minetest/map
|
||||
|
||||
Configuration file:
|
||||
-------------------
|
||||
- An optional configuration file can be used. See minetest.conf.example.
|
||||
- Path to file can be passed as a parameter to the executable:
|
||||
--config <path-to-file>
|
||||
- Defaults:
|
||||
- If built with -DRUN_IN_PLACE=1:
|
||||
../minetest.conf
|
||||
../../minetest.conf
|
||||
- Otherwise something like this:
|
||||
Windows: C:\Documents and Settings\user\Application Data\minetest\minetest.conf
|
||||
Linux: ~/.minetest/minetest.conf
|
||||
OS X: ~/Library/Application Support/minetest.conf
|
||||
|
||||
Command-line options:
|
||||
---------------------
|
||||
- Use --help
|
||||
|
||||
Compiling on GNU/Linux:
|
||||
-----------------------
|
||||
|
||||
Install dependencies. Here's an example for Debian/Ubuntu:
|
||||
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev
|
||||
|
||||
Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
|
||||
$ wget https://bitbucket.org/celeron55/minetest/get/tip.tar.gz
|
||||
$ tar xf tip.tar.gz
|
||||
$ cd minetest
|
||||
|
||||
Build a version that runs directly from the source directory:
|
||||
$ cmake . -DRUN_IN_PLACE=1
|
||||
$ make -j2
|
||||
|
||||
Run it:
|
||||
$ cd bin
|
||||
$ ./minetest
|
||||
|
||||
- Use cmake . -LH to see all CMake options and their current state
|
||||
- If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0
|
||||
- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
|
||||
- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
|
||||
- Note that the Debug build is considerably slower
|
||||
|
||||
Compiling on Windows:
|
||||
---------------------
|
||||
|
||||
- You need:
|
||||
* CMake:
|
||||
http://www.cmake.org/cmake/resources/software.html
|
||||
* MinGW or Visual Studio
|
||||
http://www.mingw.org/
|
||||
http://msdn.microsoft.com/en-us/vstudio/default
|
||||
* Irrlicht SDK 1.7:
|
||||
http://irrlicht.sourceforge.net/downloads.html
|
||||
* Zlib headers (zlib125.zip)
|
||||
http://www.winimage.com/zLibDll/index.html
|
||||
* Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
|
||||
http://www.winimage.com/zLibDll/index.html
|
||||
* And, of course, Minetest-c55:
|
||||
http://celeron.55.lt/~celeron55/minetest/download
|
||||
- Steps:
|
||||
- Select a directory called DIR hereafter in which you will operate.
|
||||
- Make sure you have CMake and a compiler installed.
|
||||
- Download all the other stuff to DIR and extract them into there. All those
|
||||
packages contain a nice base directory in them, which should end up being
|
||||
the direct subdirectories of DIR.
|
||||
- You will end up with a directory structure like this (+=dir, -=file):
|
||||
-----------------
|
||||
+ DIR
|
||||
- zlib-1.2.5.tar.gz
|
||||
- zlib125dll.zip
|
||||
- irrlicht-1.7.1.zip
|
||||
- 110214175330.zip (or whatever, this is the minetest source)
|
||||
+ zlib-1.2.5
|
||||
- zlib.h
|
||||
+ win32
|
||||
...
|
||||
+ zlib125dll
|
||||
- readme.txt
|
||||
+ dll32
|
||||
...
|
||||
+ irrlicht-1.7.1
|
||||
+ lib
|
||||
+ include
|
||||
...
|
||||
+ minetest
|
||||
+ src
|
||||
+ doc
|
||||
- CMakeLists.txt
|
||||
...
|
||||
-----------------
|
||||
- Start up the CMake GUI
|
||||
- Select "Browse Source..." and select DIR/minetest
|
||||
- Now, if using MSVC:
|
||||
- Select "Browse Build..." and select DIR/minetest-build
|
||||
- Else if using MinGW:
|
||||
- Select "Browse Build..." and select DIR/minetest
|
||||
- Select "Configure"
|
||||
- Select your compiler
|
||||
- It will warn about missing stuff, ignore that at this point. (later don't)
|
||||
- Make sure the configuration is as follows
|
||||
(note that the versions may differ for you):
|
||||
-----------------
|
||||
BUILD_CLIENT [X]
|
||||
BUILD_SERVER [ ]
|
||||
CMAKE_BUILD_TYPE Release
|
||||
CMAKE_INSTALL_PREFIX DIR/minetest-install
|
||||
IRRLICHT_SOURCE_DIR DIR/irrlicht-1.7.1
|
||||
RUN_IN_PLACE [X]
|
||||
WARN_ALL [ ]
|
||||
ZLIB_DLL DIR/zlib125dll/dll32/zlibwapi.dll
|
||||
ZLIB_INCLUDE_DIR DIR/zlib-1.2.5
|
||||
ZLIB_LIBRARIES DIR/zlib125dll/dll32/zlibwapi.lib
|
||||
-----------------
|
||||
- Hit "Configure"
|
||||
- Hit "Generate"
|
||||
If using MSVC:
|
||||
- Open the generated minetest.sln
|
||||
- The project defaults to the "Debug" configuration. Make very sure to
|
||||
select "Release", unless you want to debug some stuff (it's slower)
|
||||
- Build the ALL_BUILD project
|
||||
- Build the INSTALL project
|
||||
- You should now have a working game with the executable in
|
||||
DIR/minetest-install/bin/minetest.exe
|
||||
- Additionally you may create a zip package by building the PACKAGE
|
||||
project.
|
||||
If using MinGW:
|
||||
- Using the command line, browse to the build directory and run 'make'
|
||||
(or mingw32-make or whatever it happens to be)
|
||||
- You should now have a working game with the executable in
|
||||
DIR/minetest/bin/minetest.exe
|
||||
|
||||
License of Minetest-c55
|
||||
-----------------------
|
||||
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Irrlicht
|
||||
---------------
|
||||
|
||||
This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/
|
||||
|
||||
The Irrlicht Engine License
|
||||
|
||||
Copyright © 2002-2005 Nikolaus Gebhardt
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute
|
||||
it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
|
||||
JThread
|
||||
---------------
|
||||
|
||||
This program uses the JThread library. License for JThread follows:
|
||||
|
||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
for i in `grep -L 'This program is free software' src/*.{h,cpp}`
|
||||
do
|
||||
cat licensecomment.txt > tempfile
|
||||
cat $i >> tempfile
|
||||
cp tempfile $i
|
||||
done
|
||||
rm tempfile
|
||||
|
BIN
data/gravel.png
Normal file
BIN
data/gravel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 591 B |
BIN
data/item_fence.png
Normal file
BIN
data/item_fence.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
data/mossycobble.png
Normal file
BIN
data/mossycobble.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 965 B |
BIN
data/treeprop.png
Normal file
BIN
data/treeprop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
@ -3,7 +3,12 @@ Minetest-c55 changelog
|
||||
This should contain all the major changes.
|
||||
For minor stuff, refer to the commit log of the repository.
|
||||
|
||||
X:
|
||||
2011-06-02:
|
||||
- Password crash on windows fixed
|
||||
- Optimized server CPU usage a lot
|
||||
- Furnaces now work also while players are not near to them
|
||||
|
||||
2011-05-29:
|
||||
- Optimized smooth lighting
|
||||
- A number of small fixes
|
||||
- Added clouds and simple skyboxes
|
||||
@ -13,6 +18,10 @@ X:
|
||||
- Slightly updated map format
|
||||
- Player passwords
|
||||
- All textures first searched from texture_path
|
||||
- Map directory ("map") has been renamed to "world" (just rename it to load an old world)
|
||||
- Mouse inversion (invert_mouse)
|
||||
- Grass doesn't grow immediately anymore
|
||||
- Fence added
|
||||
|
||||
2011-04-24:
|
||||
- Smooth lighting with simple ambient occlusion
|
||||
|
89
doc/mapformat.txt
Normal file
89
doc/mapformat.txt
Normal file
@ -0,0 +1,89 @@
|
||||
I'll try to quickly document the newest block format in here (might contain
|
||||
errors). Refer to the mapgen or minetestmapper script for the directory
|
||||
structure and file naming. There are two sector namings possible,
|
||||
sector/XXXXZZZZ and sector/XXX/ZZZ.
|
||||
|
||||
There also exists files map_meta.txt and chunk_meta, that are used by the
|
||||
generator. If they are not found or invalid, the generator will currently
|
||||
behave quite strangely.
|
||||
|
||||
The MapBlock file format (sectors2/XXX/ZZZ/YYYY):
|
||||
-------------------------------------------------
|
||||
|
||||
NOTE: Byte order is MSB first.
|
||||
|
||||
u8 version
|
||||
- map format version number, this one is version 17
|
||||
|
||||
u8 flags
|
||||
- Flag bitmasks:
|
||||
- 0x01: is_underground: Should be set to 0 if there will be no light
|
||||
obstructions above the block. If/when sunlight of a block is updated and
|
||||
there is no block above it, this value is checked for determining whether
|
||||
sunlight comes from the top.
|
||||
- 0x02: day_night_differs: Whether the lighting of the block is different on
|
||||
day and night. Only blocks that have this bit set are updated when day
|
||||
transforms to night.
|
||||
- 0x04: lighting_expired: If true, lighting is invalid and should be updated.
|
||||
If you can't calculate lighting in your generator properly, you could try
|
||||
setting this 1 to everything and setting the uppermost block in every
|
||||
sector as is_underground=0. I am quite sure it doesn't work properly,
|
||||
though.
|
||||
|
||||
zlib-compressed map data:
|
||||
- content:
|
||||
u8[4096]: content types
|
||||
u8[4096]: param1 values
|
||||
u8[4096]: param2 values
|
||||
|
||||
zlib-compressed node metadata
|
||||
- content:
|
||||
u16 version (=1)
|
||||
u16 count of metadata
|
||||
foreach count:
|
||||
u16 position (= p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
|
||||
u16 type_id
|
||||
u16 content_size
|
||||
u8[content_size] misc. stuff contained in the metadata
|
||||
|
||||
u16 mapblockobject_count
|
||||
- always write as 0.
|
||||
- if read != 0, just fail.
|
||||
|
||||
foreach mapblockobject_count:
|
||||
- deprecated, should not be used. Length of this data can only be known by
|
||||
properly parsing it. Just hope not to run into any of this.
|
||||
|
||||
u8 static object version:
|
||||
- currently 0
|
||||
|
||||
u16 static_object_count
|
||||
|
||||
foreach static_object_count:
|
||||
u8 type (object type-id)
|
||||
s32 pos_x * 1000
|
||||
s32 pos_y * 1000
|
||||
s32 pos_z * 1000
|
||||
u16 data_size
|
||||
u8[data_size] data
|
||||
|
||||
u32 timestamp
|
||||
- Timestamp when last saved, as seconds from starting the game.
|
||||
- 0xffffffff = invalid/unknown timestamp, nothing will be done with the time
|
||||
difference when loaded (recommended)
|
||||
|
||||
Node metadata format:
|
||||
---------------------
|
||||
|
||||
Sign metadata:
|
||||
u16 string_len
|
||||
u8[string_len] string
|
||||
|
||||
Furnace metadata:
|
||||
TBD
|
||||
|
||||
Chest metadata:
|
||||
TBD
|
||||
|
||||
// END
|
||||
|
72
doc/protocol.txt
Normal file
72
doc/protocol.txt
Normal file
@ -0,0 +1,72 @@
|
||||
Minetest-c55 protocol (incomplete, early draft):
|
||||
Updated 2011-06-18
|
||||
|
||||
A custom protocol over UDP.
|
||||
Integers are big endian.
|
||||
Refer to connection.{h,cpp} for further reference.
|
||||
|
||||
Initialization:
|
||||
- A dummy reliable packet with peer_id=PEER_ID_INEXISTENT=0 is sent to the server:
|
||||
- Actually this can be sent without the reliable packet header, too, i guess,
|
||||
but the sequence number in the header allows the sender to re-send the
|
||||
packet without accidentally getting a double initialization.
|
||||
- Packet content:
|
||||
# Basic header
|
||||
u32 protocol_id = PROTOCOL_ID = 0x4f457403
|
||||
u16 sender_peer_id = PEER_ID_INEXISTENT = 0
|
||||
u8 channel = 0
|
||||
# Reliable packet header
|
||||
u8 type = TYPE_RELIABLE = 3
|
||||
u16 seqnum = SEQNUM_INITIAL = 65500
|
||||
# Original packet header
|
||||
u8 type = TYPE_ORIGINAL = 1
|
||||
# And no actual payload.
|
||||
- Server responds with something like this:
|
||||
- Packet content:
|
||||
# Basic header
|
||||
u32 protocol_id = PROTOCOL_ID = 0x4f457403
|
||||
u16 sender_peer_id = PEER_ID_INEXISTENT = 0
|
||||
u8 channel = 0
|
||||
# Reliable packet header
|
||||
u8 type = TYPE_RELIABLE = 3
|
||||
u16 seqnum = SEQNUM_INITIAL = 65500
|
||||
# Control packet header
|
||||
u8 type = TYPE_CONTROL = 0
|
||||
u8 controltype = CONTROLTYPE_SET_PEER_ID = 1
|
||||
u16 peer_id_new = assigned peer id to client (other than 0 or 1)
|
||||
- Then the connection can be disconnected by sending:
|
||||
- Packet content:
|
||||
# Basic header
|
||||
u32 protocol_id = PROTOCOL_ID = 0x4f457403
|
||||
u16 sender_peer_id = whatever was gotten in CONTROLTYPE_SET_PEER_ID
|
||||
u8 channel = 0
|
||||
# Control packet header
|
||||
u8 type = TYPE_CONTROL = 0
|
||||
u8 controltype = CONTROLTYPE_DISCO = 2
|
||||
|
||||
- Here's a quick untested connect-disconnect done in PHP:
|
||||
# host: ip of server (use gethostbyname(hostname) to get from a dns name)
|
||||
# port: port of server
|
||||
function check_if_minetestserver_up($host, $port)
|
||||
{
|
||||
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
$timeout = array("sec" => 1, "usec" => 0);
|
||||
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
|
||||
$buf = "\x4f\x45\x74\x03\x00\x00\x00\x03\xff\xdc\x01";
|
||||
socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
|
||||
$buf = socket_read($socket, 1000);
|
||||
if($buf != "")
|
||||
{
|
||||
# We got a reply! read the peer id from it.
|
||||
$peer_id = substr($buf, 9, 2);
|
||||
|
||||
# Disconnect
|
||||
$buf = "\x4f\x45\x74\x03".$peer_id."\x00\x00\x02";
|
||||
socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
|
||||
socket_close($socket);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
280
genmap.py
280
genmap.py
@ -6,19 +6,42 @@ import struct
|
||||
import random
|
||||
import os
|
||||
import sys
|
||||
import zlib
|
||||
import array
|
||||
from pnoise import pnoise
|
||||
|
||||
"""
|
||||
Map format:
|
||||
map/sectors/XXXXZZZZ/YYYY
|
||||
# Old directory format:
|
||||
# world/sectors/XXXXZZZZ/YYYY
|
||||
# XXXX,YYYY,ZZZZ = coordinates in hexadecimal
|
||||
# fffe = -2
|
||||
# ffff = -1
|
||||
# 0000 = 0
|
||||
# 0001 = 1
|
||||
#
|
||||
# New directory format:
|
||||
# world/sectors2/XXX/ZZZ/YYYY
|
||||
# XXX,YYYY,ZZZ = coordinates in hexadecimal
|
||||
# fffe = -2
|
||||
# ffff = -1
|
||||
# 0000 = 0
|
||||
# 0001 = 1
|
||||
# ffe = -2
|
||||
# fff = -1
|
||||
# 000 = 0
|
||||
# 001 = 1
|
||||
#
|
||||
# For more proper file format documentation, refer to mapformat.txt
|
||||
# For node type documentation, refer to mapnode.h
|
||||
# NodeMetadata documentation is not complete, refer to nodemeta.cpp
|
||||
#
|
||||
|
||||
XXXX,YYYY,ZZZZ = coordinates in hexadecimal
|
||||
# Seed for generating terrain
|
||||
SEED = 0
|
||||
|
||||
fffe = -2
|
||||
ffff = -1
|
||||
0000 = 0
|
||||
0001 = 1
|
||||
"""
|
||||
# 0=old, 1=new
|
||||
SECTOR_DIR_FORMAT = 1
|
||||
|
||||
mapdir = "world"
|
||||
|
||||
def to4h(i):
|
||||
s = "";
|
||||
@ -28,64 +51,221 @@ def to4h(i):
|
||||
s += '{0:1x}'.format((i>>0) & 0x000f)
|
||||
return s
|
||||
|
||||
def getrand():
|
||||
def to3h(i):
|
||||
s = "";
|
||||
s += '{0:1x}'.format((i>>8) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>4) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>0) & 0x000f)
|
||||
return s
|
||||
|
||||
def get_sector_dir(px, pz):
|
||||
global SECTOR_DIR_FORMAT
|
||||
if SECTOR_DIR_FORMAT == 0:
|
||||
return "/sectors/"+to4h(px)+to4h(pz)
|
||||
elif SECTOR_DIR_FORMAT == 1:
|
||||
return "/sectors2/"+to3h(px)+"/"+to3h(pz)
|
||||
else:
|
||||
assert(0)
|
||||
|
||||
def getrand_air_stone():
|
||||
i = random.randrange(0,2)
|
||||
if i==0:
|
||||
return 0
|
||||
return 254
|
||||
|
||||
def writeblock(mapdir, px,py,pz, version):
|
||||
sectordir = mapdir + "/sectors/" + to4h(px) + to4h(pz)
|
||||
# 3-dimensional vector (position)
|
||||
class v3:
|
||||
def __init__(self, x=0, y=0, z=0):
|
||||
self.X = x
|
||||
self.Y = y
|
||||
self.Z = z
|
||||
|
||||
class NodeMeta:
|
||||
def __init__(self, type_id, data):
|
||||
self.type_id = type_id
|
||||
self.data = data
|
||||
|
||||
class StaticObject:
|
||||
def __init__(self):
|
||||
self.type_id = 0
|
||||
self.data = ""
|
||||
|
||||
def ser_u16(i):
|
||||
return chr((i>>8)&0xff) + chr((i>>0)&0xff)
|
||||
def ser_u32(i):
|
||||
return (chr((i>>24)&0xff) + chr((i>>16)&0xff)
|
||||
+ chr((i>>8)&0xff) + chr((i>>0)&0xff))
|
||||
|
||||
# A 16x16x16 chunk of map
|
||||
class MapBlock:
|
||||
def __init__(self):
|
||||
self.content = array.array('B')
|
||||
self.param1 = array.array('B')
|
||||
self.param2 = array.array('B')
|
||||
for i in range(16*16*16):
|
||||
# Initialize to air
|
||||
self.content.append(254)
|
||||
# Full light on sunlight, none when no sunlight
|
||||
self.param1.append(15)
|
||||
# No additional parameters
|
||||
self.param2.append(0)
|
||||
|
||||
# key = v3 pos
|
||||
# value = NodeMeta
|
||||
self.nodemeta = {}
|
||||
|
||||
# key = v3 pos
|
||||
# value = StaticObject
|
||||
self.static_objects = {}
|
||||
|
||||
def set_content(self, v3, b):
|
||||
self.content[v3.Z*16*16+v3.Y*16+v3.X] = b
|
||||
def set_param1(self, v3, b):
|
||||
self.param1[v3.Z*16*16+v3.Y*16+v3.X] = b
|
||||
def set_param2(self, v3, b):
|
||||
self.param2[v3.Z*16*16+v3.Y*16+v3.X] = b
|
||||
|
||||
# Get data for serialization. Returns a string.
|
||||
def serialize_data(self):
|
||||
s = ""
|
||||
for i in range(16*16*16):
|
||||
s += chr(self.content[i])
|
||||
for i in range(16*16*16):
|
||||
s += chr(self.param1[i])
|
||||
for i in range(16*16*16):
|
||||
s += chr(self.param2[i])
|
||||
return s
|
||||
|
||||
def serialize_nodemeta(self):
|
||||
s = ""
|
||||
s += ser_u16(1)
|
||||
s += ser_u16(len(self.nodemeta))
|
||||
for pos, meta in self.nodemeta.items():
|
||||
pos_i = pos.Z*16*16 + pos.Y*16 + pos.X
|
||||
s += ser_u16(pos_i)
|
||||
s += ser_u16(meta.type_id)
|
||||
s += ser_u16(len(meta.data))
|
||||
s += meta.data
|
||||
return s
|
||||
|
||||
def serialize_staticobj(self):
|
||||
s = ""
|
||||
s += chr(0)
|
||||
s += ser_u16(len(self.static_objects))
|
||||
for pos, obj in self.static_objects.items():
|
||||
pos_i = pos.Z*16*16 + pos.Y*16 + pos.X
|
||||
s += ser_s32(pos.X*1000)
|
||||
s += ser_s32(pos.Y*1000)
|
||||
s += ser_s32(pos.Z*1000)
|
||||
s += ser_u16(obj.type_id)
|
||||
s += ser_u16(len(obj.data))
|
||||
s += obj.data
|
||||
return s
|
||||
|
||||
def writeblock(mapdir, px,py,pz, block):
|
||||
|
||||
sectordir = mapdir + get_sector_dir(px, pz);
|
||||
|
||||
try:
|
||||
os.makedirs(sectordir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
path = sectordir+"/"+to4h(py)
|
||||
|
||||
print("writing block file "+path)
|
||||
|
||||
f = open(sectordir+"/"+to4h(py), "wb")
|
||||
|
||||
if version == 0:
|
||||
# version
|
||||
f.write(struct.pack('B', 0))
|
||||
# is_underground
|
||||
f.write(struct.pack('B', 0))
|
||||
elif version == 2:
|
||||
# version
|
||||
f.write(struct.pack('B', 2))
|
||||
# is_underground
|
||||
f.write(struct.pack('B', 0))
|
||||
if f == None:
|
||||
return
|
||||
|
||||
# version
|
||||
version = 17
|
||||
f.write(struct.pack('B', version))
|
||||
|
||||
# flags
|
||||
# 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired
|
||||
flags = 0 + 0x02 + 0x04
|
||||
f.write(struct.pack('B', flags))
|
||||
|
||||
for z in range(0,16):
|
||||
for y in range(0,16):
|
||||
for x in range(0,16):
|
||||
b = 254
|
||||
r = 20.0*pnoise((px*16+x)/100.,(pz*16+z)/100.,0)
|
||||
r += 5.0*pnoise((px*16+x)/25.,(pz*16+z)/25.,0)
|
||||
#print("r="+str(r))
|
||||
y1 = py*16+y
|
||||
if y1 <= r-3:
|
||||
b = 0 #stone
|
||||
elif y1 <= r:
|
||||
b = 1 #grass
|
||||
elif y1 <= 1:
|
||||
b = 9 #water
|
||||
if version == 0:
|
||||
# Material content
|
||||
f.write(struct.pack('B', b))
|
||||
elif version == 2:
|
||||
# Material content
|
||||
f.write(struct.pack('B', b))
|
||||
# Brightness
|
||||
f.write(struct.pack('B', 15))
|
||||
# data
|
||||
c_obj = zlib.compressobj()
|
||||
c_obj.compress(block.serialize_data())
|
||||
f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number
|
||||
f.write(c_obj.flush())
|
||||
|
||||
# node metadata
|
||||
c_obj = zlib.compressobj()
|
||||
c_obj.compress(block.serialize_nodemeta())
|
||||
f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number
|
||||
f.write(c_obj.flush())
|
||||
|
||||
# mapblockobject count
|
||||
f.write(ser_u16(0))
|
||||
|
||||
# static objects
|
||||
f.write(block.serialize_staticobj())
|
||||
|
||||
# timestamp
|
||||
f.write(ser_u32(0xffffffff))
|
||||
|
||||
f.close()
|
||||
|
||||
mapdir = "map"
|
||||
for z0 in range(-1,3):
|
||||
for x0 in range(-1,3):
|
||||
for y0 in range(-1,3):
|
||||
print("generating block "+str(x0)+","+str(y0)+","+str(z0))
|
||||
#v3 blockp = v3(x0,y0,z0)
|
||||
|
||||
# Create a MapBlock
|
||||
block = MapBlock()
|
||||
|
||||
# Generate stuff in it
|
||||
for z in range(0,16):
|
||||
for x in range(0,16):
|
||||
h = 20.0*pnoise((x0*16+x)/100.,(z0*16+z)/100.,SEED+0)
|
||||
h += 5.0*pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+0)
|
||||
if pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+92412) > 0.05:
|
||||
h += 10
|
||||
#print("r="+str(r))
|
||||
# This enables comparison by ==
|
||||
h = int(h)
|
||||
for y in range(0,16):
|
||||
p = v3(x,y,z)
|
||||
b = 254
|
||||
y1 = y0*16+y
|
||||
if y1 <= h-3:
|
||||
b = 0 #stone
|
||||
elif y1 <= h and y1 <= 0:
|
||||
b = 8 #mud
|
||||
elif y1 == h:
|
||||
b = 1 #grass
|
||||
elif y1 < h:
|
||||
b = 8 #mud
|
||||
elif y1 <= 1:
|
||||
b = 9 #water
|
||||
|
||||
for z in range(-2,3):
|
||||
for y in range(-1,2):
|
||||
for x in range(-2,3):
|
||||
print("generating block "+str(x)+","+str(y)+","+str(z))
|
||||
writeblock(mapdir, x,y,z, 0)
|
||||
# Material content
|
||||
block.set_content(p, b)
|
||||
|
||||
# Place a sign at the center at surface level.
|
||||
# Placing a sign means placing the sign node and
|
||||
# adding node metadata to the mapblock.
|
||||
if x == 8 and z == 8 and y0*16 <= h-1 and (y0+1)*16-1 > h:
|
||||
p = v3(8,h+1-y0*16,8)
|
||||
# 14 = Sign
|
||||
content_type = 14
|
||||
block.set_content(p, content_type)
|
||||
# This places the sign to the bottom of the cube.
|
||||
# Working values: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20
|
||||
block.set_param2(p, 0x08)
|
||||
# Then add metadata to hold the text of the sign
|
||||
s = "Hello at sector ("+str(x0)+","+str(z0)+")"
|
||||
meta = NodeMeta(content_type, ser_u16(len(s))+s)
|
||||
block.nodemeta[p] = meta
|
||||
|
||||
# Write it on disk
|
||||
writeblock(mapdir, x0,y0,z0, block)
|
||||
|
||||
#END
|
||||
|
@ -42,6 +42,8 @@
|
||||
#keymap_special1 = KEY_KEY_E
|
||||
#keymap_print_debug_stacks = KEY_KEY_P
|
||||
|
||||
#invert_mouse = false
|
||||
|
||||
# The desired FPS
|
||||
#wanted_fps = 30
|
||||
|
||||
@ -56,6 +58,12 @@
|
||||
# Whether to fog out the end of the visible area
|
||||
#enable_fog = true
|
||||
|
||||
# Enable/disable clouds
|
||||
#enable_clouds = true
|
||||
|
||||
# Experimental
|
||||
#enable_farmesh = false
|
||||
|
||||
# Enable a bit lower water surface; disable for speed
|
||||
#new_style_water = true
|
||||
|
||||
@ -90,10 +98,6 @@
|
||||
# Server side stuff
|
||||
#
|
||||
|
||||
# Set to true to enable experimental features
|
||||
# (varies from version to version, see wiki)
|
||||
#enable_experimental = false
|
||||
|
||||
# Map directory (everything in the world is stored here)
|
||||
#map-dir = /home/palle/custom_map
|
||||
|
||||
@ -102,9 +106,21 @@
|
||||
|
||||
#enable_damage = false
|
||||
|
||||
#default_password =
|
||||
|
||||
# Available privileges: build, teleport, settime, privs, shout
|
||||
#default_privs = build, shout
|
||||
|
||||
# Gives some stuff to players at the beginning
|
||||
#give_initial_stuff = false
|
||||
|
||||
# Set to true to enable experimental features
|
||||
# (varies from version to version, see wiki)
|
||||
#enable_experimental = false
|
||||
|
||||
# Profiler data print interval. 0 = disable.
|
||||
#profiler_print_interval = 10
|
||||
|
||||
# Player and object positions are sent at intervals specified by this
|
||||
#objectdata_inverval = 0.2
|
||||
|
||||
|
@ -61,6 +61,13 @@ configure_file(
|
||||
)
|
||||
|
||||
set(common_SRCS
|
||||
mapgen.cpp
|
||||
content_inventory.cpp
|
||||
content_nodemeta.cpp
|
||||
content_craft.cpp
|
||||
content_mapblock.cpp
|
||||
content_mapnode.cpp
|
||||
auth.cpp
|
||||
collision.cpp
|
||||
nodemetadata.cpp
|
||||
serverobject.cpp
|
||||
@ -95,10 +102,11 @@ set(common_SRCS
|
||||
# Client sources
|
||||
set(minetest_SRCS
|
||||
${common_SRCS}
|
||||
mapblock_mesh.cpp
|
||||
farmesh.cpp
|
||||
keycode.cpp
|
||||
clouds.cpp
|
||||
clientobject.cpp
|
||||
guiFurnaceMenu.cpp
|
||||
guiMainMenu.cpp
|
||||
guiKeyChangeMenu.cpp
|
||||
guiMessageMenu.cpp
|
||||
@ -125,6 +133,7 @@ include_directories(
|
||||
${CMAKE_BUILD_TYPE}
|
||||
${PNG_INCLUDE_DIR}
|
||||
"${PROJECT_SOURCE_DIR}/jthread"
|
||||
"${PROJECT_SOURCE_DIR}/sqlite"
|
||||
)
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ../bin)
|
||||
@ -143,6 +152,7 @@ if(BUILD_CLIENT)
|
||||
${PLATFORM_LIBS}
|
||||
${CLIENT_PLATFORM_LIBS}
|
||||
jthread
|
||||
sqlite3
|
||||
)
|
||||
endif(BUILD_CLIENT)
|
||||
|
||||
@ -153,6 +163,7 @@ if(BUILD_SERVER)
|
||||
${ZLIB_LIBRARIES}
|
||||
${PLATFORM_LIBS}
|
||||
jthread
|
||||
sqlite3
|
||||
)
|
||||
endif(BUILD_SERVER)
|
||||
|
||||
@ -181,21 +192,22 @@ else()
|
||||
# Probably GCC
|
||||
|
||||
if(WARN_ALL)
|
||||
set(WARNING_FLAGS "-Wall")
|
||||
set(RELEASE_WARNING_FLAGS "-Wall")
|
||||
else()
|
||||
set(WARNING_FLAGS "")
|
||||
set(RELEASE_WARNING_FLAGS "")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT APPLE)
|
||||
set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-unused-but-set-variable")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_OSX_ARCHITECTURES i386 CACHE STRING "do not build for 64-bit" FORCE)
|
||||
set(ARCH i386)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall ${WARNING_FLAGS}")
|
||||
|
||||
if(USE_GPROF)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg")
|
||||
@ -242,5 +254,6 @@ endif(BUILD_SERVER)
|
||||
# Subdirectories
|
||||
|
||||
add_subdirectory(jthread)
|
||||
add_subdirectory(sqlite)
|
||||
|
||||
#end
|
||||
|
264
src/auth.cpp
Normal file
264
src/auth.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "auth.h"
|
||||
#include <fstream>
|
||||
#include <jmutexautolock.h>
|
||||
//#include "main.h" // for g_settings
|
||||
#include <sstream>
|
||||
#include "strfnd.h"
|
||||
#include "debug.h"
|
||||
|
||||
// Convert a privileges value into a human-readable string,
|
||||
// with each component separated by a comma.
|
||||
std::string privsToString(u64 privs)
|
||||
{
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
if(privs & PRIV_BUILD)
|
||||
os<<"build,";
|
||||
if(privs & PRIV_TELEPORT)
|
||||
os<<"teleport,";
|
||||
if(privs & PRIV_SETTIME)
|
||||
os<<"settime,";
|
||||
if(privs & PRIV_PRIVS)
|
||||
os<<"privs,";
|
||||
if(privs & PRIV_SHOUT)
|
||||
os<<"shout,";
|
||||
if(os.tellp())
|
||||
{
|
||||
// Drop the trailing comma. (Why on earth can't
|
||||
// you truncate a C++ stream anyway???)
|
||||
std::string tmp = os.str();
|
||||
return tmp.substr(0, tmp.length() -1);
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
// Converts a comma-seperated list of privilege values into a
|
||||
// privileges value. The reverse of privsToString(). Returns
|
||||
// PRIV_INVALID if there is anything wrong with the input.
|
||||
u64 stringToPrivs(std::string str)
|
||||
{
|
||||
u64 privs=0;
|
||||
Strfnd f(str);
|
||||
while(f.atend() == false)
|
||||
{
|
||||
std::string s = trim(f.next(","));
|
||||
if(s == "build")
|
||||
privs |= PRIV_BUILD;
|
||||
else if(s == "teleport")
|
||||
privs |= PRIV_TELEPORT;
|
||||
else if(s == "settime")
|
||||
privs |= PRIV_SETTIME;
|
||||
else if(s == "privs")
|
||||
privs |= PRIV_PRIVS;
|
||||
else if(s == "shout")
|
||||
privs |= PRIV_SHOUT;
|
||||
else
|
||||
return PRIV_INVALID;
|
||||
}
|
||||
return privs;
|
||||
}
|
||||
|
||||
AuthManager::AuthManager(const std::string &authfilepath):
|
||||
m_authfilepath(authfilepath),
|
||||
m_modified(false)
|
||||
{
|
||||
m_mutex.Init();
|
||||
|
||||
try{
|
||||
load();
|
||||
}
|
||||
catch(SerializationError &e)
|
||||
{
|
||||
dstream<<"WARNING: AuthManager: creating "
|
||||
<<m_authfilepath<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
AuthManager::~AuthManager()
|
||||
{
|
||||
save();
|
||||
}
|
||||
|
||||
void AuthManager::load()
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
dstream<<"AuthManager: loading from "<<m_authfilepath<<std::endl;
|
||||
std::ifstream is(m_authfilepath.c_str(), std::ios::binary);
|
||||
if(is.good() == false)
|
||||
{
|
||||
dstream<<"AuthManager: failed loading from "<<m_authfilepath<<std::endl;
|
||||
throw SerializationError("AuthManager::load(): Couldn't open file");
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(is.eof() || is.good() == false)
|
||||
break;
|
||||
|
||||
// Read a line
|
||||
std::string line;
|
||||
std::getline(is, line, '\n');
|
||||
|
||||
std::istringstream iss(line);
|
||||
|
||||
// Read name
|
||||
std::string name;
|
||||
std::getline(iss, name, ':');
|
||||
|
||||
// Read password
|
||||
std::string pwd;
|
||||
std::getline(iss, pwd, ':');
|
||||
|
||||
// Read privileges
|
||||
std::string stringprivs;
|
||||
std::getline(iss, stringprivs, ':');
|
||||
u64 privs = stringToPrivs(stringprivs);
|
||||
|
||||
// Store it
|
||||
AuthData ad;
|
||||
ad.pwd = pwd;
|
||||
ad.privs = privs;
|
||||
m_authdata[name] = ad;
|
||||
}
|
||||
|
||||
m_modified = false;
|
||||
}
|
||||
|
||||
void AuthManager::save()
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
dstream<<"AuthManager: saving to "<<m_authfilepath<<std::endl;
|
||||
std::ofstream os(m_authfilepath.c_str(), std::ios::binary);
|
||||
if(os.good() == false)
|
||||
{
|
||||
dstream<<"AuthManager: failed saving to "<<m_authfilepath<<std::endl;
|
||||
throw SerializationError("AuthManager::save(): Couldn't open file");
|
||||
}
|
||||
|
||||
for(core::map<std::string, AuthData>::Iterator
|
||||
i = m_authdata.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
std::string name = i.getNode()->getKey();
|
||||
if(name == "")
|
||||
continue;
|
||||
AuthData ad = i.getNode()->getValue();
|
||||
os<<name<<":"<<ad.pwd<<":"<<privsToString(ad.privs)<<"\n";
|
||||
}
|
||||
|
||||
m_modified = false;
|
||||
}
|
||||
|
||||
bool AuthManager::exists(const std::string &username)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::map<std::string, AuthData>::Node *n;
|
||||
n = m_authdata.find(username);
|
||||
if(n == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AuthManager::set(const std::string &username, AuthData ad)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
m_authdata[username] = ad;
|
||||
|
||||
m_modified = true;
|
||||
}
|
||||
|
||||
void AuthManager::add(const std::string &username)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
m_authdata[username] = AuthData();
|
||||
|
||||
m_modified = true;
|
||||
}
|
||||
|
||||
std::string AuthManager::getPassword(const std::string &username)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::map<std::string, AuthData>::Node *n;
|
||||
n = m_authdata.find(username);
|
||||
if(n == NULL)
|
||||
throw AuthNotFoundException("");
|
||||
|
||||
return n->getValue().pwd;
|
||||
}
|
||||
|
||||
void AuthManager::setPassword(const std::string &username,
|
||||
const std::string &password)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::map<std::string, AuthData>::Node *n;
|
||||
n = m_authdata.find(username);
|
||||
if(n == NULL)
|
||||
throw AuthNotFoundException("");
|
||||
|
||||
AuthData ad = n->getValue();
|
||||
ad.pwd = password;
|
||||
n->setValue(ad);
|
||||
|
||||
m_modified = true;
|
||||
}
|
||||
|
||||
u64 AuthManager::getPrivs(const std::string &username)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::map<std::string, AuthData>::Node *n;
|
||||
n = m_authdata.find(username);
|
||||
if(n == NULL)
|
||||
throw AuthNotFoundException("");
|
||||
|
||||
return n->getValue().privs;
|
||||
}
|
||||
|
||||
void AuthManager::setPrivs(const std::string &username, u64 privs)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::map<std::string, AuthData>::Node *n;
|
||||
n = m_authdata.find(username);
|
||||
if(n == NULL)
|
||||
throw AuthNotFoundException("");
|
||||
|
||||
AuthData ad = n->getValue();
|
||||
ad.privs = privs;
|
||||
n->setValue(ad);
|
||||
|
||||
m_modified = true;
|
||||
}
|
||||
|
||||
bool AuthManager::isModified()
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
return m_modified;
|
||||
}
|
||||
|
||||
|
101
src/auth.h
Normal file
101
src/auth.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef AUTH_HEADER
|
||||
#define AUTH_HEADER
|
||||
|
||||
#include <string>
|
||||
#include <jthread.h>
|
||||
#include <jmutex.h>
|
||||
#include "common_irrlicht.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
// Player privileges. These form a bitmask stored in the privs field
|
||||
// of the player, and define things they're allowed to do. See also
|
||||
// the static methods Player::privsToString and stringToPrivs that
|
||||
// convert these to human-readable form.
|
||||
const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world
|
||||
const u64 PRIV_TELEPORT = 2; // Can teleport
|
||||
const u64 PRIV_SETTIME = 4; // Can set the time
|
||||
const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges
|
||||
const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn
|
||||
// ,settings)
|
||||
const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all
|
||||
// players
|
||||
|
||||
// Default privileges - these can be overriden for new players using the
|
||||
// config option "default_privs" - however, this value still applies for
|
||||
// players that existed before the privileges system was added.
|
||||
const u64 PRIV_DEFAULT = PRIV_BUILD|PRIV_SHOUT;
|
||||
const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
|
||||
const u64 PRIV_INVALID = 0x8000000000000000ULL;
|
||||
|
||||
// Convert a privileges value into a human-readable string,
|
||||
// with each component separated by a comma.
|
||||
std::string privsToString(u64 privs);
|
||||
|
||||
// Converts a comma-seperated list of privilege values into a
|
||||
// privileges value. The reverse of privsToString(). Returns
|
||||
// PRIV_INVALID if there is anything wrong with the input.
|
||||
u64 stringToPrivs(std::string str);
|
||||
|
||||
struct AuthData
|
||||
{
|
||||
std::string pwd;
|
||||
u64 privs;
|
||||
|
||||
AuthData():
|
||||
privs(PRIV_DEFAULT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class AuthNotFoundException : public BaseException
|
||||
{
|
||||
public:
|
||||
AuthNotFoundException(const char *s):
|
||||
BaseException(s)
|
||||
{}
|
||||
};
|
||||
|
||||
class AuthManager
|
||||
{
|
||||
public:
|
||||
AuthManager(const std::string &authfilepath);
|
||||
~AuthManager();
|
||||
void load();
|
||||
void save();
|
||||
bool exists(const std::string &username);
|
||||
void set(const std::string &username, AuthData ad);
|
||||
void add(const std::string &username);
|
||||
std::string getPassword(const std::string &username);
|
||||
void setPassword(const std::string &username,
|
||||
const std::string &password);
|
||||
u64 getPrivs(const std::string &username);
|
||||
void setPrivs(const std::string &username, u64 privs);
|
||||
bool isModified();
|
||||
private:
|
||||
JMutex m_mutex;
|
||||
std::string m_authfilepath;
|
||||
core::map<std::string, AuthData> m_authdata;
|
||||
bool m_modified;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -71,9 +71,10 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
// Don't pad it with =
|
||||
/*while((i++ < 3))
|
||||
ret += '=';*/
|
||||
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,12 @@ void * MeshUpdateThread::Thread()
|
||||
QueuedMeshUpdate *q = m_queue_in.pop();
|
||||
if(q == NULL)
|
||||
{
|
||||
sleep_ms(50);
|
||||
sleep_ms(3);
|
||||
continue;
|
||||
}
|
||||
|
||||
ScopeProfiler sp(&g_profiler, "mesh make");
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
mesh_new = makeMapBlockMesh(q->data);
|
||||
|
||||
@ -218,12 +220,12 @@ void Client::step(float dtime)
|
||||
g_settings.getFloat("client_delete_unused_sectors_timeout");
|
||||
|
||||
// Delete sector blocks
|
||||
/*u32 num = m_env.getMap().deleteUnusedSectors
|
||||
/*u32 num = m_env.getMap().unloadUnusedData
|
||||
(delete_unused_sectors_timeout,
|
||||
true, &deleted_blocks);*/
|
||||
|
||||
// Delete whole sectors
|
||||
u32 num = m_env.getMap().deleteUnusedSectors
|
||||
u32 num = m_env.getMap().unloadUnusedData
|
||||
(delete_unused_sectors_timeout,
|
||||
false, &deleted_blocks);
|
||||
|
||||
@ -306,8 +308,14 @@ void Client::step(float dtime)
|
||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
|
||||
writeU16(&data[0], TOSERVER_INIT);
|
||||
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
||||
|
||||
memset((char*)&data[3], 0, PLAYERNAME_SIZE);
|
||||
snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
|
||||
|
||||
/*dstream<<"Client: password hash is \""<<m_password<<"\""
|
||||
<<std::endl;*/
|
||||
|
||||
memset((char*)&data[23], 0, PASSWORD_SIZE);
|
||||
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
|
||||
|
||||
// Send as unreliable
|
||||
@ -610,6 +618,13 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
// to be processed even if the serialisation format has
|
||||
// not been agreed yet, the same as TOCLIENT_INIT.
|
||||
m_access_denied = true;
|
||||
m_access_denied_reason = L"Unknown";
|
||||
if(datasize >= 4)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
m_access_denied_reason = deSerializeWideString(is);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -780,7 +795,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
*/
|
||||
|
||||
//m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
|
||||
|
||||
/*
|
||||
Add it to mesh update queue and set it to be acknowledged after update.
|
||||
*/
|
||||
addUpdateMeshTaskWithEdge(p, true);
|
||||
}
|
||||
else if(command == TOCLIENT_PLAYERPOS)
|
||||
|
@ -385,6 +385,11 @@ public:
|
||||
return m_access_denied;
|
||||
}
|
||||
|
||||
inline std::wstring accessDeniedReason()
|
||||
{
|
||||
return m_access_denied_reason;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Virtual methods from con::PeerHandler
|
||||
@ -440,10 +445,13 @@ private:
|
||||
|
||||
std::string m_password;
|
||||
bool m_access_denied;
|
||||
std::wstring m_access_denied_reason;
|
||||
|
||||
InventoryContext m_inventory_context;
|
||||
|
||||
Queue<ClientEvent> m_client_event_queue;
|
||||
|
||||
friend class FarMesh;
|
||||
};
|
||||
|
||||
#endif // !SERVER
|
||||
|
@ -24,6 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#define PROTOCOL_ID 0x4f457403
|
||||
|
||||
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||
// base64-encoded SHA-1 (27+\0).
|
||||
|
||||
enum ToClientCommand
|
||||
{
|
||||
TOCLIENT_INIT = 0x10,
|
||||
@ -154,6 +157,8 @@ enum ToClientCommand
|
||||
TOCLIENT_ACCESS_DENIED = 0x35,
|
||||
/*
|
||||
u16 command
|
||||
u16 reason_length
|
||||
wstring reason
|
||||
*/
|
||||
};
|
||||
|
||||
|
@ -58,8 +58,8 @@ void Clouds::OnRegisterSceneNode()
|
||||
{
|
||||
if(IsVisible)
|
||||
{
|
||||
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
|
||||
//SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
|
||||
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
|
||||
}
|
||||
|
||||
ISceneNode::OnRegisterSceneNode();
|
||||
|
586
src/content_craft.cpp
Normal file
586
src/content_craft.cpp
Normal file
@ -0,0 +1,586 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "content_craft.h"
|
||||
#include "inventory.h"
|
||||
#include "content_mapnode.h"
|
||||
#include "player.h"
|
||||
|
||||
/*
|
||||
items: actually *items[9]
|
||||
return value: allocates a new item, or returns NULL.
|
||||
*/
|
||||
InventoryItem *craft_get_result(InventoryItem **items)
|
||||
{
|
||||
// Wood
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_WOOD, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Stick
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new CraftItem("Stick", 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Fence
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[5] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[6] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[8] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_FENCE, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Sign
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
//return new MapBlockObjectItem("Sign");
|
||||
return new MaterialItem(CONTENT_SIGN_WALL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Torch
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_TORCH, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Wooden pick
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("WPick", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Stone pick
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("STPick", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Steel pick
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("SteelPick", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Mese pick
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("MesePick", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Wooden shovel
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("WShovel", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Stone shovel
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("STShovel", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Steel shovel
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("SteelShovel", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Wooden axe
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("WAxe", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Stone axe
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("STAxe", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Steel axe
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("SteelAxe", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Wooden sword
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("WSword", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Stone sword
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("STSword", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Steel sword
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new ToolItem("SteelSword", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Rail
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_RAIL, 15);
|
||||
}
|
||||
}
|
||||
|
||||
// Chest
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_CHEST, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Furnace
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_FURNACE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Steel block
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_STEEL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Sandstone
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
|
||||
specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
|
||||
specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
|
||||
specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_SANDSTONE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Clay
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
|
||||
specs[6] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_CLAY, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Brick
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "clay_brick");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "clay_brick");
|
||||
specs[6] = ItemSpec(ITEM_CRAFT, "clay_brick");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "clay_brick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_BRICK, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Paper
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS);
|
||||
specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS);
|
||||
specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new CraftItem("paper", 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Book
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[1] = ItemSpec(ITEM_CRAFT, "paper");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "paper");
|
||||
specs[7] = ItemSpec(ITEM_CRAFT, "paper");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new CraftItem("book", 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Book shelf
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "book");
|
||||
specs[4] = ItemSpec(ITEM_CRAFT, "book");
|
||||
specs[5] = ItemSpec(ITEM_CRAFT, "book");
|
||||
specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
return new MaterialItem(CONTENT_BOOKSHELF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void craft_set_creative_inventory(Player *player)
|
||||
{
|
||||
player->resetInventory();
|
||||
|
||||
// Give some good tools
|
||||
{
|
||||
InventoryItem *item = new ToolItem("MesePick", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("SteelPick", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("SteelAxe", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("SteelShovel", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
Give materials
|
||||
*/
|
||||
|
||||
// CONTENT_IGNORE-terminated list
|
||||
u8 material_items[] = {
|
||||
CONTENT_TORCH,
|
||||
CONTENT_COBBLE,
|
||||
CONTENT_MUD,
|
||||
CONTENT_STONE,
|
||||
CONTENT_SAND,
|
||||
CONTENT_SANDSTONE,
|
||||
CONTENT_CLAY,
|
||||
CONTENT_BRICK,
|
||||
CONTENT_TREE,
|
||||
CONTENT_LEAVES,
|
||||
CONTENT_CACTUS,
|
||||
CONTENT_PAPYRUS,
|
||||
CONTENT_BOOKSHELF,
|
||||
CONTENT_GLASS,
|
||||
CONTENT_FENCE,
|
||||
CONTENT_RAIL,
|
||||
CONTENT_MESE,
|
||||
CONTENT_WATERSOURCE,
|
||||
CONTENT_CLOUD,
|
||||
CONTENT_CHEST,
|
||||
CONTENT_FURNACE,
|
||||
CONTENT_SIGN_WALL,
|
||||
CONTENT_IGNORE
|
||||
};
|
||||
|
||||
u8 *mip = material_items;
|
||||
for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
|
||||
{
|
||||
if(*mip == CONTENT_IGNORE)
|
||||
break;
|
||||
|
||||
InventoryItem *item = new MaterialItem(*mip, 1);
|
||||
player->inventory.addItem("main", item);
|
||||
|
||||
mip++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
|
||||
|
||||
// add torch first
|
||||
InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
|
||||
player->inventory.addItem("main", item);
|
||||
|
||||
// Then others
|
||||
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
|
||||
{
|
||||
// Skip some materials
|
||||
if(i == CONTENT_WATER || i == CONTENT_TORCH
|
||||
|| i == CONTENT_COALSTONE)
|
||||
continue;
|
||||
|
||||
InventoryItem *item = new MaterialItem(i, 1);
|
||||
player->inventory.addItem("main", item);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*// Sign
|
||||
{
|
||||
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}*/
|
||||
}
|
||||
|
||||
void craft_give_initial_stuff(Player *player)
|
||||
{
|
||||
{
|
||||
InventoryItem *item = new ToolItem("SteelPick", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_TORCH, 99);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("SteelAxe", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("SteelShovel", 0);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_COBBLE, 99);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
/*{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new CraftItem("Stick", 4);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("WPick", 32000);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
{
|
||||
InventoryItem *item = new ToolItem("STPick", 32000);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}*/
|
||||
/*// and some signs
|
||||
for(u16 i=0; i<4; i++)
|
||||
{
|
||||
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
|
||||
bool r = player->inventory.addItem("main", item);
|
||||
assert(r == true);
|
||||
}*/
|
||||
/*// Give some other stuff
|
||||
{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
|
||||
bool r = player->inventory.addItem("main", item);
|
||||
assert(r == true);
|
||||
}*/
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -17,28 +17,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef GUIFURNACEMENU_HEADER
|
||||
#define GUIFURNACEMENU_HEADER
|
||||
#ifndef CONTENT_CRAFT_HEADER
|
||||
#define CONTENT_CRAFT_HEADER
|
||||
|
||||
#include "guiInventoryMenu.h"
|
||||
class InventoryItem;
|
||||
class Player;
|
||||
|
||||
class Client;
|
||||
/*
|
||||
items: actually *items[9]
|
||||
return value: allocates a new item, or returns NULL.
|
||||
*/
|
||||
InventoryItem *craft_get_result(InventoryItem **items);
|
||||
|
||||
class GUIFurnaceMenu : public GUIInventoryMenu
|
||||
{
|
||||
public:
|
||||
GUIFurnaceMenu(
|
||||
gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
v3s16 nodepos,
|
||||
Client *client
|
||||
);
|
||||
private:
|
||||
|
||||
v3s16 m_nodepos;
|
||||
Client *m_client;
|
||||
};
|
||||
void craft_set_creative_inventory(Player *player);
|
||||
|
||||
// Called when give_initial_stuff setting is used
|
||||
void craft_give_initial_stuff(Player *player);
|
||||
|
||||
#endif
|
||||
|
108
src/content_inventory.cpp
Normal file
108
src/content_inventory.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "content_inventory.h"
|
||||
#include "inventory.h"
|
||||
#include "serverobject.h"
|
||||
#include "content_mapnode.h"
|
||||
|
||||
bool item_material_is_cookable(u8 content)
|
||||
{
|
||||
if(content == CONTENT_TREE)
|
||||
return true;
|
||||
else if(content == CONTENT_COBBLE)
|
||||
return true;
|
||||
else if(content == CONTENT_SAND)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
InventoryItem* item_material_create_cook_result(u8 content)
|
||||
{
|
||||
if(content == CONTENT_TREE)
|
||||
return new CraftItem("lump_of_coal", 1);
|
||||
else if(content == CONTENT_COBBLE)
|
||||
return new MaterialItem(CONTENT_STONE, 1);
|
||||
else if(content == CONTENT_SAND)
|
||||
return new MaterialItem(CONTENT_GLASS, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string item_craft_get_image_name(const std::string &subname)
|
||||
{
|
||||
if(subname == "Stick")
|
||||
return "stick.png";
|
||||
else if(subname == "paper")
|
||||
return "paper.png";
|
||||
else if(subname == "book")
|
||||
return "book.png";
|
||||
else if(subname == "lump_of_coal")
|
||||
return "lump_of_coal.png";
|
||||
else if(subname == "lump_of_iron")
|
||||
return "lump_of_iron.png";
|
||||
else if(subname == "lump_of_clay")
|
||||
return "lump_of_clay.png";
|
||||
else if(subname == "steel_ingot")
|
||||
return "steel_ingot.png";
|
||||
else if(subname == "clay_brick")
|
||||
return "clay_brick.png";
|
||||
else if(subname == "rat")
|
||||
return "rat.png";
|
||||
else
|
||||
return "cloud.png"; // just something
|
||||
}
|
||||
|
||||
ServerActiveObject* item_craft_create_object(const std::string &subname,
|
||||
ServerEnvironment *env, u16 id, v3f pos)
|
||||
{
|
||||
if(subname == "rat")
|
||||
{
|
||||
ServerActiveObject *obj = new RatSAO(env, id, pos);
|
||||
return obj;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s16 item_craft_get_drop_count(const std::string &subname)
|
||||
{
|
||||
if(subname == "rat")
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool item_craft_is_cookable(const std::string &subname)
|
||||
{
|
||||
if(subname == "lump_of_iron" || subname == "lump_of_clay")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
InventoryItem* item_craft_create_cook_result(const std::string &subname)
|
||||
{
|
||||
if(subname == "lump_of_iron")
|
||||
return new CraftItem("steel_ingot", 1);
|
||||
else if(subname == "lump_of_clay")
|
||||
return new CraftItem("clay_brick", 1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
41
src/content_inventory.h
Normal file
41
src/content_inventory.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef CONTENT_INVENTORY_HEADER
|
||||
#define CONTENT_INVENTORY_HEADER
|
||||
|
||||
#include "common_irrlicht.h" // For u8, s16
|
||||
#include <string>
|
||||
|
||||
class InventoryItem;
|
||||
class ServerActiveObject;
|
||||
class ServerEnvironment;
|
||||
|
||||
bool item_material_is_cookable(u8 content);
|
||||
InventoryItem* item_material_create_cook_result(u8 content);
|
||||
|
||||
std::string item_craft_get_image_name(const std::string &subname);
|
||||
ServerActiveObject* item_craft_create_object(const std::string &subname,
|
||||
ServerEnvironment *env, u16 id, v3f pos);
|
||||
s16 item_craft_get_drop_count(const std::string &subname);
|
||||
bool item_craft_is_cookable(const std::string &subname);
|
||||
InventoryItem* item_craft_create_cook_result(const std::string &subname);
|
||||
|
||||
#endif
|
||||
|
1076
src/content_mapblock.cpp
Normal file
1076
src/content_mapblock.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -17,3 +17,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef CONTENT_MAPBLOCK_HEADER
|
||||
#define CONTENT_MAPBLOCK_HEADER
|
||||
|
||||
#ifndef SERVER
|
||||
#include "mapblock_mesh.h"
|
||||
#include "utility.h"
|
||||
void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
MeshCollector &collector);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
450
src/content_mapnode.cpp
Normal file
450
src/content_mapnode.cpp
Normal file
@ -0,0 +1,450 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
// For g_settings
|
||||
#include "main.h"
|
||||
|
||||
#include "content_mapnode.h"
|
||||
#include "mapnode.h"
|
||||
#include "content_nodemeta.h"
|
||||
|
||||
// TODO: Get rid of these and set up some attributes like toughness,
|
||||
// fluffyness, and a funciton to calculate time and durability loss
|
||||
// (and sound? and whatever else) from them
|
||||
void setStoneLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
|
||||
void setDirtLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
|
||||
void setWoodLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
|
||||
|
||||
void content_mapnode_init()
|
||||
{
|
||||
// Read some settings
|
||||
bool new_style_water = g_settings.getBool("new_style_water");
|
||||
bool new_style_leaves = g_settings.getBool("new_style_leaves");
|
||||
bool invisible_stone = g_settings.getBool("invisible_stone");
|
||||
|
||||
u8 i;
|
||||
ContentFeatures *f = NULL;
|
||||
|
||||
i = CONTENT_STONE;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("stone.png");
|
||||
f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 1";
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
if(invisible_stone)
|
||||
f->solidness = 0; // For debugging, hides regular stone
|
||||
|
||||
i = CONTENT_GRASS;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("mud.png^grass_side.png");
|
||||
f->setTexture(0, "grass.png");
|
||||
f->setTexture(1, "mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_MUD)+" 1";
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_GRASS_FOOTSTEPS;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("mud.png^grass_side.png");
|
||||
f->setTexture(0, "grass_footsteps.png");
|
||||
f->setTexture(1, "mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_MUD)+" 1";
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_MUD;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("mud.png");
|
||||
f->setInventoryTextureCube("mud.png", "mud.png", "mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_SAND;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("sand.png");
|
||||
f->setInventoryTextureCube("sand.png", "sand.png", "sand.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_GRAVEL;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("gravel.png");
|
||||
f->setInventoryTextureCube("gravel.png", "gravel.png", "gravel.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.75);
|
||||
|
||||
i = CONTENT_SANDSTONE;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("sandstone.png");
|
||||
f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_SAND)+" 1";
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_CLAY;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("clay.png");
|
||||
f->setInventoryTextureCube("clay.png", "clay.png", "clay.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("CraftItem lump_of_clay 4");
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_BRICK;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("brick.png");
|
||||
f->setInventoryTextureCube("brick.png", "brick.png", "brick.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("CraftItem clay_brick 4");
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_TREE;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("tree.png");
|
||||
f->setTexture(0, "tree_top.png");
|
||||
f->setTexture(1, "tree_top.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_LEAVES;
|
||||
f = &content_features(i);
|
||||
f->light_propagates = true;
|
||||
//f->param_type = CPT_MINERAL;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
if(new_style_leaves)
|
||||
{
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
f->setAllTextures("[noalpha:leaves.png");
|
||||
}
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.15);
|
||||
|
||||
i = CONTENT_CACTUS;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("cactus_side.png");
|
||||
f->setTexture(0, "cactus_top.png");
|
||||
f->setTexture(1, "cactus_top.png");
|
||||
f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
|
||||
|
||||
i = CONTENT_PAPYRUS;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("papyrus.png");
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.25);
|
||||
|
||||
i = CONTENT_BOOKSHELF;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("bookshelf.png");
|
||||
f->setTexture(0, "wood.png");
|
||||
f->setTexture(1, "wood.png");
|
||||
// FIXME: setInventoryTextureCube() only cares for the first texture
|
||||
f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png");
|
||||
//f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
|
||||
|
||||
i = CONTENT_GLASS;
|
||||
f = &content_features(i);
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->setInventoryTextureCube("glass.png", "glass.png", "glass.png");
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.15);
|
||||
|
||||
i = CONTENT_FENCE;
|
||||
f = &content_features(i);
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->air_equivalent = true; // grass grows underneath
|
||||
f->setInventoryTexture("item_fence.png");
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
|
||||
|
||||
i = CONTENT_RAIL;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("rail.png");
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->air_equivalent = true; // grass grows underneath
|
||||
f->walkable = false;
|
||||
setDirtLikeDiggingProperties(f->digging_properties, 0.75);
|
||||
|
||||
// Deprecated
|
||||
i = CONTENT_COALSTONE;
|
||||
f = &content_features(i);
|
||||
//f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
|
||||
f->setAllTextures("stone.png^mineral_coal.png");
|
||||
f->is_ground_content = true;
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 1.5);
|
||||
|
||||
i = CONTENT_WOOD;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("wood.png");
|
||||
f->setInventoryTextureCube("wood.png", "wood.png", "wood.png");
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
|
||||
|
||||
i = CONTENT_MESE;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("mese.png");
|
||||
f->setInventoryTextureCube("mese.png", "mese.png", "mese.png");
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 0.5);
|
||||
|
||||
i = CONTENT_CLOUD;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("cloud.png");
|
||||
f->setInventoryTextureCube("cloud.png", "cloud.png", "cloud.png");
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_AIR;
|
||||
f = &content_features(i);
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
f->solidness = 0;
|
||||
f->walkable = false;
|
||||
f->pointable = false;
|
||||
f->diggable = false;
|
||||
f->buildable_to = true;
|
||||
f->air_equivalent = true;
|
||||
|
||||
i = CONTENT_WATER;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTextureCube("water.png", "water.png", "water.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->solidness = 0; // Drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
f->pointable = false;
|
||||
f->diggable = false;
|
||||
f->buildable_to = true;
|
||||
f->liquid_type = LIQUID_FLOWING;
|
||||
f->liquid_alternative_flowing = CONTENT_WATER;
|
||||
|
||||
i = CONTENT_WATERSOURCE;
|
||||
f = &content_features(i);
|
||||
//f->setInventoryTexture("water.png");
|
||||
f->setInventoryTextureCube("water.png", "water.png", "water.png");
|
||||
if(new_style_water)
|
||||
{
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
}
|
||||
else // old style
|
||||
{
|
||||
f->solidness = 1;
|
||||
|
||||
TileSpec t;
|
||||
if(g_texturesource)
|
||||
t.texture = g_texturesource->getTexture("water.png");
|
||||
|
||||
t.alpha = WATER_ALPHA;
|
||||
t.material_type = MATERIAL_ALPHA_VERTEX;
|
||||
t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
f->setAllTiles(t);
|
||||
}
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->walkable = false;
|
||||
f->pointable = false;
|
||||
f->diggable = false;
|
||||
f->buildable_to = true;
|
||||
f->liquid_type = LIQUID_SOURCE;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->liquid_alternative_flowing = CONTENT_WATER;
|
||||
|
||||
i = CONTENT_TORCH;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("torch_on_floor.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
f->wall_mounted = true;
|
||||
f->air_equivalent = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->light_source = LIGHT_MAX-1;
|
||||
f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
|
||||
|
||||
i = CONTENT_SIGN_WALL;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("sign_wall.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
f->wall_mounted = true;
|
||||
f->air_equivalent = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
if(f->initial_metadata == NULL)
|
||||
f->initial_metadata = new SignNodeMetadata("Some sign");
|
||||
f->digging_properties.set("", DiggingProperties(true, 0.5, 0));
|
||||
|
||||
i = CONTENT_CHEST;
|
||||
f = &content_features(i);
|
||||
f->param_type = CPT_FACEDIR_SIMPLE;
|
||||
f->setAllTextures("chest_side.png");
|
||||
f->setTexture(0, "chest_top.png");
|
||||
f->setTexture(1, "chest_top.png");
|
||||
f->setTexture(5, "chest_front.png"); // Z-
|
||||
f->setInventoryTexture("chest_top.png");
|
||||
//f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
if(f->initial_metadata == NULL)
|
||||
f->initial_metadata = new ChestNodeMetadata();
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
|
||||
i = CONTENT_FURNACE;
|
||||
f = &content_features(i);
|
||||
f->param_type = CPT_FACEDIR_SIMPLE;
|
||||
f->setAllTextures("furnace_side.png");
|
||||
f->setTexture(5, "furnace_front.png"); // Z-
|
||||
f->setInventoryTexture("furnace_front.png");
|
||||
//f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 6";
|
||||
if(f->initial_metadata == NULL)
|
||||
f->initial_metadata = new FurnaceNodeMetadata();
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 3.0);
|
||||
|
||||
i = CONTENT_COBBLE;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("cobble.png");
|
||||
f->setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png");
|
||||
f->param_type = CPT_NONE;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 0.9);
|
||||
|
||||
i = CONTENT_MOSSYCOBBLE;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("mossycobble.png");
|
||||
f->setInventoryTextureCube("mossycobble.png", "mossycobble.png", "mossycobble.png");
|
||||
f->param_type = CPT_NONE;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
|
||||
|
||||
i = CONTENT_STEEL;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("steel_block.png");
|
||||
f->setInventoryTextureCube("steel_block.png", "steel_block.png",
|
||||
"steel_block.png");
|
||||
f->param_type = CPT_NONE;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 5.0);
|
||||
|
||||
// NOTE: Remember to add frequently used stuff to the texture atlas in tile.cpp
|
||||
|
||||
|
||||
/*
|
||||
Add MesePick to everything
|
||||
*/
|
||||
for(u16 i=0; i<256; i++)
|
||||
{
|
||||
content_features(i).digging_properties.set("MesePick",
|
||||
DiggingProperties(true, 0.0, 65535./1337));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setStoneLikeDiggingProperties(DiggingPropertiesList &list, float toughness)
|
||||
{
|
||||
list.set("",
|
||||
DiggingProperties(true, 15.0*toughness, 0));
|
||||
|
||||
list.set("WPick",
|
||||
DiggingProperties(true, 1.3*toughness, 65535./30.*toughness));
|
||||
list.set("STPick",
|
||||
DiggingProperties(true, 0.75*toughness, 65535./100.*toughness));
|
||||
list.set("SteelPick",
|
||||
DiggingProperties(true, 0.50*toughness, 65535./333.*toughness));
|
||||
|
||||
/*list.set("MesePick",
|
||||
DiggingProperties(true, 0.0*toughness, 65535./20.*toughness));*/
|
||||
}
|
||||
|
||||
void setDirtLikeDiggingProperties(DiggingPropertiesList &list, float toughness)
|
||||
{
|
||||
list.set("",
|
||||
DiggingProperties(true, 0.75*toughness, 0));
|
||||
|
||||
list.set("WShovel",
|
||||
DiggingProperties(true, 0.4*toughness, 65535./50.*toughness));
|
||||
list.set("STShovel",
|
||||
DiggingProperties(true, 0.2*toughness, 65535./150.*toughness));
|
||||
list.set("SteelShovel",
|
||||
DiggingProperties(true, 0.15*toughness, 65535./400.*toughness));
|
||||
}
|
||||
|
||||
void setWoodLikeDiggingProperties(DiggingPropertiesList &list, float toughness)
|
||||
{
|
||||
list.set("",
|
||||
DiggingProperties(true, 3.0*toughness, 0));
|
||||
|
||||
list.set("WAxe",
|
||||
DiggingProperties(true, 1.5*toughness, 65535./30.*toughness));
|
||||
list.set("STAxe",
|
||||
DiggingProperties(true, 0.75*toughness, 65535./100.*toughness));
|
||||
list.set("SteelAxe",
|
||||
DiggingProperties(true, 0.5*toughness, 65535./333.*toughness));
|
||||
}
|
||||
|
||||
|
62
src/content_mapnode.h
Normal file
62
src/content_mapnode.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef CONTENT_MAPNODE_HEADER
|
||||
#define CONTENT_MAPNODE_HEADER
|
||||
|
||||
void content_mapnode_init();
|
||||
|
||||
/*
|
||||
Node content type IDs
|
||||
*/
|
||||
#define CONTENT_STONE 0
|
||||
#define CONTENT_GRASS 1
|
||||
#define CONTENT_WATER 2
|
||||
#define CONTENT_TORCH 3
|
||||
#define CONTENT_TREE 4
|
||||
#define CONTENT_LEAVES 5
|
||||
#define CONTENT_GRASS_FOOTSTEPS 6
|
||||
#define CONTENT_MESE 7
|
||||
#define CONTENT_MUD 8
|
||||
#define CONTENT_WATERSOURCE 9
|
||||
// Pretty much useless, clouds won't be drawn this way
|
||||
#define CONTENT_CLOUD 10
|
||||
#define CONTENT_COALSTONE 11
|
||||
#define CONTENT_WOOD 12
|
||||
#define CONTENT_SAND 13
|
||||
#define CONTENT_SIGN_WALL 14
|
||||
#define CONTENT_CHEST 15
|
||||
#define CONTENT_FURNACE 16
|
||||
//#define CONTENT_WORKBENCH 17
|
||||
#define CONTENT_COBBLE 18
|
||||
#define CONTENT_STEEL 19
|
||||
#define CONTENT_GLASS 20
|
||||
#define CONTENT_FENCE 21
|
||||
#define CONTENT_MOSSYCOBBLE 22
|
||||
#define CONTENT_GRAVEL 23
|
||||
#define CONTENT_SANDSTONE 24
|
||||
#define CONTENT_CACTUS 25
|
||||
#define CONTENT_BRICK 26
|
||||
#define CONTENT_CLAY 27
|
||||
#define CONTENT_PAPYRUS 28
|
||||
#define CONTENT_BOOKSHELF 29
|
||||
#define CONTENT_RAIL 30
|
||||
|
||||
#endif
|
||||
|
321
src/content_nodemeta.cpp
Normal file
321
src/content_nodemeta.cpp
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "content_nodemeta.h"
|
||||
#include "inventory.h"
|
||||
#include "content_mapnode.h"
|
||||
|
||||
/*
|
||||
SignNodeMetadata
|
||||
*/
|
||||
|
||||
// Prototype
|
||||
SignNodeMetadata proto_SignNodeMetadata("");
|
||||
|
||||
SignNodeMetadata::SignNodeMetadata(std::string text):
|
||||
m_text(text)
|
||||
{
|
||||
NodeMetadata::registerType(typeId(), create);
|
||||
}
|
||||
u16 SignNodeMetadata::typeId() const
|
||||
{
|
||||
return CONTENT_SIGN_WALL;
|
||||
}
|
||||
NodeMetadata* SignNodeMetadata::create(std::istream &is)
|
||||
{
|
||||
std::string text = deSerializeString(is);
|
||||
return new SignNodeMetadata(text);
|
||||
}
|
||||
NodeMetadata* SignNodeMetadata::clone()
|
||||
{
|
||||
return new SignNodeMetadata(m_text);
|
||||
}
|
||||
void SignNodeMetadata::serializeBody(std::ostream &os)
|
||||
{
|
||||
os<<serializeString(m_text);
|
||||
}
|
||||
std::string SignNodeMetadata::infoText()
|
||||
{
|
||||
return std::string("\"")+m_text+"\"";
|
||||
}
|
||||
|
||||
/*
|
||||
ChestNodeMetadata
|
||||
*/
|
||||
|
||||
// Prototype
|
||||
ChestNodeMetadata proto_ChestNodeMetadata;
|
||||
|
||||
ChestNodeMetadata::ChestNodeMetadata()
|
||||
{
|
||||
NodeMetadata::registerType(typeId(), create);
|
||||
|
||||
m_inventory = new Inventory();
|
||||
m_inventory->addList("0", 8*4);
|
||||
}
|
||||
ChestNodeMetadata::~ChestNodeMetadata()
|
||||
{
|
||||
delete m_inventory;
|
||||
}
|
||||
u16 ChestNodeMetadata::typeId() const
|
||||
{
|
||||
return CONTENT_CHEST;
|
||||
}
|
||||
NodeMetadata* ChestNodeMetadata::create(std::istream &is)
|
||||
{
|
||||
ChestNodeMetadata *d = new ChestNodeMetadata();
|
||||
d->m_inventory->deSerialize(is);
|
||||
return d;
|
||||
}
|
||||
NodeMetadata* ChestNodeMetadata::clone()
|
||||
{
|
||||
ChestNodeMetadata *d = new ChestNodeMetadata();
|
||||
*d->m_inventory = *m_inventory;
|
||||
return d;
|
||||
}
|
||||
void ChestNodeMetadata::serializeBody(std::ostream &os)
|
||||
{
|
||||
m_inventory->serialize(os);
|
||||
}
|
||||
std::string ChestNodeMetadata::infoText()
|
||||
{
|
||||
return "Chest";
|
||||
}
|
||||
bool ChestNodeMetadata::nodeRemovalDisabled()
|
||||
{
|
||||
/*
|
||||
Disable removal if chest contains something
|
||||
*/
|
||||
InventoryList *list = m_inventory->getList("0");
|
||||
if(list == NULL)
|
||||
return false;
|
||||
if(list->getUsedSlots() == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
std::string ChestNodeMetadata::getInventoryDrawSpecString()
|
||||
{
|
||||
return
|
||||
"invsize[8,9;]"
|
||||
"list[current_name;0;0,0;8,4;]"
|
||||
"list[current_player;main;0,5;8,4;]";
|
||||
}
|
||||
|
||||
/*
|
||||
FurnaceNodeMetadata
|
||||
*/
|
||||
|
||||
// Prototype
|
||||
FurnaceNodeMetadata proto_FurnaceNodeMetadata;
|
||||
|
||||
FurnaceNodeMetadata::FurnaceNodeMetadata()
|
||||
{
|
||||
NodeMetadata::registerType(typeId(), create);
|
||||
|
||||
m_inventory = new Inventory();
|
||||
m_inventory->addList("fuel", 1);
|
||||
m_inventory->addList("src", 1);
|
||||
m_inventory->addList("dst", 4);
|
||||
|
||||
m_step_accumulator = 0;
|
||||
m_fuel_totaltime = 0;
|
||||
m_fuel_time = 0;
|
||||
m_src_totaltime = 0;
|
||||
m_src_time = 0;
|
||||
}
|
||||
FurnaceNodeMetadata::~FurnaceNodeMetadata()
|
||||
{
|
||||
delete m_inventory;
|
||||
}
|
||||
u16 FurnaceNodeMetadata::typeId() const
|
||||
{
|
||||
return CONTENT_FURNACE;
|
||||
}
|
||||
NodeMetadata* FurnaceNodeMetadata::clone()
|
||||
{
|
||||
FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
|
||||
*d->m_inventory = *m_inventory;
|
||||
return d;
|
||||
}
|
||||
NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
|
||||
{
|
||||
FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
|
||||
|
||||
d->m_inventory->deSerialize(is);
|
||||
|
||||
int temp;
|
||||
is>>temp;
|
||||
d->m_fuel_totaltime = (float)temp/10;
|
||||
is>>temp;
|
||||
d->m_fuel_time = (float)temp/10;
|
||||
|
||||
return d;
|
||||
}
|
||||
void FurnaceNodeMetadata::serializeBody(std::ostream &os)
|
||||
{
|
||||
m_inventory->serialize(os);
|
||||
os<<itos(m_fuel_totaltime*10)<<" ";
|
||||
os<<itos(m_fuel_time*10)<<" ";
|
||||
}
|
||||
std::string FurnaceNodeMetadata::infoText()
|
||||
{
|
||||
//return "Furnace";
|
||||
if(m_fuel_time >= m_fuel_totaltime)
|
||||
{
|
||||
InventoryList *src_list = m_inventory->getList("src");
|
||||
assert(src_list);
|
||||
InventoryItem *src_item = src_list->getItem(0);
|
||||
|
||||
if(src_item)
|
||||
return "Furnace is out of fuel";
|
||||
else
|
||||
return "Furnace is inactive";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string s = "Furnace is active (";
|
||||
s += itos(m_fuel_time/m_fuel_totaltime*100);
|
||||
s += "%)";
|
||||
return s;
|
||||
}
|
||||
}
|
||||
void FurnaceNodeMetadata::inventoryModified()
|
||||
{
|
||||
dstream<<"Furnace inventory modification callback"<<std::endl;
|
||||
}
|
||||
bool FurnaceNodeMetadata::step(float dtime)
|
||||
{
|
||||
if(dtime > 60.0)
|
||||
dstream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
|
||||
// Update at a fixed frequency
|
||||
const float interval = 2.0;
|
||||
m_step_accumulator += dtime;
|
||||
bool changed = false;
|
||||
while(m_step_accumulator > interval)
|
||||
{
|
||||
m_step_accumulator -= interval;
|
||||
dtime = interval;
|
||||
|
||||
//dstream<<"Furnace step dtime="<<dtime<<std::endl;
|
||||
|
||||
InventoryList *dst_list = m_inventory->getList("dst");
|
||||
assert(dst_list);
|
||||
|
||||
InventoryList *src_list = m_inventory->getList("src");
|
||||
assert(src_list);
|
||||
InventoryItem *src_item = src_list->getItem(0);
|
||||
|
||||
// Start only if there are free slots in dst, so that it can
|
||||
// accomodate any result item
|
||||
if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable())
|
||||
{
|
||||
m_src_totaltime = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_src_time = 0;
|
||||
m_src_totaltime = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
If fuel is burning, increment the burn counters.
|
||||
If item finishes cooking, move it to result.
|
||||
*/
|
||||
if(m_fuel_time < m_fuel_totaltime)
|
||||
{
|
||||
//dstream<<"Furnace is active"<<std::endl;
|
||||
m_fuel_time += dtime;
|
||||
m_src_time += dtime;
|
||||
if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
|
||||
&& src_item)
|
||||
{
|
||||
InventoryItem *cookresult = src_item->createCookResult();
|
||||
dst_list->addItem(cookresult);
|
||||
src_list->decrementMaterials(1);
|
||||
m_src_time = 0;
|
||||
m_src_totaltime = 0;
|
||||
}
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
If there is no source item or source item is not cookable, stop loop.
|
||||
*/
|
||||
if(src_item == NULL || m_src_totaltime < 0.001)
|
||||
{
|
||||
m_step_accumulator = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
//dstream<<"Furnace is out of fuel"<<std::endl;
|
||||
|
||||
InventoryList *fuel_list = m_inventory->getList("fuel");
|
||||
assert(fuel_list);
|
||||
InventoryItem *fuel_item = fuel_list->getItem(0);
|
||||
|
||||
if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 30;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 30/4;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 30/4/4;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 40;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//dstream<<"No fuel found"<<std::endl;
|
||||
// No fuel, stop loop.
|
||||
m_step_accumulator = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
|
||||
{
|
||||
return
|
||||
"invsize[8,9;]"
|
||||
"list[current_name;fuel;2,3;1,1;]"
|
||||
"list[current_name;src;2,1;1,1;]"
|
||||
"list[current_name;dst;5,1;2,2;]"
|
||||
"list[current_player;main;0,5;8,4;]";
|
||||
}
|
||||
|
||||
|
92
src/content_nodemeta.h
Normal file
92
src/content_nodemeta.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef CONTENT_NODEMETA_HEADER
|
||||
#define CONTENT_NODEMETA_HEADER
|
||||
|
||||
#include "nodemetadata.h"
|
||||
|
||||
class Inventory;
|
||||
|
||||
class SignNodeMetadata : public NodeMetadata
|
||||
{
|
||||
public:
|
||||
SignNodeMetadata(std::string text);
|
||||
//~SignNodeMetadata();
|
||||
|
||||
virtual u16 typeId() const;
|
||||
static NodeMetadata* create(std::istream &is);
|
||||
virtual NodeMetadata* clone();
|
||||
virtual void serializeBody(std::ostream &os);
|
||||
virtual std::string infoText();
|
||||
|
||||
std::string getText(){ return m_text; }
|
||||
void setText(std::string t){ m_text = t; }
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
};
|
||||
|
||||
class ChestNodeMetadata : public NodeMetadata
|
||||
{
|
||||
public:
|
||||
ChestNodeMetadata();
|
||||
~ChestNodeMetadata();
|
||||
|
||||
virtual u16 typeId() const;
|
||||
static NodeMetadata* create(std::istream &is);
|
||||
virtual NodeMetadata* clone();
|
||||
virtual void serializeBody(std::ostream &os);
|
||||
virtual std::string infoText();
|
||||
virtual Inventory* getInventory() {return m_inventory;}
|
||||
virtual bool nodeRemovalDisabled();
|
||||
virtual std::string getInventoryDrawSpecString();
|
||||
|
||||
private:
|
||||
Inventory *m_inventory;
|
||||
};
|
||||
|
||||
class FurnaceNodeMetadata : public NodeMetadata
|
||||
{
|
||||
public:
|
||||
FurnaceNodeMetadata();
|
||||
~FurnaceNodeMetadata();
|
||||
|
||||
virtual u16 typeId() const;
|
||||
virtual NodeMetadata* clone();
|
||||
static NodeMetadata* create(std::istream &is);
|
||||
virtual void serializeBody(std::ostream &os);
|
||||
virtual std::string infoText();
|
||||
virtual Inventory* getInventory() {return m_inventory;}
|
||||
virtual void inventoryModified();
|
||||
virtual bool step(float dtime);
|
||||
virtual std::string getInventoryDrawSpecString();
|
||||
|
||||
private:
|
||||
Inventory *m_inventory;
|
||||
float m_step_accumulator;
|
||||
float m_fuel_totaltime;
|
||||
float m_fuel_time;
|
||||
float m_src_totaltime;
|
||||
float m_src_time;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -49,7 +49,7 @@ void set_default_settings()
|
||||
g_settings.setDefault("wanted_fps", "30");
|
||||
g_settings.setDefault("fps_max", "60");
|
||||
g_settings.setDefault("viewing_range_nodes_max", "300");
|
||||
g_settings.setDefault("viewing_range_nodes_min", "35");
|
||||
g_settings.setDefault("viewing_range_nodes_min", "25");
|
||||
g_settings.setDefault("screenW", "800");
|
||||
g_settings.setDefault("screenH", "600");
|
||||
g_settings.setDefault("address", "");
|
||||
@ -63,22 +63,28 @@ void set_default_settings()
|
||||
g_settings.setDefault("enable_texture_atlas", "true");
|
||||
g_settings.setDefault("texture_path", "");
|
||||
g_settings.setDefault("video_driver", "opengl");
|
||||
|
||||
g_settings.setDefault("free_move", "false");
|
||||
g_settings.setDefault("continuous_forward", "false");
|
||||
g_settings.setDefault("fast_move", "false");
|
||||
g_settings.setDefault("invert_mouse", "false");
|
||||
g_settings.setDefault("enable_farmesh", "false");
|
||||
g_settings.setDefault("enable_clouds", "true");
|
||||
g_settings.setDefault("invisible_stone", "false");
|
||||
|
||||
// Server stuff
|
||||
g_settings.setDefault("enable_experimental", "false");
|
||||
g_settings.setDefault("creative_mode", "false");
|
||||
g_settings.setDefault("enable_damage", "false"); //TODO: Set to true
|
||||
g_settings.setDefault("enable_damage", "false"); //TODO: Set to true when healing is possible
|
||||
g_settings.setDefault("give_initial_stuff", "false");
|
||||
g_settings.setDefault("default_password", "");
|
||||
g_settings.setDefault("default_privs", "build, shout");
|
||||
g_settings.setDefault("profiler_print_interval", "0");
|
||||
|
||||
g_settings.setDefault("objectdata_interval", "0.2");
|
||||
g_settings.setDefault("active_object_range", "2");
|
||||
g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
|
||||
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "2");
|
||||
g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");
|
||||
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
|
||||
g_settings.setDefault("max_simultaneous_block_sends_per_client", "2");
|
||||
g_settings.setDefault("max_simultaneous_block_sends_server_total", "8");
|
||||
g_settings.setDefault("max_block_send_distance", "8");
|
||||
g_settings.setDefault("max_block_generate_distance", "8");
|
||||
g_settings.setDefault("time_send_interval", "20");
|
||||
@ -86,5 +92,6 @@ void set_default_settings()
|
||||
g_settings.setDefault("server_unload_unused_sectors_timeout", "60");
|
||||
g_settings.setDefault("server_map_save_interval", "60");
|
||||
g_settings.setDefault("full_block_send_enable_min_time_from_building", "2.0");
|
||||
//g_settings.setDefault("dungeon_rarity", "0.025");
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "filesys.h"
|
||||
#include "porting.h"
|
||||
#include "collision.h"
|
||||
#include "content_mapnode.h"
|
||||
|
||||
|
||||
Environment::Environment():
|
||||
@ -426,7 +427,14 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
|
||||
testplayer.deSerialize(is);
|
||||
}
|
||||
|
||||
dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
|
||||
if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
|
||||
{
|
||||
dstream<<"Not loading player with invalid name: "
|
||||
<<testplayer.getName()<<std::endl;
|
||||
}
|
||||
|
||||
dstream<<"Loaded test player with name "<<testplayer.getName()
|
||||
<<std::endl;
|
||||
|
||||
// Search for the player
|
||||
std::string playername = testplayer.getName();
|
||||
@ -571,6 +579,66 @@ void spawnRandomObjects(MapBlock *block)
|
||||
}
|
||||
#endif
|
||||
|
||||
void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
|
||||
{
|
||||
// Get time difference
|
||||
u32 dtime_s = 0;
|
||||
u32 stamp = block->getTimestamp();
|
||||
if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
|
||||
dtime_s = m_game_time - block->getTimestamp();
|
||||
dtime_s += additional_dtime;
|
||||
|
||||
// Set current time as timestamp (and let it set ChangedFlag)
|
||||
block->setTimestamp(m_game_time);
|
||||
|
||||
//dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
|
||||
|
||||
// Activate stored objects
|
||||
activateObjects(block);
|
||||
|
||||
// Run node metadata
|
||||
bool changed = block->m_node_metadata.step((float)dtime_s);
|
||||
if(changed)
|
||||
{
|
||||
MapEditEvent event;
|
||||
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
|
||||
event.p = block->getPos();
|
||||
m_map->dispatchEvent(&event);
|
||||
|
||||
block->setChangedFlag();
|
||||
}
|
||||
|
||||
// TODO: Do something
|
||||
// TODO: Implement usage of ActiveBlockModifier
|
||||
|
||||
// Here's a quick demonstration
|
||||
v3s16 p0;
|
||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
|
||||
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
|
||||
{
|
||||
v3s16 p = p0 + block->getPosRelative();
|
||||
MapNode n = block->getNodeNoEx(p0);
|
||||
#if 1
|
||||
// Test something:
|
||||
// Convert all mud under proper day lighting to grass
|
||||
if(n.d == CONTENT_MUD)
|
||||
{
|
||||
if(dtime_s > 300)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(content_features(n_top.d).air_equivalent &&
|
||||
n_top.getLight(LIGHTBANK_DAY) >= 13)
|
||||
{
|
||||
n.d = CONTENT_GRASS;
|
||||
m_map->addNodeWithEvent(p, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ServerEnvironment::step(float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
@ -686,8 +754,8 @@ void ServerEnvironment::step(float dtime)
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
|
||||
// Set current time as timestamp
|
||||
// Set current time as timestamp (and let it set ChangedFlag)
|
||||
|
||||
block->setTimestamp(m_game_time);
|
||||
}
|
||||
|
||||
@ -707,23 +775,36 @@ void ServerEnvironment::step(float dtime)
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
|
||||
|
||||
// Get time difference
|
||||
u32 dtime_s = 0;
|
||||
u32 stamp = block->getTimestamp();
|
||||
if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
|
||||
dtime_s = m_game_time - block->getTimestamp();
|
||||
|
||||
// Set current time as timestamp
|
||||
// Set current time as timestamp (and let it set ChangedFlag)
|
||||
block->setTimestamp(m_game_time);
|
||||
|
||||
//dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
|
||||
|
||||
|
||||
// Activate stored objects
|
||||
activateObjects(block);
|
||||
|
||||
// Run node metadata
|
||||
bool changed = block->m_node_metadata.step((float)dtime_s);
|
||||
if(changed)
|
||||
{
|
||||
MapEditEvent event;
|
||||
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
|
||||
event.p = p;
|
||||
m_map->dispatchEvent(&event);
|
||||
|
||||
block->setChangedFlag();
|
||||
}
|
||||
|
||||
// TODO: Do something
|
||||
|
||||
// TODO: Implement usage of ActiveBlockModifier
|
||||
|
||||
// Here's a quick demonstration
|
||||
v3s16 p0;
|
||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||
@ -736,7 +817,7 @@ void ServerEnvironment::step(float dtime)
|
||||
// Convert all mud under proper day lighting to grass
|
||||
if(n.d == CONTENT_MUD)
|
||||
{
|
||||
if(1)
|
||||
if(dtime_s > 300)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(content_features(n_top.d).air_equivalent &&
|
||||
@ -747,6 +828,22 @@ void ServerEnvironment::step(float dtime)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Convert grass into mud if under something else than air
|
||||
*/
|
||||
else if(n.d == CONTENT_GRASS)
|
||||
{
|
||||
//if(myrand()%20 == 0)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(n_top.d != CONTENT_AIR
|
||||
&& n_top.d != CONTENT_IGNORE)
|
||||
{
|
||||
n.d = CONTENT_MUD;
|
||||
m_map->addNodeWithEvent(p, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -754,8 +851,10 @@ void ServerEnvironment::step(float dtime)
|
||||
/*
|
||||
Mess around in active blocks
|
||||
*/
|
||||
if(m_active_blocks_test_interval.step(dtime, 5.0))
|
||||
if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
|
||||
{
|
||||
float dtime = 1.0;
|
||||
|
||||
for(core::map<v3s16, bool>::Iterator
|
||||
i = m_active_blocks.m_list.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
@ -770,8 +869,41 @@ void ServerEnvironment::step(float dtime)
|
||||
continue;
|
||||
|
||||
// Set current time as timestamp
|
||||
block->setTimestamp(m_game_time);
|
||||
block->setTimestampNoChangedFlag(m_game_time);
|
||||
|
||||
// Run node metadata
|
||||
bool changed = block->m_node_metadata.step(dtime);
|
||||
if(changed)
|
||||
{
|
||||
MapEditEvent event;
|
||||
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
|
||||
event.p = p;
|
||||
m_map->dispatchEvent(&event);
|
||||
|
||||
block->setChangedFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_active_blocks_test_interval.step(dtime, 10.0))
|
||||
{
|
||||
//float dtime = 10.0;
|
||||
|
||||
for(core::map<v3s16, bool>::Iterator
|
||||
i = m_active_blocks.m_list.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
|
||||
/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
|
||||
<<") being handled"<<std::endl;*/
|
||||
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
|
||||
// Set current time as timestamp
|
||||
block->setTimestampNoChangedFlag(m_game_time);
|
||||
|
||||
/*
|
||||
Do stuff!
|
||||
|
||||
@ -784,6 +916,7 @@ void ServerEnvironment::step(float dtime)
|
||||
Everything should bind to inside this single content
|
||||
searching loop to keep things fast.
|
||||
*/
|
||||
// TODO: Implement usage of ActiveBlockModifier
|
||||
|
||||
v3s16 p0;
|
||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||
@ -792,11 +925,14 @@ void ServerEnvironment::step(float dtime)
|
||||
{
|
||||
v3s16 p = p0 + block->getPosRelative();
|
||||
MapNode n = block->getNodeNoEx(p0);
|
||||
// Test something:
|
||||
// Convert mud under proper lighting to grass
|
||||
|
||||
/*
|
||||
Test something:
|
||||
Convert mud under proper lighting to grass
|
||||
*/
|
||||
if(n.d == CONTENT_MUD)
|
||||
{
|
||||
if(myrand()%10 == 0)
|
||||
if(myrand()%20 == 0)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(content_features(n_top.d).air_equivalent &&
|
||||
@ -807,6 +943,22 @@ void ServerEnvironment::step(float dtime)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Convert grass into mud if under something else than air
|
||||
*/
|
||||
else if(n.d == CONTENT_GRASS)
|
||||
{
|
||||
//if(myrand()%20 == 0)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(n_top.d != CONTENT_AIR
|
||||
&& n_top.d != CONTENT_IGNORE)
|
||||
{
|
||||
n.d = CONTENT_MUD;
|
||||
m_map->addNodeWithEvent(p, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -941,49 +1093,8 @@ u16 getFreeServerActiveObjectId(
|
||||
u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
|
||||
{
|
||||
assert(object);
|
||||
if(object->getId() == 0)
|
||||
{
|
||||
u16 new_id = getFreeServerActiveObjectId(m_active_objects);
|
||||
if(new_id == 0)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
|
||||
<<"no free ids available"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
object->setId(new_id);
|
||||
}
|
||||
if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
|
||||
<<"id is not free ("<<object->getId()<<")"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
/*dstream<<"INGO: ServerEnvironment::addActiveObject(): "
|
||||
<<"added (id="<<object->getId()<<")"<<std::endl;*/
|
||||
|
||||
m_active_objects.insert(object->getId(), object);
|
||||
|
||||
// Add static object to active static list of the block
|
||||
v3f objectpos = object->getBasePosition();
|
||||
std::string staticdata = object->getStaticData();
|
||||
StaticObject s_obj(object->getType(), objectpos, staticdata);
|
||||
// Add to the block where the object is located in
|
||||
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
|
||||
if(block)
|
||||
{
|
||||
block->m_static_objects.m_active.insert(object->getId(), s_obj);
|
||||
object->m_static_exists = true;
|
||||
object->m_static_block = blockpos;
|
||||
}
|
||||
else{
|
||||
dstream<<"WARNING: Server: Could not find a block for "
|
||||
<<"storing newly added static active object"<<std::endl;
|
||||
}
|
||||
|
||||
return object->getId();
|
||||
u16 id = addActiveObjectRaw(object, true);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1086,6 +1197,58 @@ ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
|
||||
************ Private methods *************
|
||||
*/
|
||||
|
||||
u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
||||
bool set_changed)
|
||||
{
|
||||
assert(object);
|
||||
if(object->getId() == 0)
|
||||
{
|
||||
u16 new_id = getFreeServerActiveObjectId(m_active_objects);
|
||||
if(new_id == 0)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"no free ids available"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
object->setId(new_id);
|
||||
}
|
||||
if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"id is not free ("<<object->getId()<<")"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
/*dstream<<"INGO: ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"added (id="<<object->getId()<<")"<<std::endl;*/
|
||||
|
||||
m_active_objects.insert(object->getId(), object);
|
||||
|
||||
// Add static object to active static list of the block
|
||||
v3f objectpos = object->getBasePosition();
|
||||
std::string staticdata = object->getStaticData();
|
||||
StaticObject s_obj(object->getType(), objectpos, staticdata);
|
||||
// Add to the block where the object is located in
|
||||
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
|
||||
if(block)
|
||||
{
|
||||
block->m_static_objects.m_active.insert(object->getId(), s_obj);
|
||||
object->m_static_exists = true;
|
||||
object->m_static_block = blockpos;
|
||||
|
||||
if(set_changed)
|
||||
block->setChangedFlag();
|
||||
}
|
||||
else{
|
||||
dstream<<"WARNING: Server: Could not find a block for "
|
||||
<<"storing newly added static active object"<<std::endl;
|
||||
}
|
||||
|
||||
return object->getId();
|
||||
}
|
||||
|
||||
/*
|
||||
Remove objects that satisfy (m_removed && m_known_by_count==0)
|
||||
*/
|
||||
@ -1176,8 +1339,8 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
||||
continue;
|
||||
}
|
||||
// This will also add the object to the active static list
|
||||
addActiveObject(obj);
|
||||
//u16 id = addActiveObject(obj);
|
||||
addActiveObjectRaw(obj, false);
|
||||
//u16 id = addActiveObjectRaw(obj, false);
|
||||
}
|
||||
// Clear stored list
|
||||
block->m_static_objects.m_stored.clear();
|
||||
@ -1190,7 +1353,8 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
||||
block->m_static_objects.m_stored.push_back(s_obj);
|
||||
}
|
||||
// Block has been modified
|
||||
block->setChangedFlag();
|
||||
// NOTE: No it has not really. Save I/O here.
|
||||
//block->setChangedFlag();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -112,25 +112,6 @@ public:
|
||||
private:
|
||||
};
|
||||
|
||||
/*
|
||||
Active block modifier interface
|
||||
*/
|
||||
|
||||
class ServerEnvironment;
|
||||
|
||||
class ActiveBlockModifier
|
||||
{
|
||||
public:
|
||||
ActiveBlockModifier(){};
|
||||
virtual ~ActiveBlockModifier(){};
|
||||
|
||||
virtual u32 getTriggerContentCount(){ return 1;}
|
||||
virtual u8 getTriggerContent(u32 i) = 0;
|
||||
virtual float getActiveInterval() = 0;
|
||||
virtual u32 getActiveChance() = 0;
|
||||
virtual void triggerEvent(ServerEnvironment *env, v3s16 p) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
The server-side environment.
|
||||
|
||||
@ -140,6 +121,7 @@ public:
|
||||
#include "serverobject.h"
|
||||
|
||||
class Server;
|
||||
class ActiveBlockModifier;
|
||||
|
||||
class ServerEnvironment : public Environment
|
||||
{
|
||||
@ -177,7 +159,8 @@ public:
|
||||
void loadMeta(const std::string &savedir);
|
||||
|
||||
/*
|
||||
ActiveObjects
|
||||
External ActiveObject interface
|
||||
-------------------------------------------
|
||||
*/
|
||||
|
||||
ServerActiveObject* getActiveObject(u16 id);
|
||||
@ -214,7 +197,38 @@ public:
|
||||
*/
|
||||
ActiveObjectMessage getActiveObjectMessage();
|
||||
|
||||
/*
|
||||
Activate objects and dynamically modify for the dtime determined
|
||||
from timestamp and additional_dtime
|
||||
*/
|
||||
void activateBlock(MapBlock *block, u32 additional_dtime=0);
|
||||
|
||||
/*
|
||||
ActiveBlockModifiers (TODO)
|
||||
-------------------------------------------
|
||||
*/
|
||||
|
||||
void addActiveBlockModifier(ActiveBlockModifier *abm);
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
Internal ActiveObject interface
|
||||
-------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
Add an active object to the environment.
|
||||
|
||||
Called by addActiveObject.
|
||||
|
||||
Object may be deleted by environment immediately.
|
||||
If id of object is 0, assigns a free id to it.
|
||||
Returns the id of the object.
|
||||
Returns 0 if not added and thus deleted.
|
||||
*/
|
||||
u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed);
|
||||
|
||||
/*
|
||||
Remove all objects that satisfy (m_removed && m_known_by_count==0)
|
||||
*/
|
||||
@ -256,6 +270,7 @@ private:
|
||||
ActiveBlockList m_active_blocks;
|
||||
IntervalLimiter m_active_blocks_management_interval;
|
||||
IntervalLimiter m_active_blocks_test_interval;
|
||||
IntervalLimiter m_active_blocks_nodemetadata_interval;
|
||||
// Time from the beginning of the game in seconds.
|
||||
// Incremented in step().
|
||||
u32 m_game_time;
|
||||
@ -263,6 +278,29 @@ private:
|
||||
float m_game_time_fraction_counter;
|
||||
};
|
||||
|
||||
/*
|
||||
Active block modifier interface.
|
||||
|
||||
These are fed into ServerEnvironment at initialization time;
|
||||
ServerEnvironment handles deleting them.
|
||||
*/
|
||||
|
||||
class ActiveBlockModifier
|
||||
{
|
||||
public:
|
||||
ActiveBlockModifier(){};
|
||||
virtual ~ActiveBlockModifier(){};
|
||||
|
||||
//virtual core::list<u8> update(ServerEnvironment *env) = 0;
|
||||
virtual u32 getTriggerContentCount(){ return 1;}
|
||||
virtual u8 getTriggerContent(u32 i) = 0;
|
||||
virtual float getActiveInterval() = 0;
|
||||
// chance of (1 / return value), 0 is disallowed
|
||||
virtual u32 getActiveChance() = 0;
|
||||
// This is called usually at interval for 1/chance of the nodes
|
||||
virtual void triggerEvent(ServerEnvironment *env, v3s16 p) = 0;
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
#include "clientobject.h"
|
||||
|
413
src/farmesh.cpp
Normal file
413
src/farmesh.cpp
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
Part of Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
A quick messy implementation of terrain rendering for a long
|
||||
distance according to map seed
|
||||
*/
|
||||
|
||||
#include "farmesh.h"
|
||||
#include "constants.h"
|
||||
#include "debug.h"
|
||||
#include "noise.h"
|
||||
#include "map.h"
|
||||
#include "client.h"
|
||||
|
||||
#include "mapgen.h"
|
||||
|
||||
FarMesh::FarMesh(
|
||||
scene::ISceneNode* parent,
|
||||
scene::ISceneManager* mgr,
|
||||
s32 id,
|
||||
u64 seed,
|
||||
Client *client
|
||||
):
|
||||
scene::ISceneNode(parent, mgr, id),
|
||||
m_seed(seed),
|
||||
m_camera_pos(0,0),
|
||||
m_time(0),
|
||||
m_client(client),
|
||||
m_render_range(20*MAP_BLOCKSIZE)
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<std::endl;
|
||||
|
||||
video::IVideoDriver* driver = mgr->getVideoDriver();
|
||||
|
||||
m_materials[0].setFlag(video::EMF_LIGHTING, false);
|
||||
m_materials[0].setFlag(video::EMF_BACK_FACE_CULLING, true);
|
||||
//m_materials[0].setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
m_materials[0].setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
m_materials[0].setFlag(video::EMF_FOG_ENABLE, false);
|
||||
//m_materials[0].setFlag(video::EMF_ANTI_ALIASING, true);
|
||||
//m_materials[0].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
m_materials[0].setFlag(video::EMF_FOG_ENABLE, true);
|
||||
|
||||
m_materials[1].setFlag(video::EMF_LIGHTING, false);
|
||||
m_materials[1].setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
m_materials[1].setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
m_materials[1].setFlag(video::EMF_FOG_ENABLE, false);
|
||||
m_materials[1].setTexture
|
||||
(0, driver->getTexture(getTexturePath("treeprop.png").c_str()));
|
||||
m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
m_materials[1].setFlag(video::EMF_FOG_ENABLE, true);
|
||||
|
||||
m_box = core::aabbox3d<f32>(-BS*1000000,-BS*31000,-BS*1000000,
|
||||
BS*1000000,BS*31000,BS*1000000);
|
||||
|
||||
}
|
||||
|
||||
FarMesh::~FarMesh()
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<std::endl;
|
||||
}
|
||||
|
||||
u32 FarMesh::getMaterialCount() const
|
||||
{
|
||||
return FARMESH_MATERIAL_COUNT;
|
||||
}
|
||||
|
||||
video::SMaterial& FarMesh::getMaterial(u32 i)
|
||||
{
|
||||
return m_materials[i];
|
||||
}
|
||||
|
||||
|
||||
void FarMesh::OnRegisterSceneNode()
|
||||
{
|
||||
if(IsVisible)
|
||||
{
|
||||
//SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
|
||||
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
|
||||
//SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
|
||||
}
|
||||
|
||||
ISceneNode::OnRegisterSceneNode();
|
||||
}
|
||||
|
||||
#define MYROUND(x) (x > 0.0 ? (int)x : (int)x - 1)
|
||||
|
||||
// Temporary hack
|
||||
struct HeightPoint
|
||||
{
|
||||
float gh; // ground height
|
||||
float ma; // mud amount
|
||||
float have_sand;
|
||||
float tree_amount;
|
||||
};
|
||||
core::map<v2s16, HeightPoint> g_heights;
|
||||
|
||||
HeightPoint ground_height(u64 seed, v2s16 p2d)
|
||||
{
|
||||
core::map<v2s16, HeightPoint>::Node *n = g_heights.find(p2d);
|
||||
if(n)
|
||||
return n->getValue();
|
||||
HeightPoint hp;
|
||||
s16 level = mapgen::find_ground_level_from_noise(seed, p2d, 3);
|
||||
hp.gh = (level-4)*BS;
|
||||
hp.ma = (4)*BS;
|
||||
/*hp.gh = BS*base_rock_level_2d(seed, p2d);
|
||||
hp.ma = BS*get_mud_add_amount(seed, p2d);*/
|
||||
hp.have_sand = mapgen::get_have_sand(seed, p2d);
|
||||
if(hp.gh > BS*WATER_LEVEL)
|
||||
hp.tree_amount = mapgen::tree_amount_2d(seed, p2d);
|
||||
else
|
||||
hp.tree_amount = 0;
|
||||
// No mud has been added if mud amount is less than 1
|
||||
if(hp.ma < 1.0*BS)
|
||||
hp.ma = 0.0;
|
||||
//hp.gh -= BS*3; // Lower a bit so that it is not that much in the way
|
||||
g_heights[p2d] = hp;
|
||||
return hp;
|
||||
}
|
||||
|
||||
void FarMesh::render()
|
||||
{
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
|
||||
/*if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
|
||||
return;*/
|
||||
if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
|
||||
return;
|
||||
/*if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SKY_BOX)
|
||||
return;*/
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
|
||||
//const s16 grid_radius_i = 12;
|
||||
//const float grid_size = BS*50;
|
||||
const s16 grid_radius_i = m_render_range/MAP_BLOCKSIZE;
|
||||
const float grid_size = BS*MAP_BLOCKSIZE;
|
||||
const v2f grid_speed(-BS*0, 0);
|
||||
|
||||
// Position of grid noise origin in world coordinates
|
||||
v2f world_grid_origin_pos_f(0,0);
|
||||
// Position of grid noise origin from the camera
|
||||
v2f grid_origin_from_camera_f = world_grid_origin_pos_f - m_camera_pos;
|
||||
// The center point of drawing in the noise
|
||||
v2f center_of_drawing_in_noise_f = -grid_origin_from_camera_f;
|
||||
// The integer center point of drawing in the noise
|
||||
v2s16 center_of_drawing_in_noise_i(
|
||||
MYROUND(center_of_drawing_in_noise_f.X / grid_size),
|
||||
MYROUND(center_of_drawing_in_noise_f.Y / grid_size)
|
||||
);
|
||||
// The world position of the integer center point of drawing in the noise
|
||||
v2f world_center_of_drawing_in_noise_f = v2f(
|
||||
center_of_drawing_in_noise_i.X * grid_size,
|
||||
center_of_drawing_in_noise_i.Y * grid_size
|
||||
) + world_grid_origin_pos_f;
|
||||
|
||||
for(s16 zi=-grid_radius_i; zi<grid_radius_i; zi++)
|
||||
for(s16 xi=-grid_radius_i; xi<grid_radius_i; xi++)
|
||||
{
|
||||
/*// Don't draw very close to player
|
||||
s16 dd = 3;
|
||||
if(zi > -dd && zi < dd && xi > -dd && xi < dd)
|
||||
continue;*/
|
||||
|
||||
v2s16 p_in_noise_i(
|
||||
xi+center_of_drawing_in_noise_i.X,
|
||||
zi+center_of_drawing_in_noise_i.Y
|
||||
);
|
||||
|
||||
// If sector was drawn, don't draw it this way
|
||||
if(m_client->m_env.getClientMap().sectorWasDrawn(p_in_noise_i))
|
||||
continue;
|
||||
|
||||
/*if((p_in_noise_i.X + p_in_noise_i.Y)%2==0)
|
||||
continue;*/
|
||||
/*if((p_in_noise_i.X/2 + p_in_noise_i.Y/2)%2==0)
|
||||
continue;*/
|
||||
|
||||
v2f p0 = v2f(xi,zi)*grid_size + world_center_of_drawing_in_noise_f;
|
||||
|
||||
/*double noise[4];
|
||||
double d = 100*BS;
|
||||
noise[0] = d*noise2d_perlin(
|
||||
(float)(p_in_noise_i.X+0)*grid_size/BS/100,
|
||||
(float)(p_in_noise_i.Y+0)*grid_size/BS/100,
|
||||
m_seed, 3, 0.5);
|
||||
|
||||
noise[1] = d*noise2d_perlin(
|
||||
(float)(p_in_noise_i.X+0)*grid_size/BS/100,
|
||||
(float)(p_in_noise_i.Y+1)*grid_size/BS/100,
|
||||
m_seed, 3, 0.5);
|
||||
|
||||
noise[2] = d*noise2d_perlin(
|
||||
(float)(p_in_noise_i.X+1)*grid_size/BS/100,
|
||||
(float)(p_in_noise_i.Y+1)*grid_size/BS/100,
|
||||
m_seed, 3, 0.5);
|
||||
|
||||
noise[3] = d*noise2d_perlin(
|
||||
(float)(p_in_noise_i.X+1)*grid_size/BS/100,
|
||||
(float)(p_in_noise_i.Y+0)*grid_size/BS/100,
|
||||
m_seed, 3, 0.5);*/
|
||||
|
||||
HeightPoint hps[5];
|
||||
hps[0] = ground_height(m_seed, v2s16(
|
||||
(p_in_noise_i.X+0)*grid_size/BS,
|
||||
(p_in_noise_i.Y+0)*grid_size/BS));
|
||||
hps[1] = ground_height(m_seed, v2s16(
|
||||
(p_in_noise_i.X+0)*grid_size/BS,
|
||||
(p_in_noise_i.Y+1)*grid_size/BS));
|
||||
hps[2] = ground_height(m_seed, v2s16(
|
||||
(p_in_noise_i.X+1)*grid_size/BS,
|
||||
(p_in_noise_i.Y+1)*grid_size/BS));
|
||||
hps[3] = ground_height(m_seed, v2s16(
|
||||
(p_in_noise_i.X+1)*grid_size/BS,
|
||||
(p_in_noise_i.Y+0)*grid_size/BS));
|
||||
v2s16 centerpoint(
|
||||
(p_in_noise_i.X+0)*grid_size/BS+MAP_BLOCKSIZE/2,
|
||||
(p_in_noise_i.Y+0)*grid_size/BS+MAP_BLOCKSIZE/2);
|
||||
hps[4] = ground_height(m_seed, centerpoint);
|
||||
|
||||
float noise[5];
|
||||
float h_min = BS*65535;
|
||||
float h_max = -BS*65536;
|
||||
float ma_avg = 0;
|
||||
float h_avg = 0;
|
||||
u32 have_sand_count = 0;
|
||||
float tree_amount_avg = 0;
|
||||
for(u32 i=0; i<5; i++)
|
||||
{
|
||||
noise[i] = hps[i].gh + hps[i].ma;
|
||||
if(noise[i] < h_min)
|
||||
h_min = noise[i];
|
||||
if(noise[i] > h_max)
|
||||
h_max = noise[i];
|
||||
ma_avg += hps[i].ma;
|
||||
h_avg += noise[i];
|
||||
if(hps[i].have_sand)
|
||||
have_sand_count++;
|
||||
tree_amount_avg += hps[i].tree_amount;
|
||||
}
|
||||
ma_avg /= 5.0;
|
||||
h_avg /= 5.0;
|
||||
tree_amount_avg /= 5.0;
|
||||
|
||||
float steepness = (h_max - h_min)/grid_size;
|
||||
|
||||
float light_f = noise[0]+noise[1]-noise[2]-noise[3];
|
||||
light_f /= 100;
|
||||
if(light_f < -1.0) light_f = -1.0;
|
||||
if(light_f > 1.0) light_f = 1.0;
|
||||
//light_f += 1.0;
|
||||
//light_f /= 2.0;
|
||||
|
||||
v2f p1 = p0 + v2f(1,1)*grid_size;
|
||||
|
||||
bool ground_is_sand = false;
|
||||
bool ground_is_rock = false;
|
||||
bool ground_is_mud = false;
|
||||
video::SColor c;
|
||||
// Detect water
|
||||
if(h_avg < WATER_LEVEL*BS && h_max < (WATER_LEVEL+5)*BS)
|
||||
{
|
||||
//c = video::SColor(255,59,86,146);
|
||||
c = video::SColor(255,82,120,204);
|
||||
|
||||
/*// Set to water level
|
||||
for(u32 i=0; i<4; i++)
|
||||
{
|
||||
if(noise[i] < BS*WATER_LEVEL)
|
||||
noise[i] = BS*WATER_LEVEL;
|
||||
}*/
|
||||
light_f = 0;
|
||||
}
|
||||
// Steep cliffs
|
||||
else if(steepness > 2.0)
|
||||
{
|
||||
c = video::SColor(255,128,128,128);
|
||||
ground_is_rock = true;
|
||||
}
|
||||
// Basic ground
|
||||
else
|
||||
{
|
||||
if(ma_avg < 2.0*BS)
|
||||
{
|
||||
c = video::SColor(255,128,128,128);
|
||||
ground_is_rock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(h_avg <= 2.5*BS && have_sand_count >= 2)
|
||||
{
|
||||
c = video::SColor(255,210,194,156);
|
||||
ground_is_sand = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*// Trees if there are over 0.01 trees per MapNode
|
||||
if(tree_amount_avg > 0.01)
|
||||
c = video::SColor(255,50,128,50);
|
||||
else
|
||||
c = video::SColor(255,107,134,51);*/
|
||||
c = video::SColor(255,107,134,51);
|
||||
ground_is_mud = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set to water level
|
||||
for(u32 i=0; i<4; i++)
|
||||
{
|
||||
if(noise[i] < BS*WATER_LEVEL)
|
||||
noise[i] = BS*WATER_LEVEL;
|
||||
}
|
||||
|
||||
float b = m_brightness + light_f*0.1*m_brightness;
|
||||
if(b < 0) b = 0;
|
||||
if(b > 2) b = 2;
|
||||
|
||||
c = video::SColor(255, b*c.getRed(), b*c.getGreen(), b*c.getBlue());
|
||||
|
||||
driver->setMaterial(m_materials[0]);
|
||||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(p0.X,noise[0],p0.Y, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(p0.X,noise[1],p1.Y, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(p1.X,noise[2],p1.Y, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(p1.X,noise[3],p0.Y, 0,0,0, c, 0,0),
|
||||
};
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
|
||||
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
|
||||
|
||||
// Add some trees if appropriate
|
||||
if(tree_amount_avg >= 0.0065 && steepness < 1.4
|
||||
&& ground_is_mud == true)
|
||||
{
|
||||
driver->setMaterial(m_materials[1]);
|
||||
|
||||
float b = m_brightness;
|
||||
c = video::SColor(255, b*255, b*255, b*255);
|
||||
|
||||
{
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(p0.X,noise[0],p0.Y,
|
||||
0,0,0, c, 0,1),
|
||||
video::S3DVertex(p0.X,noise[0]+BS*MAP_BLOCKSIZE,p0.Y,
|
||||
0,0,0, c, 0,0),
|
||||
video::S3DVertex(p1.X,noise[2]+BS*MAP_BLOCKSIZE,p1.Y,
|
||||
0,0,0, c, 1,0),
|
||||
video::S3DVertex(p1.X,noise[2],p1.Y,
|
||||
0,0,0, c, 1,1),
|
||||
};
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
|
||||
video::EVT_STANDARD, scene::EPT_TRIANGLES,
|
||||
video::EIT_16BIT);
|
||||
}
|
||||
{
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(p1.X,noise[3],p0.Y,
|
||||
0,0,0, c, 0,1),
|
||||
video::S3DVertex(p1.X,noise[3]+BS*MAP_BLOCKSIZE,p0.Y,
|
||||
0,0,0, c, 0,0),
|
||||
video::S3DVertex(p0.X,noise[1]+BS*MAP_BLOCKSIZE,p1.Y,
|
||||
0,0,0, c, 1,0),
|
||||
video::S3DVertex(p0.X,noise[1],p1.Y,
|
||||
0,0,0, c, 1,1),
|
||||
};
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
|
||||
video::EVT_STANDARD, scene::EPT_TRIANGLES,
|
||||
video::EIT_16BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//driver->clearZBuffer();
|
||||
}
|
||||
|
||||
void FarMesh::step(float dtime)
|
||||
{
|
||||
m_time += dtime;
|
||||
}
|
||||
|
||||
void FarMesh::update(v2f camera_p, float brightness, s16 render_range)
|
||||
{
|
||||
m_camera_pos = camera_p;
|
||||
m_brightness = brightness;
|
||||
m_render_range = render_range;
|
||||
}
|
||||
|
||||
|
85
src/farmesh.h
Normal file
85
src/farmesh.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Part of Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef FARMESH_HEADER
|
||||
#define FARMESH_HEADER
|
||||
|
||||
/*
|
||||
A quick messy implementation of terrain rendering for a long
|
||||
distance according to map seed
|
||||
*/
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
|
||||
#define FARMESH_MATERIAL_COUNT 2
|
||||
|
||||
class Client;
|
||||
|
||||
class FarMesh : public scene::ISceneNode
|
||||
{
|
||||
public:
|
||||
FarMesh(
|
||||
scene::ISceneNode* parent,
|
||||
scene::ISceneManager* mgr,
|
||||
s32 id,
|
||||
u64 seed,
|
||||
Client *client
|
||||
);
|
||||
|
||||
~FarMesh();
|
||||
|
||||
/*
|
||||
ISceneNode methods
|
||||
*/
|
||||
|
||||
virtual void OnRegisterSceneNode();
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual const core::aabbox3d<f32>& getBoundingBox() const
|
||||
{
|
||||
return m_box;
|
||||
}
|
||||
|
||||
virtual u32 getMaterialCount() const;
|
||||
|
||||
virtual video::SMaterial& getMaterial(u32 i);
|
||||
|
||||
/*
|
||||
Other stuff
|
||||
*/
|
||||
|
||||
void step(float dtime);
|
||||
|
||||
void update(v2f camera_p, float brightness, s16 render_range);
|
||||
|
||||
private:
|
||||
video::SMaterial m_materials[FARMESH_MATERIAL_COUNT];
|
||||
core::aabbox3d<f32> m_box;
|
||||
float m_cloud_y;
|
||||
float m_brightness;
|
||||
u64 m_seed;
|
||||
v2f m_camera_pos;
|
||||
float m_time;
|
||||
Client *m_client;
|
||||
s16 m_render_range;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
200
src/game.cpp
200
src/game.cpp
@ -25,11 +25,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "guiPasswordChange.h"
|
||||
#include "guiInventoryMenu.h"
|
||||
#include "guiTextInputMenu.h"
|
||||
#include "guiFurnaceMenu.h"
|
||||
#include "materials.h"
|
||||
#include "config.h"
|
||||
#include "clouds.h"
|
||||
#include "keycode.h"
|
||||
#include "farmesh.h"
|
||||
|
||||
// TODO: Move content-aware stuff to separate file
|
||||
#include "content_mapnode.h"
|
||||
#include "content_nodemeta.h"
|
||||
|
||||
/*
|
||||
Setting this to 1 enables a special camera mode that forces
|
||||
@ -358,7 +362,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(heart_texture->getOriginalSize())),
|
||||
NULL, colors, true);
|
||||
p += v2s32(20,0);
|
||||
p += v2s32(16,0);
|
||||
}
|
||||
if(halfheartcount % 2 == 1)
|
||||
{
|
||||
@ -371,7 +375,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
|
||||
driver->draw2DImage(heart_texture, rect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0), srcd),
|
||||
NULL, colors, true);
|
||||
p += v2s32(20,0);
|
||||
p += v2s32(16,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -632,6 +636,10 @@ void update_skybox(video::IVideoDriver* driver,
|
||||
skybox->remove();
|
||||
}
|
||||
|
||||
/*// Disable skybox if FarMesh is enabled
|
||||
if(g_settings.getBool("enable_farmesh"))
|
||||
return;*/
|
||||
|
||||
if(brightness >= 0.5)
|
||||
{
|
||||
skybox = smgr->addSkyBoxSceneNode(
|
||||
@ -801,8 +809,9 @@ void the_game(
|
||||
{
|
||||
if(client.accessDenied())
|
||||
{
|
||||
error_message = L"Access denied. Check your password and try again.";
|
||||
std::cout<<DTIME<<"Access denied."<<std::endl;
|
||||
error_message = L"Access denied. Reason: "
|
||||
+client.accessDeniedReason();
|
||||
std::cout<<DTIME<<wide_to_narrow(error_message)<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -851,8 +860,21 @@ void the_game(
|
||||
|
||||
float cloud_height = BS*100;
|
||||
Clouds *clouds = NULL;
|
||||
clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1,
|
||||
cloud_height, time(0));
|
||||
if(g_settings.getBool("enable_clouds"))
|
||||
{
|
||||
clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1,
|
||||
cloud_height, time(0));
|
||||
}
|
||||
|
||||
/*
|
||||
FarMesh
|
||||
*/
|
||||
|
||||
FarMesh *farmesh = NULL;
|
||||
if(g_settings.getBool("enable_farmesh"))
|
||||
{
|
||||
farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
|
||||
}
|
||||
|
||||
/*
|
||||
Move into game
|
||||
@ -886,8 +908,8 @@ void the_game(
|
||||
gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
|
||||
L"",
|
||||
core::rect<s32>(0,0,0,0),
|
||||
false, false); // Disable word wrap as of now
|
||||
//false, true);
|
||||
//false, false); // Disable word wrap as of now
|
||||
false, true);
|
||||
//guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
|
||||
core::list<ChatLine> chat_lines;
|
||||
|
||||
@ -930,6 +952,9 @@ void the_game(
|
||||
core::list<float> frametime_log;
|
||||
|
||||
float damage_flash_timer = 0;
|
||||
s16 farmesh_range = 20*MAP_BLOCKSIZE;
|
||||
|
||||
bool invert_mouse = g_settings.getBool("invert_mouse");
|
||||
|
||||
/*
|
||||
Main loop
|
||||
@ -937,6 +962,10 @@ void the_game(
|
||||
|
||||
bool first_loop_after_window_activation = true;
|
||||
|
||||
// TODO: Convert the static interval timers to these
|
||||
// Interval limiter for profiler
|
||||
IntervalLimiter m_profiler_interval;
|
||||
|
||||
// Time is in milliseconds
|
||||
// NOTE: getRealTime() causes strange problems in wine (imprecision?)
|
||||
// NOTE: So we have to use getTime() and call run()s between them
|
||||
@ -1123,6 +1152,21 @@ void the_game(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Profiler
|
||||
*/
|
||||
float profiler_print_interval =
|
||||
g_settings.getFloat("profiler_print_interval");
|
||||
if(profiler_print_interval != 0)
|
||||
{
|
||||
if(m_profiler_interval.step(0.030, profiler_print_interval))
|
||||
{
|
||||
dstream<<"Profiler:"<<std::endl;
|
||||
g_profiler.print(dstream);
|
||||
g_profiler.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Direct handling of user input
|
||||
*/
|
||||
@ -1189,10 +1233,12 @@ void the_game(
|
||||
if(g_settings.getBool("free_move"))
|
||||
{
|
||||
g_settings.set("free_move","false");
|
||||
chat_lines.push_back(ChatLine(L"free_move disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_settings.set("free_move","true");
|
||||
chat_lines.push_back(ChatLine(L"free_move enabled"));
|
||||
}
|
||||
}
|
||||
else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
|
||||
@ -1200,10 +1246,12 @@ void the_game(
|
||||
if(g_settings.getBool("fast_move"))
|
||||
{
|
||||
g_settings.set("fast_move","false");
|
||||
chat_lines.push_back(ChatLine(L"fast_move disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_settings.set("fast_move","true");
|
||||
chat_lines.push_back(ChatLine(L"fast_move enabled"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1355,7 +1403,11 @@ void the_game(
|
||||
if((device->isWindowActive() && noMenuActive()) || random_input)
|
||||
{
|
||||
if(!random_input)
|
||||
device->getCursorControl()->setVisible(false);
|
||||
{
|
||||
// Mac OSX gets upset if this is set every frame
|
||||
if(device->getCursorControl()->isVisible())
|
||||
device->getCursorControl()->setVisible(false);
|
||||
}
|
||||
|
||||
if(first_loop_after_window_activation){
|
||||
//std::cout<<"window active, first loop"<<std::endl;
|
||||
@ -1364,6 +1416,8 @@ void the_game(
|
||||
else{
|
||||
s32 dx = input->getMousePos().X - displaycenter.X;
|
||||
s32 dy = input->getMousePos().Y - displaycenter.Y;
|
||||
if(invert_mouse)
|
||||
dy = -dy;
|
||||
//std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
|
||||
|
||||
/*const float keyspeed = 500;
|
||||
@ -1384,7 +1438,9 @@ void the_game(
|
||||
input->setMousePos(displaycenter.X, displaycenter.Y);
|
||||
}
|
||||
else{
|
||||
device->getCursorControl()->setVisible(true);
|
||||
// Mac OSX gets upset if this is set every frame
|
||||
if(device->getCursorControl()->isVisible() == false)
|
||||
device->getCursorControl()->setVisible(true);
|
||||
|
||||
//std::cout<<"window inactive"<<std::endl;
|
||||
first_loop_after_window_activation = true;
|
||||
@ -1696,7 +1752,41 @@ void the_game(
|
||||
{
|
||||
std::cout<<DTIME<<"Ground right-clicked"<<std::endl;
|
||||
|
||||
if(meta && meta->typeId() == CONTENT_SIGN_WALL && !random_input)
|
||||
// If metadata provides an inventory view, activate it
|
||||
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
|
||||
{
|
||||
dstream<<DTIME<<"Launching custom inventory view"<<std::endl;
|
||||
/*
|
||||
Construct the unique identification string of the node
|
||||
*/
|
||||
std::string current_name;
|
||||
current_name += "nodemeta:";
|
||||
current_name += itos(nodepos.X);
|
||||
current_name += ",";
|
||||
current_name += itos(nodepos.Y);
|
||||
current_name += ",";
|
||||
current_name += itos(nodepos.Z);
|
||||
|
||||
/*
|
||||
Create menu
|
||||
*/
|
||||
|
||||
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
|
||||
v2s16 invsize =
|
||||
GUIInventoryMenu::makeDrawSpecArrayFromString(
|
||||
draw_spec,
|
||||
meta->getInventoryDrawSpecString(),
|
||||
current_name);
|
||||
|
||||
GUIInventoryMenu *menu =
|
||||
new GUIInventoryMenu(guienv, guiroot, -1,
|
||||
&g_menumgr, invsize,
|
||||
client.getInventoryContext(),
|
||||
&client);
|
||||
menu->setDrawSpec(draw_spec);
|
||||
menu->drop();
|
||||
}
|
||||
else if(meta && meta->typeId() == CONTENT_SIGN_WALL && !random_input)
|
||||
{
|
||||
dstream<<"Sign node right-clicked"<<std::endl;
|
||||
|
||||
@ -1713,51 +1803,6 @@ void the_game(
|
||||
&g_menumgr, dest,
|
||||
wtext))->drop();
|
||||
}
|
||||
else if(meta && meta->typeId() == CONTENT_CHEST && !random_input)
|
||||
{
|
||||
dstream<<"Chest node right-clicked"<<std::endl;
|
||||
|
||||
//ChestNodeMetadata *chestmeta = (ChestNodeMetadata*)meta;
|
||||
|
||||
std::string chest_inv_id;
|
||||
chest_inv_id += "nodemeta:";
|
||||
chest_inv_id += itos(nodepos.X);
|
||||
chest_inv_id += ",";
|
||||
chest_inv_id += itos(nodepos.Y);
|
||||
chest_inv_id += ",";
|
||||
chest_inv_id += itos(nodepos.Z);
|
||||
|
||||
GUIInventoryMenu *menu =
|
||||
new GUIInventoryMenu(guienv, guiroot, -1,
|
||||
&g_menumgr, v2s16(8,9),
|
||||
client.getInventoryContext(),
|
||||
&client);
|
||||
|
||||
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
|
||||
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", chest_inv_id, "0",
|
||||
v2s32(0, 0), v2s32(8, 4)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", "current_player", "main",
|
||||
v2s32(0, 5), v2s32(8, 4)));
|
||||
|
||||
menu->setDrawSpec(draw_spec);
|
||||
|
||||
menu->drop();
|
||||
|
||||
}
|
||||
else if(meta && meta->typeId() == CONTENT_FURNACE && !random_input)
|
||||
{
|
||||
dstream<<"Furnace node right-clicked"<<std::endl;
|
||||
|
||||
GUIFurnaceMenu *menu =
|
||||
new GUIFurnaceMenu(guienv, guiroot, -1,
|
||||
&g_menumgr, nodepos, &client);
|
||||
|
||||
menu->drop();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
client.groundAction(1, nodepos, neighbourpos, g_selected_item);
|
||||
@ -1824,6 +1869,22 @@ void the_game(
|
||||
0.05+brightness*0.95);
|
||||
}
|
||||
|
||||
/*
|
||||
Update farmesh
|
||||
*/
|
||||
if(farmesh)
|
||||
{
|
||||
farmesh_range = draw_control.wanted_range * 10;
|
||||
if(draw_control.range_all && farmesh_range < 500)
|
||||
farmesh_range = 500;
|
||||
if(farmesh_range > 1000)
|
||||
farmesh_range = 1000;
|
||||
|
||||
farmesh->step(dtime);
|
||||
farmesh->update(v2f(player_position.X, player_position.Z),
|
||||
0.05+brightness*0.95, farmesh_range);
|
||||
}
|
||||
|
||||
// Store brightness value
|
||||
old_brightness = brightness;
|
||||
|
||||
@ -1833,11 +1894,19 @@ void the_game(
|
||||
|
||||
if(g_settings.getBool("enable_fog") == true)
|
||||
{
|
||||
f32 range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
|
||||
if(draw_control.range_all)
|
||||
range = 100000*BS;
|
||||
if(range < 50*BS)
|
||||
range = range * 0.5 + 25*BS;
|
||||
f32 range;
|
||||
if(farmesh)
|
||||
{
|
||||
range = BS*farmesh_range;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
|
||||
if(draw_control.range_all)
|
||||
range = 100000*BS;
|
||||
if(range < 50*BS)
|
||||
range = range * 0.5 + 25*BS;
|
||||
}
|
||||
|
||||
driver->setFog(
|
||||
bgcolor,
|
||||
@ -1985,7 +2054,7 @@ void the_game(
|
||||
10,
|
||||
50,
|
||||
screensize.X - 10,
|
||||
50 + text_height*chat_lines.size()
|
||||
50 + guitext_chat->getTextHeight()
|
||||
);
|
||||
|
||||
guitext_chat->setRelativePosition(rect);
|
||||
@ -2034,7 +2103,7 @@ void the_game(
|
||||
//driver->beginScene(false, true, bgcolor);
|
||||
beginscenetime = timer.stop(true);
|
||||
}
|
||||
|
||||
|
||||
//timer3.stop();
|
||||
|
||||
//std::cout<<DTIME<<"smgr->drawAll()"<<std::endl;
|
||||
@ -2166,7 +2235,8 @@ void the_game(
|
||||
/*
|
||||
Drop stuff
|
||||
*/
|
||||
clouds->drop();
|
||||
if(clouds)
|
||||
clouds->drop();
|
||||
|
||||
/*
|
||||
Draw a "shutting down" screen, which will be shown while the map
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "guiFurnaceMenu.h"
|
||||
#include "client.h"
|
||||
|
||||
GUIFurnaceMenu::GUIFurnaceMenu(
|
||||
gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
v3s16 nodepos,
|
||||
Client *client
|
||||
):
|
||||
GUIInventoryMenu(env, parent, id, menumgr, v2s16(8,9),
|
||||
client->getInventoryContext(), client),
|
||||
m_nodepos(nodepos),
|
||||
m_client(client)
|
||||
{
|
||||
std::string furnace_inv_id;
|
||||
furnace_inv_id += "nodemeta:";
|
||||
furnace_inv_id += itos(nodepos.X);
|
||||
furnace_inv_id += ",";
|
||||
furnace_inv_id += itos(nodepos.Y);
|
||||
furnace_inv_id += ",";
|
||||
furnace_inv_id += itos(nodepos.Z);
|
||||
|
||||
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", furnace_inv_id, "fuel",
|
||||
v2s32(2, 3), v2s32(1, 1)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", furnace_inv_id, "src",
|
||||
v2s32(2, 1), v2s32(1, 1)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", furnace_inv_id, "dst",
|
||||
v2s32(5, 1), v2s32(2, 2)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", "current_player", "main",
|
||||
v2s32(0, 5), v2s32(8, 4)));
|
||||
setDrawSpec(draw_spec);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "guiInventoryMenu.h"
|
||||
#include "constants.h"
|
||||
#include "keycode.h"
|
||||
#include "strfnd.h"
|
||||
|
||||
void drawInventoryItem(video::IVideoDriver *driver,
|
||||
gui::IGUIFont *font,
|
||||
@ -412,5 +413,85 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
|
||||
return Parent ? Parent->OnEvent(event) : false;
|
||||
}
|
||||
|
||||
/*
|
||||
Here is an example traditional set-up sequence for a DrawSpec list:
|
||||
|
||||
std::string furnace_inv_id = "nodemetadata:0,1,2";
|
||||
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", furnace_inv_id, "fuel",
|
||||
v2s32(2, 3), v2s32(1, 1)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", furnace_inv_id, "src",
|
||||
v2s32(2, 1), v2s32(1, 1)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", furnace_inv_id, "dst",
|
||||
v2s32(5, 1), v2s32(2, 2)));
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
"list", "current_player", "main",
|
||||
v2s32(0, 5), v2s32(8, 4)));
|
||||
setDrawSpec(draw_spec);
|
||||
|
||||
Here is the string for creating the same DrawSpec list (a single line,
|
||||
spread to multiple lines here):
|
||||
|
||||
GUIInventoryMenu::makeDrawSpecArrayFromString(
|
||||
draw_spec,
|
||||
"nodemetadata:0,1,2",
|
||||
"invsize[8,9;]"
|
||||
"list[current_name;fuel;2,3;1,1;]"
|
||||
"list[current_name;src;2,1;1,1;]"
|
||||
"list[current_name;dst;5,1;2,2;]"
|
||||
"list[current_player;main;0,5;8,4;]");
|
||||
|
||||
Returns inventory menu size defined by invsize[].
|
||||
*/
|
||||
v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
|
||||
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
|
||||
const std::string &data,
|
||||
const std::string ¤t_name)
|
||||
{
|
||||
v2s16 invsize(8,9);
|
||||
Strfnd f(data);
|
||||
while(f.atend() == false)
|
||||
{
|
||||
std::string type = trim(f.next("["));
|
||||
//dstream<<"type="<<type<<std::endl;
|
||||
if(type == "list")
|
||||
{
|
||||
std::string name = f.next(";");
|
||||
if(name == "current_name")
|
||||
name = current_name;
|
||||
std::string subname = f.next(";");
|
||||
s32 pos_x = stoi(f.next(","));
|
||||
s32 pos_y = stoi(f.next(";"));
|
||||
s32 geom_x = stoi(f.next(","));
|
||||
s32 geom_y = stoi(f.next(";"));
|
||||
dstream<<"list name="<<name<<", subname="<<subname
|
||||
<<", pos=("<<pos_x<<","<<pos_y<<")"
|
||||
<<", geom=("<<geom_x<<","<<geom_y<<")"
|
||||
<<std::endl;
|
||||
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
|
||||
type, name, subname,
|
||||
v2s32(pos_x,pos_y),v2s32(geom_x,geom_y)));
|
||||
f.next("]");
|
||||
}
|
||||
else if(type == "invsize")
|
||||
{
|
||||
invsize.X = stoi(f.next(","));
|
||||
invsize.Y = stoi(f.next(";"));
|
||||
dstream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
||||
f.next("]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore others
|
||||
std::string ts = f.next("]");
|
||||
dstream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
|
||||
<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return invsize;
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,12 @@ public:
|
||||
v2s32 pos;
|
||||
v2s32 geom;
|
||||
};
|
||||
|
||||
// See .cpp for format
|
||||
static v2s16 makeDrawSpecArrayFromString(
|
||||
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
|
||||
const std::string &data,
|
||||
const std::string ¤t_name);
|
||||
|
||||
GUIInventoryMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef GUIMAINMENU_HEADER
|
||||
#define GUIMAINMENU_HEADER
|
||||
@ -44,18 +44,19 @@ enum
|
||||
|
||||
struct MainMenuData
|
||||
{
|
||||
MainMenuData() :
|
||||
MainMenuData():
|
||||
// Client opts
|
||||
fancy_trees(false), smooth_lighting(false),
|
||||
// Server opts
|
||||
creative_mode(false), enable_damage(false),
|
||||
// Actions
|
||||
delete_map(false)
|
||||
{
|
||||
}
|
||||
fancy_trees(false),
|
||||
smooth_lighting(false),
|
||||
// Server opts
|
||||
creative_mode(false),
|
||||
enable_damage(false),
|
||||
// Actions
|
||||
delete_map(false)
|
||||
{}
|
||||
|
||||
// These are in the native format of the gui elements
|
||||
|
||||
|
||||
// Client options
|
||||
std::wstring address;
|
||||
std::wstring port;
|
||||
@ -70,23 +71,20 @@ struct MainMenuData
|
||||
bool delete_map;
|
||||
};
|
||||
|
||||
class GUIMainMenu: public GUIModalMenu
|
||||
class GUIMainMenu : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIMainMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr, MainMenuData *data,
|
||||
GUIMainMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
MainMenuData *data,
|
||||
IGameCallback *gamecallback);
|
||||
~GUIMainMenu();
|
||||
|
||||
gui::IGUIEnvironment* env;
|
||||
gui::IGUIElement* parent;
|
||||
s32 id;
|
||||
IMenuManager *menumgr;
|
||||
|
||||
|
||||
void removeChildren();
|
||||
/*
|
||||
Remove and re-add (or reposition) stuff
|
||||
*/
|
||||
Remove and re-add (or reposition) stuff
|
||||
*/
|
||||
void regenerateGui(v2u32 screensize);
|
||||
|
||||
void drawMenu();
|
||||
@ -99,11 +97,16 @@ public:
|
||||
}
|
||||
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
|
||||
private:
|
||||
MainMenuData *m_data;
|
||||
bool m_accepted;
|
||||
IGameCallback *m_gamecallback;
|
||||
|
||||
gui::IGUIEnvironment* env;
|
||||
gui::IGUIElement* parent;
|
||||
s32 id;
|
||||
IMenuManager *menumgr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef GUIMESSAGEMENU_HEADER
|
||||
#define GUIMESSAGEMENU_HEADER
|
||||
@ -25,17 +25,19 @@
|
||||
#include "utility.h"
|
||||
#include <string>
|
||||
|
||||
class GUIMessageMenu: public GUIModalMenu
|
||||
class GUIMessageMenu : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIMessageMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr, std::wstring message_text);
|
||||
GUIMessageMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
std::wstring message_text);
|
||||
~GUIMessageMenu();
|
||||
|
||||
|
||||
void removeChildren();
|
||||
/*
|
||||
Remove and re-add (or reposition) stuff
|
||||
*/
|
||||
Remove and re-add (or reposition) stuff
|
||||
*/
|
||||
void regenerateGui(v2u32 screensize);
|
||||
|
||||
void drawMenu();
|
||||
@ -43,13 +45,13 @@ public:
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
/*
|
||||
true = ok'd
|
||||
*/
|
||||
true = ok'd
|
||||
*/
|
||||
bool getStatus()
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::wstring m_message_text;
|
||||
bool m_status;
|
||||
|
@ -1,21 +1,19 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Part of Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "guiPasswordChange.h"
|
||||
|
@ -1,21 +1,19 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Part of Minetest-c55
|
||||
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GUIPASSWORDCHANGE_HEADER
|
||||
|
@ -28,6 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <sstream>
|
||||
#include "main.h"
|
||||
#include "serverobject.h"
|
||||
#include "content_mapnode.h"
|
||||
#include "content_inventory.h"
|
||||
|
||||
/*
|
||||
InventoryItem
|
||||
@ -110,36 +112,12 @@ ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f
|
||||
|
||||
bool MaterialItem::isCookable()
|
||||
{
|
||||
if(m_content == CONTENT_TREE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(m_content == CONTENT_COBBLE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(m_content == CONTENT_SAND)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return item_material_is_cookable(m_content);
|
||||
}
|
||||
|
||||
InventoryItem *MaterialItem::createCookResult()
|
||||
{
|
||||
if(m_content == CONTENT_TREE)
|
||||
{
|
||||
return new CraftItem("lump_of_coal", 1);
|
||||
}
|
||||
else if(m_content == CONTENT_COBBLE)
|
||||
{
|
||||
return new MaterialItem(CONTENT_STONE, 1);
|
||||
}
|
||||
else if(m_content == CONTENT_SAND)
|
||||
{
|
||||
return new MaterialItem(CONTENT_GLASS, 1);
|
||||
}
|
||||
return NULL;
|
||||
return item_material_create_cook_result(m_content);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -152,29 +130,8 @@ video::ITexture * CraftItem::getImage()
|
||||
if(g_texturesource == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string name;
|
||||
std::string name = item_craft_get_image_name(m_subname);
|
||||
|
||||
if(m_subname == "Stick")
|
||||
name = "stick.png";
|
||||
else if(m_subname == "paper")
|
||||
name = "paper.png";
|
||||
else if(m_subname == "book")
|
||||
name = "book.png";
|
||||
else if(m_subname == "lump_of_coal")
|
||||
name = "lump_of_coal.png";
|
||||
else if(m_subname == "lump_of_iron")
|
||||
name = "lump_of_iron.png";
|
||||
else if(m_subname == "lump_of_clay")
|
||||
name = "lump_of_clay.png";
|
||||
else if(m_subname == "steel_ingot")
|
||||
name = "steel_ingot.png";
|
||||
else if(m_subname == "clay_brick")
|
||||
name = "clay_brick.png";
|
||||
else if(m_subname == "rat")
|
||||
name = "rat.png";
|
||||
else
|
||||
name = "cloud.png";
|
||||
|
||||
// Get such a texture
|
||||
return g_texturesource->getTextureRaw(name);
|
||||
}
|
||||
@ -183,50 +140,35 @@ video::ITexture * CraftItem::getImage()
|
||||
ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos)
|
||||
{
|
||||
// Special cases
|
||||
if(m_subname == "rat")
|
||||
{
|
||||
ServerActiveObject *obj = new RatSAO(env, id, pos);
|
||||
ServerActiveObject *obj = item_craft_create_object(m_subname, env, id, pos);
|
||||
if(obj)
|
||||
return obj;
|
||||
}
|
||||
// Default
|
||||
else
|
||||
{
|
||||
return InventoryItem::createSAO(env, id, pos);
|
||||
}
|
||||
return InventoryItem::createSAO(env, id, pos);
|
||||
}
|
||||
|
||||
u16 CraftItem::getDropCount()
|
||||
{
|
||||
// Special cases
|
||||
if(m_subname == "rat")
|
||||
return 1;
|
||||
s16 dc = item_craft_get_drop_count(m_subname);
|
||||
if(dc != -1)
|
||||
return dc;
|
||||
// Default
|
||||
else
|
||||
return InventoryItem::getDropCount();
|
||||
return InventoryItem::getDropCount();
|
||||
}
|
||||
|
||||
bool CraftItem::isCookable()
|
||||
{
|
||||
if(m_subname == "lump_of_iron" || m_subname == "lump_of_clay")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return item_craft_is_cookable(m_subname);
|
||||
}
|
||||
|
||||
InventoryItem *CraftItem::createCookResult()
|
||||
{
|
||||
if(m_subname == "lump_of_iron")
|
||||
{
|
||||
return new CraftItem("steel_ingot", 1);
|
||||
}
|
||||
else if(m_subname == "lump_of_clay")
|
||||
return new CraftItem("clay_brick", 1);
|
||||
return NULL;
|
||||
return item_craft_create_cook_result(m_subname);
|
||||
}
|
||||
|
||||
/*
|
||||
MapBlockObjectItem
|
||||
MapBlockObjectItem DEPRECATED
|
||||
TODO: Remove
|
||||
*/
|
||||
#ifndef SERVER
|
||||
@ -528,7 +470,7 @@ InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
|
||||
//setDirty(true);
|
||||
|
||||
// If it is an empty position, it's an easy job.
|
||||
InventoryItem *to_item = m_items[i];
|
||||
InventoryItem *to_item = getItem(i);
|
||||
if(to_item == NULL)
|
||||
{
|
||||
m_items[i] = newitem;
|
||||
@ -560,7 +502,7 @@ InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
|
||||
bool InventoryList::itemFits(u32 i, InventoryItem *newitem)
|
||||
{
|
||||
// If it is an empty position, it's an easy job.
|
||||
InventoryItem *to_item = m_items[i];
|
||||
InventoryItem *to_item = getItem(i);
|
||||
if(to_item == NULL)
|
||||
{
|
||||
return true;
|
||||
@ -586,7 +528,7 @@ InventoryItem * InventoryList::takeItem(u32 i, u32 count)
|
||||
|
||||
//setDirty(true);
|
||||
|
||||
InventoryItem *item = m_items[i];
|
||||
InventoryItem *item = getItem(i);
|
||||
// If it is an empty position, return NULL
|
||||
if(item == NULL)
|
||||
return NULL;
|
||||
|
@ -1,24 +1,25 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "keycode.h"
|
||||
#include "main.h" // For g_settings
|
||||
|
||||
#define CHECKKEY(x){if(strcmp(name, #x)==0) return irr::x;}
|
||||
|
||||
irr::EKEY_CODE keyname_to_keycode(const char *name)
|
||||
@ -209,9 +210,10 @@ std::string keycode_to_keyname(s32 keycode)
|
||||
{
|
||||
return KeyNames[keycode];
|
||||
}
|
||||
|
||||
/*
|
||||
Key config
|
||||
*/
|
||||
Key config
|
||||
*/
|
||||
|
||||
// A simple cache for quicker lookup
|
||||
core::map<std::string, irr::EKEY_CODE> g_key_setting_cache;
|
||||
@ -220,7 +222,7 @@ irr::EKEY_CODE getKeySetting(const char *settingname)
|
||||
{
|
||||
core::map<std::string, irr::EKEY_CODE>::Node *n;
|
||||
n = g_key_setting_cache.find(settingname);
|
||||
if (n)
|
||||
if(n)
|
||||
return n->getValue();
|
||||
irr::EKEY_CODE c = keyname_to_keycode(g_settings.get(settingname).c_str());
|
||||
g_key_setting_cache.insert(settingname, c);
|
||||
@ -231,4 +233,3 @@ void clearKeyCache()
|
||||
{
|
||||
g_key_setting_cache.clear();
|
||||
}
|
||||
|
||||
|
@ -29,5 +29,6 @@ irr::EKEY_CODE keyname_to_keycode(const char *name);
|
||||
irr::EKEY_CODE getKeySetting(const char *settingname);
|
||||
std::string keycode_to_keyname(s32 keycode);
|
||||
void clearCache();
|
||||
|
||||
#endif
|
||||
|
||||
|
201
src/main.cpp
201
src/main.cpp
@ -89,6 +89,17 @@ SUGG: Make a system for pregenerating quick information for mapblocks, so
|
||||
that the client can show them as cubes before they are actually sent
|
||||
or even generated.
|
||||
|
||||
SUGG: Erosion simulation at map generation time
|
||||
- Simulate water flows, which would carve out dirt fast and
|
||||
then turn stone into gravel and sand and relocate it.
|
||||
- How about relocating minerals, too? Coal and gold in
|
||||
downstream sand and gravel would be kind of cool
|
||||
- This would need a better way of handling minerals, mainly
|
||||
to have mineral content as a separate field. the first
|
||||
parameter field is free for this.
|
||||
- Simulate rock falling from cliffs when water has removed
|
||||
enough solid rock from the bottom
|
||||
|
||||
Gaming ideas:
|
||||
-------------
|
||||
|
||||
@ -172,7 +183,15 @@ TODO: A setting for enabling bilinear filtering for textures
|
||||
|
||||
TODO: Better control of draw_control.wanted_max_blocks
|
||||
|
||||
TODO: Block mesh generator to tile properly on smooth lighting
|
||||
TODO: Further investigate the use of GPU lighting in addition to the
|
||||
current one
|
||||
|
||||
TODO: Artificial (night) light could be more yellow colored than sunlight.
|
||||
- This is technically doable.
|
||||
- Also the actual colors of the textures could be made less colorful
|
||||
in the dark but it's a bit more difficult.
|
||||
|
||||
SUGG: Somehow make the night less colorful
|
||||
|
||||
Configuration:
|
||||
--------------
|
||||
@ -198,6 +217,9 @@ TODO: Don't update all meshes always on single node changes, but
|
||||
|
||||
FIXME: When disconnected to the menu, memory is not freed properly
|
||||
|
||||
TODO: Investigate how much the mesh generator thread gets used when
|
||||
transferring map data
|
||||
|
||||
Server:
|
||||
-------
|
||||
|
||||
@ -214,11 +236,20 @@ FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
|
||||
|
||||
FIXME: The new optimized map sending doesn't sometimes send enough blocks
|
||||
from big caves and such
|
||||
FIXME: Block send distance configuration does not take effect for some reason
|
||||
|
||||
TODO: Map saving should be done by EmergeThread
|
||||
|
||||
SUGG: Map unloading based on sector reference is not very good, it keeps
|
||||
unnecessary stuff in memory. I guess. Investigate this.
|
||||
|
||||
TODO: When block is placed and it has param_type==CPT_FACEDIR_SIMPLE, set
|
||||
the direction accordingly.
|
||||
|
||||
Environment:
|
||||
------------
|
||||
|
||||
TODO: A list of "active blocks" in which stuff happens.
|
||||
TODO: A list of "active blocks" in which stuff happens. (+=done)
|
||||
+ Add a never-resetted game timer to the server
|
||||
+ Add a timestamp value to blocks
|
||||
+ The simple rule: All blocks near some player are "active"
|
||||
@ -260,31 +291,24 @@ SUGG: MovingObject::move and Player::move are basically the same.
|
||||
- NOTE: There is a simple move implementation now in collision.{h,cpp}
|
||||
- NOTE: MovingObject will be deleted (MapBlockObject)
|
||||
|
||||
TODO: Add a long step function to objects that is called with the time
|
||||
difference when block activates
|
||||
|
||||
Map:
|
||||
----
|
||||
|
||||
TODO: Mineral and ground material properties
|
||||
- This way mineral ground toughness can be calculated with just
|
||||
some formula, as well as tool strengths
|
||||
- There are TODOs in appropriate files: material.h, content_mapnode.h
|
||||
|
||||
TODO: Flowing water to actually contain flow direction information
|
||||
- There is a space for this - it just has to be implemented.
|
||||
|
||||
SUGG: Erosion simulation at map generation time
|
||||
- Simulate water flows, which would carve out dirt fast and
|
||||
then turn stone into gravel and sand and relocate it.
|
||||
- How about relocating minerals, too? Coal and gold in
|
||||
downstream sand and gravel would be kind of cool
|
||||
- This would need a better way of handling minerals, mainly
|
||||
to have mineral content as a separate field. the first
|
||||
parameter field is free for this.
|
||||
- Simulate rock falling from cliffs when water has removed
|
||||
enough solid rock from the bottom
|
||||
|
||||
SUGG: Try out the notch way of generating maps, that is, make bunches
|
||||
of low-res 3d noise and interpolate linearly.
|
||||
|
||||
Mapgen v2:
|
||||
Mapgen v2 (the current one):
|
||||
* Possibly add some kind of erosion and other stuff
|
||||
* Better water generation (spread it to underwater caverns but don't
|
||||
fill dungeons that don't touch big water masses)
|
||||
@ -293,25 +317,66 @@ Mapgen v2:
|
||||
the other chunk making nasty straight walls when the other chunk
|
||||
is generated. Fix it. Maybe just a special case if the ground is
|
||||
flat?
|
||||
* Consider not updating this one and make a good mainly block-based
|
||||
generator
|
||||
|
||||
SUGG: Make two "modified states", one that forces the block to be saved at
|
||||
the next save event, and one that makes the block to be saved at exit
|
||||
time.
|
||||
|
||||
TODO: Add a not_fully_generated flag to MapBlock, which would be set for
|
||||
blocks that contain eg. trees from neighboring generations but haven't
|
||||
been generated itself. This is required for the future generator.
|
||||
|
||||
Misc. stuff:
|
||||
------------
|
||||
* Move digging property stuff from material.{h,cpp} to mapnode.cpp
|
||||
- ...Or maybe move content_features to material.{h,cpp}?
|
||||
- Make sure server handles removing grass when a block is placed (etc)
|
||||
- The client should not do it by itself
|
||||
- Block cube placement around player's head
|
||||
- Protocol version field
|
||||
- Consider getting some textures from cisoun's texture pack
|
||||
- Ask from Cisoun
|
||||
- Make sure the fence implementation and data format is good
|
||||
- Think about using same bits for material for fences and doors, for
|
||||
example
|
||||
- Finish the ActiveBlockModifier stuff and use it for something
|
||||
- Move mineral to param2, increment map serialization version, add conversion
|
||||
|
||||
TODO: Add a per-sector database to store surface stuff as simple flags/values
|
||||
- Light?
|
||||
- A building?
|
||||
And at some point make the server send this data to the client too,
|
||||
instead of referring to the noise functions
|
||||
- Ground height
|
||||
- Surface ground type
|
||||
- Trees?
|
||||
|
||||
TODO: Restart irrlicht completely when coming back to main menu from game.
|
||||
- This gets rid of everything that is stored in irrlicht's caches.
|
||||
|
||||
TODO: Merge bahamada's audio stuff (clean patch available)
|
||||
|
||||
TODO: Merge spongie's chest/furnace direction (by hand)
|
||||
|
||||
TODO: Merge key configuration menu (no clean patch available)
|
||||
|
||||
Making it more portable:
|
||||
------------------------
|
||||
|
||||
Stuff to do before release:
|
||||
---------------------------
|
||||
- Player default privileges and default password
|
||||
- Chat privilege
|
||||
- Some simple block-based dynamic stuff in the world (finish the
|
||||
ActiveBlockModifier stuff)
|
||||
- Protocol version field
|
||||
- Consider getting some textures from cisoun's texture pack
|
||||
- Add a long step function to objects that is called with the time
|
||||
difference when block activates
|
||||
|
||||
Fixes to the current release:
|
||||
-----------------------------
|
||||
|
||||
Stuff to do after release:
|
||||
---------------------------
|
||||
|
||||
Doing currently:
|
||||
----------------
|
||||
|
||||
TODO: Use MapBlock::resetUsageTimer() in appropriate places
|
||||
(on client and server)
|
||||
|
||||
======================================================================
|
||||
|
||||
@ -377,6 +442,9 @@ Settings g_settings;
|
||||
// This is located in defaultsettings.cpp
|
||||
extern void set_default_settings();
|
||||
|
||||
// Global profiler
|
||||
Profiler g_profiler;
|
||||
|
||||
/*
|
||||
Random stuff
|
||||
*/
|
||||
@ -427,7 +495,14 @@ std::ostream *derr_client_ptr = &dstream;
|
||||
class TimeGetter
|
||||
{
|
||||
public:
|
||||
TimeGetter(IrrlichtDevice *device):
|
||||
virtual u32 getTime() = 0;
|
||||
};
|
||||
|
||||
// A precise irrlicht one
|
||||
class IrrlichtTimeGetter: public TimeGetter
|
||||
{
|
||||
public:
|
||||
IrrlichtTimeGetter(IrrlichtDevice *device):
|
||||
m_device(device)
|
||||
{}
|
||||
u32 getTime()
|
||||
@ -439,8 +514,18 @@ public:
|
||||
private:
|
||||
IrrlichtDevice *m_device;
|
||||
};
|
||||
// Not so precise one which works without irrlicht
|
||||
class SimpleTimeGetter: public TimeGetter
|
||||
{
|
||||
public:
|
||||
u32 getTime()
|
||||
{
|
||||
return porting::getTimeMs();
|
||||
}
|
||||
};
|
||||
|
||||
// A pointer to a global instance of the time getter
|
||||
// TODO: why?
|
||||
TimeGetter *g_timegetter = NULL;
|
||||
|
||||
u32 getTimeMs()
|
||||
@ -994,6 +1079,15 @@ void drawMenuBackground(video::IVideoDriver* driver)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
Initialization
|
||||
*/
|
||||
|
||||
// Set locale. This is for forcing '.' as the decimal point.
|
||||
std::locale::global(std::locale("C"));
|
||||
// This enables printing all characters in bitmap font
|
||||
setlocale(LC_CTYPE, "en_US");
|
||||
|
||||
/*
|
||||
Parse command line
|
||||
*/
|
||||
@ -1057,22 +1151,29 @@ int main(int argc, char *argv[])
|
||||
disable_stderr = true;
|
||||
#endif
|
||||
|
||||
porting::signal_handler_init();
|
||||
bool &kill = *porting::signal_handler_killstatus();
|
||||
|
||||
// Initialize porting::path_data and porting::path_userdata
|
||||
porting::initializePaths();
|
||||
|
||||
// Create user data directory
|
||||
fs::CreateDir(porting::path_userdata);
|
||||
|
||||
// Initialize debug streams
|
||||
debugstreams_init(disable_stderr, DEBUGFILE);
|
||||
#ifdef RUN_IN_PLACE
|
||||
std::string debugfile = DEBUGFILE;
|
||||
#else
|
||||
std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;
|
||||
#endif
|
||||
debugstreams_init(disable_stderr, debugfile.c_str());
|
||||
// Initialize debug stacks
|
||||
debug_stacks_init();
|
||||
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
porting::signal_handler_init();
|
||||
bool &kill = *porting::signal_handler_killstatus();
|
||||
|
||||
porting::initializePaths();
|
||||
// Create user data directory
|
||||
fs::CreateDir(porting::path_userdata);
|
||||
|
||||
// C-style stuff initialization
|
||||
initializeMaterialProperties();
|
||||
// Init material properties table
|
||||
//initializeMaterialProperties();
|
||||
|
||||
// Debug handler
|
||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||
@ -1090,19 +1191,10 @@ int main(int argc, char *argv[])
|
||||
// Initialize default settings
|
||||
set_default_settings();
|
||||
|
||||
// Set locale. This is for forcing '.' as the decimal point.
|
||||
std::locale::global(std::locale("C"));
|
||||
// This enables printing all characters in bitmap font
|
||||
setlocale(LC_CTYPE, "en_US");
|
||||
|
||||
// Initialize sockets
|
||||
sockets_init();
|
||||
atexit(sockets_cleanup);
|
||||
|
||||
/*
|
||||
Initialization
|
||||
*/
|
||||
|
||||
/*
|
||||
Read config file
|
||||
*/
|
||||
@ -1188,7 +1280,7 @@ int main(int argc, char *argv[])
|
||||
port = 30000;
|
||||
|
||||
// Map directory
|
||||
std::string map_dir = porting::path_userdata+"/map";
|
||||
std::string map_dir = porting::path_userdata+"/world";
|
||||
if(cmd_args.exists("map-dir"))
|
||||
map_dir = cmd_args.get("map-dir");
|
||||
else if(g_settings.exists("map-dir"))
|
||||
@ -1199,6 +1291,9 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
DSTACK("Dedicated server branch");
|
||||
|
||||
// Create time getter
|
||||
g_timegetter = new SimpleTimeGetter();
|
||||
|
||||
// Create server
|
||||
Server server(map_dir.c_str());
|
||||
server.start(port);
|
||||
@ -1281,7 +1376,7 @@ int main(int argc, char *argv[])
|
||||
device = device;
|
||||
|
||||
// Create time getter
|
||||
g_timegetter = new TimeGetter(device);
|
||||
g_timegetter = new IrrlichtTimeGetter(device);
|
||||
|
||||
// Create game callback for menus
|
||||
g_gamecallback = new MainGameCallback(device);
|
||||
@ -1349,7 +1444,6 @@ int main(int argc, char *argv[])
|
||||
Preload some textures and stuff
|
||||
*/
|
||||
|
||||
init_content_inventory_texture_paths();
|
||||
init_mapnode(); // Second call with g_texturesource set
|
||||
init_mineral();
|
||||
|
||||
@ -1488,13 +1582,22 @@ int main(int argc, char *argv[])
|
||||
g_settings.set("creative_mode", itos(menudata.creative_mode));
|
||||
g_settings.set("enable_damage", itos(menudata.enable_damage));
|
||||
|
||||
// Check for valid parameters, restart menu if invalid.
|
||||
// NOTE: These are now checked server side; no need to do it
|
||||
// here, so let's not do it here.
|
||||
/*// Check for valid parameters, restart menu if invalid.
|
||||
if(playername == "")
|
||||
{
|
||||
error_message = L"Name required.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check that name has only valid chars
|
||||
if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
|
||||
{
|
||||
error_message = L"Characters allowed: "
|
||||
+narrow_to_wide(PLAYERNAME_ALLOWED_CHARS);
|
||||
continue;
|
||||
}*/
|
||||
|
||||
// Save settings
|
||||
g_settings.set("name", playername);
|
||||
g_settings.set("address", address);
|
||||
|
@ -28,6 +28,10 @@ extern Settings g_settings;
|
||||
#include "tile.h"
|
||||
extern ITextureSource *g_texturesource;
|
||||
|
||||
// Global profiler
|
||||
#include "profiler.h"
|
||||
extern Profiler g_profiler;
|
||||
|
||||
// Debug streams
|
||||
|
||||
#include <fstream>
|
||||
|
3483
src/map.cpp
3483
src/map.cpp
File diff suppressed because it is too large
Load Diff
246
src/map.h
246
src/map.h
@ -41,13 +41,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mapchunk.h"
|
||||
#include "nodemetadata.h"
|
||||
|
||||
namespace mapgen{
|
||||
struct BlockMakeData;
|
||||
};
|
||||
|
||||
/*
|
||||
MapEditEvent
|
||||
*/
|
||||
|
||||
#define MAPTYPE_BASE 0
|
||||
#define MAPTYPE_SERVER 1
|
||||
#define MAPTYPE_CLIENT 2
|
||||
|
||||
enum MapEditEventType{
|
||||
// Node added (changed from air or something else to something)
|
||||
MEET_ADDNODE,
|
||||
// Node removed (changed to air)
|
||||
MEET_REMOVENODE,
|
||||
// Node metadata of block changed (not knowing which node exactly)
|
||||
// p stores block coordinate
|
||||
MEET_BLOCK_NODE_METADATA_CHANGED,
|
||||
// Anything else
|
||||
MEET_OTHER
|
||||
};
|
||||
|
||||
@ -122,7 +136,7 @@ public:
|
||||
|
||||
// On failure returns NULL
|
||||
MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
|
||||
// On failure returns NULL
|
||||
// Same as the above (there exists no lock anymore)
|
||||
MapSector * getSectorNoGenerateNoEx(v2s16 p2d);
|
||||
// On failure throws InvalidPositionException
|
||||
MapSector * getSectorNoGenerate(v2s16 p2d);
|
||||
@ -258,6 +272,9 @@ public:
|
||||
//bool updateChangedVisibleArea();
|
||||
|
||||
virtual void save(bool only_changed){assert(0);};
|
||||
|
||||
// Server implements this
|
||||
virtual void saveBlock(MapBlock *block){};
|
||||
|
||||
/*
|
||||
Updates usage timers
|
||||
@ -269,7 +286,7 @@ public:
|
||||
void deleteSectors(core::list<v2s16> &list, bool only_blocks);
|
||||
|
||||
// Returns count of deleted sectors
|
||||
u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
|
||||
u32 unloadUnusedData(float timeout, bool only_blocks=false,
|
||||
core::list<v3s16> *deleted_blocks=NULL);
|
||||
|
||||
// For debug printing
|
||||
@ -320,8 +337,6 @@ protected:
|
||||
This is the only map class that is able to generate map.
|
||||
*/
|
||||
|
||||
struct ChunkMakeData;
|
||||
|
||||
class ServerMap : public Map
|
||||
{
|
||||
public:
|
||||
@ -336,160 +351,25 @@ public:
|
||||
return MAPTYPE_SERVER;
|
||||
}
|
||||
|
||||
/*
|
||||
Map generation
|
||||
*/
|
||||
|
||||
// Returns the position of the chunk where the sector is in
|
||||
v2s16 sector_to_chunk(v2s16 sectorpos)
|
||||
{
|
||||
if(m_chunksize == 0)
|
||||
return v2s16(0,0);
|
||||
sectorpos.X += m_chunksize / 2;
|
||||
sectorpos.Y += m_chunksize / 2;
|
||||
v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
|
||||
return chunkpos;
|
||||
}
|
||||
|
||||
// Returns the position of the (0,0) sector of the chunk
|
||||
v2s16 chunk_to_sector(v2s16 chunkpos)
|
||||
{
|
||||
if(m_chunksize == 0)
|
||||
return v2s16(0,0);
|
||||
v2s16 sectorpos(
|
||||
chunkpos.X * m_chunksize,
|
||||
chunkpos.Y * m_chunksize
|
||||
);
|
||||
sectorpos.X -= m_chunksize / 2;
|
||||
sectorpos.Y -= m_chunksize / 2;
|
||||
return sectorpos;
|
||||
}
|
||||
|
||||
/*
|
||||
Get a chunk.
|
||||
*/
|
||||
MapChunk *getChunk(v2s16 chunkpos)
|
||||
{
|
||||
core::map<v2s16, MapChunk*>::Node *n;
|
||||
n = m_chunks.find(chunkpos);
|
||||
if(n == NULL)
|
||||
return NULL;
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
/*
|
||||
True if the chunk and its neighbors are fully generated.
|
||||
It means the chunk will not be touched in the future by the
|
||||
generator. If false, generateChunk will make it true.
|
||||
*/
|
||||
bool chunkNonVolatile(v2s16 chunkpos)
|
||||
{
|
||||
if(m_chunksize == 0)
|
||||
return true;
|
||||
|
||||
/*for(s16 x=-1; x<=1; x++)
|
||||
for(s16 y=-1; y<=1; y++)*/
|
||||
s16 x=0;
|
||||
s16 y=0;
|
||||
{
|
||||
v2s16 chunkpos0 = chunkpos + v2s16(x,y);
|
||||
MapChunk *chunk = getChunk(chunkpos);
|
||||
if(chunk == NULL)
|
||||
return false;
|
||||
if(chunk->getGenLevel() != GENERATED_FULLY)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if any chunk is marked as modified
|
||||
*/
|
||||
bool anyChunkModified()
|
||||
{
|
||||
for(core::map<v2s16, MapChunk*>::Iterator
|
||||
i = m_chunks.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v2s16 p = i.getNode()->getKey();
|
||||
MapChunk *chunk = i.getNode()->getValue();
|
||||
if(chunk->isModified())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setChunksNonModified()
|
||||
{
|
||||
for(core::map<v2s16, MapChunk*>::Iterator
|
||||
i = m_chunks.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v2s16 p = i.getNode()->getKey();
|
||||
MapChunk *chunk = i.getNode()->getValue();
|
||||
chunk->setModified(false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Chunks are generated by using these and makeChunk().
|
||||
*/
|
||||
void initChunkMake(ChunkMakeData &data, v2s16 chunkpos);
|
||||
MapChunk* finishChunkMake(ChunkMakeData &data,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks);
|
||||
|
||||
/*
|
||||
Generate a chunk.
|
||||
|
||||
All chunks touching this one can be altered also.
|
||||
*/
|
||||
/*MapChunk* generateChunkRaw(v2s16 chunkpos,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks,
|
||||
bool force=false);*/
|
||||
|
||||
/*
|
||||
Generate a chunk and its neighbors so that it won't be touched
|
||||
anymore.
|
||||
*/
|
||||
/*MapChunk* generateChunk(v2s16 chunkpos,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks);*/
|
||||
|
||||
/*
|
||||
Generate a sector.
|
||||
|
||||
This is mainly called by generateChunkRaw.
|
||||
*/
|
||||
//ServerMapSector * generateSector(v2s16 p);
|
||||
|
||||
/*
|
||||
Get a sector from somewhere.
|
||||
- Check memory
|
||||
- Check disk (loads blocks also)
|
||||
- Check disk (doesn't load blocks)
|
||||
- Create blank one
|
||||
*/
|
||||
ServerMapSector * createSector(v2s16 p);
|
||||
|
||||
/*
|
||||
Get a sector from somewhere.
|
||||
- Check memory
|
||||
- Check disk (loads blocks also)
|
||||
- Generate chunk
|
||||
Blocks are generated by using these and makeBlock().
|
||||
*/
|
||||
/*MapSector * emergeSector(v2s16 p,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks);*/
|
||||
void initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos);
|
||||
MapBlock* finishBlockMake(mapgen::BlockMakeData *data,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks);
|
||||
|
||||
/*MapSector * emergeSector(v2s16 p)
|
||||
{
|
||||
core::map<v3s16, MapBlock*> changed_blocks;
|
||||
return emergeSector(p, changed_blocks);
|
||||
}*/
|
||||
|
||||
// A non-threaded wrapper to the above
|
||||
MapBlock * generateBlock(
|
||||
v3s16 p,
|
||||
MapBlock *original_dummy,
|
||||
ServerMapSector *sector,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks,
|
||||
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
|
||||
core::map<v3s16, MapBlock*> &modified_blocks
|
||||
);
|
||||
|
||||
/*
|
||||
@ -498,37 +378,17 @@ public:
|
||||
- Create blank
|
||||
*/
|
||||
MapBlock * createBlock(v3s16 p);
|
||||
|
||||
/*
|
||||
only_from_disk, changed_blocks and lighting_invalidated_blocks
|
||||
are not properly used by the new map generator.
|
||||
*/
|
||||
MapBlock * emergeBlock(
|
||||
v3s16 p,
|
||||
bool only_from_disk,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks,
|
||||
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
|
||||
);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
NOTE: This comment might be outdated
|
||||
|
||||
Forcefully get a block from somewhere.
|
||||
|
||||
Exceptions:
|
||||
- InvalidPositionException: possible if only_from_disk==true
|
||||
InvalidPositionException possible if only_from_disk==true
|
||||
|
||||
changed_blocks:
|
||||
- All already existing blocks that were modified are added.
|
||||
- If found on disk, nothing will be added.
|
||||
- If generated, the new block will not be included.
|
||||
|
||||
lighting_invalidated_blocks:
|
||||
- All blocks that have heavy-to-calculate lighting changes
|
||||
are added.
|
||||
- updateLighting() should be called for these.
|
||||
|
||||
- A block that is in changed_blocks may not be in
|
||||
lighting_invalidated_blocks.
|
||||
Parameters:
|
||||
changed_blocks: Blocks that have been modified
|
||||
*/
|
||||
MapBlock * emergeBlock(
|
||||
v3s16 p,
|
||||
@ -551,6 +411,7 @@ public:
|
||||
// dirname: final directory name
|
||||
v2s16 getSectorPos(std::string dirname);
|
||||
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
|
||||
static std::string getBlockFilename(v3s16 p);
|
||||
|
||||
void save(bool only_changed);
|
||||
//void loadAll();
|
||||
@ -559,8 +420,8 @@ public:
|
||||
void saveMapMeta();
|
||||
void loadMapMeta();
|
||||
|
||||
void saveChunkMeta();
|
||||
void loadChunkMeta();
|
||||
/*void saveChunkMeta();
|
||||
void loadChunkMeta();*/
|
||||
|
||||
// The sector mutex should be locked when calling most of these
|
||||
|
||||
@ -569,6 +430,7 @@ public:
|
||||
// DEPRECATED? Sectors have no metadata anymore.
|
||||
void saveSectorMeta(ServerMapSector *sector);
|
||||
MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
|
||||
bool loadSectorMeta(v2s16 p2d);
|
||||
|
||||
// Full load of a sector including all blocks.
|
||||
// returns true on success, false on failure.
|
||||
@ -580,12 +442,15 @@ public:
|
||||
void saveBlock(MapBlock *block);
|
||||
// This will generate a sector with getSector if not found.
|
||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
|
||||
MapBlock* loadBlock(v3s16 p);
|
||||
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
||||
bool isSavingEnabled(){ return m_map_saving_enabled; }
|
||||
|
||||
u64 getSeed(){ return m_seed; }
|
||||
|
||||
private:
|
||||
// Seed used for all kinds of randomness
|
||||
u64 m_seed;
|
||||
@ -593,11 +458,13 @@ private:
|
||||
std::string m_savedir;
|
||||
bool m_map_saving_enabled;
|
||||
|
||||
#if 0
|
||||
// Chunk size in MapSectors
|
||||
// If 0, chunks are disabled.
|
||||
s16 m_chunksize;
|
||||
// Chunks
|
||||
core::map<v2s16, MapChunk*> m_chunks;
|
||||
#endif
|
||||
|
||||
/*
|
||||
Metadata is re-written on disk only if this is true.
|
||||
@ -732,6 +599,12 @@ public:
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
||||
// Check if sector was drawn on last render()
|
||||
bool sectorWasDrawn(v2s16 p)
|
||||
{
|
||||
return (m_last_drawn_sectors.find(p) != NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
Client *m_client;
|
||||
|
||||
@ -746,7 +619,8 @@ private:
|
||||
v3f m_camera_position;
|
||||
v3f m_camera_direction;
|
||||
JMutex m_camera_mutex;
|
||||
|
||||
|
||||
core::map<v2s16, bool> m_last_drawn_sectors;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -796,29 +670,5 @@ protected:
|
||||
bool m_create_area;
|
||||
};
|
||||
|
||||
struct ChunkMakeData
|
||||
{
|
||||
bool no_op;
|
||||
ManualMapVoxelManipulator vmanip;
|
||||
u64 seed;
|
||||
v2s16 chunkpos;
|
||||
s16 y_blocks_min;
|
||||
s16 y_blocks_max;
|
||||
v2s16 sectorpos_base;
|
||||
s16 sectorpos_base_size;
|
||||
v2s16 sectorpos_bigbase;
|
||||
s16 sectorpos_bigbase_size;
|
||||
s16 max_spread_amount;
|
||||
UniqueQueue<v3s16> transforming_liquid;
|
||||
|
||||
ChunkMakeData():
|
||||
no_op(false),
|
||||
vmanip(NULL),
|
||||
seed(0)
|
||||
{}
|
||||
};
|
||||
|
||||
void makeChunk(ChunkMakeData *data);
|
||||
|
||||
#endif
|
||||
|
||||
|
1847
src/mapblock.cpp
1847
src/mapblock.cpp
File diff suppressed because it is too large
Load Diff
260
src/mapblock.h
260
src/mapblock.h
@ -33,10 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "voxel.h"
|
||||
#include "nodemetadata.h"
|
||||
#include "staticobject.h"
|
||||
#include "mapblock_nodemod.h"
|
||||
#ifndef SERVER
|
||||
#include "mapblock_mesh.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
|
||||
|
||||
// Named by looking towards z+
|
||||
/*// Named by looking towards z+
|
||||
enum{
|
||||
FACE_BACK=0,
|
||||
FACE_TOP,
|
||||
@ -44,103 +49,37 @@ enum{
|
||||
FACE_FRONT,
|
||||
FACE_BOTTOM,
|
||||
FACE_LEFT
|
||||
};
|
||||
};*/
|
||||
|
||||
struct FastFace
|
||||
enum ModifiedState
|
||||
{
|
||||
TileSpec tile;
|
||||
video::S3DVertex vertices[4]; // Precalculated vertices
|
||||
// Has not been modified.
|
||||
MOD_STATE_CLEAN = 0,
|
||||
MOD_RESERVED1 = 1,
|
||||
// Has been modified, and will be saved when being unloaded.
|
||||
MOD_STATE_WRITE_AT_UNLOAD = 2,
|
||||
MOD_RESERVED3 = 3,
|
||||
// Has been modified, and will be saved as soon as possible.
|
||||
MOD_STATE_WRITE_NEEDED = 4,
|
||||
MOD_RESERVED5 = 5,
|
||||
};
|
||||
|
||||
enum NodeModType
|
||||
// NOTE: If this is enabled, set MapBlock to be initialized with
|
||||
// CONTENT_IGNORE.
|
||||
/*enum BlockGenerationStatus
|
||||
{
|
||||
NODEMOD_NONE,
|
||||
NODEMOD_CHANGECONTENT, //param is content id
|
||||
NODEMOD_CRACK // param is crack progression
|
||||
};
|
||||
|
||||
struct NodeMod
|
||||
{
|
||||
NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
|
||||
{
|
||||
type = a_type;
|
||||
param = a_param;
|
||||
}
|
||||
bool operator==(const NodeMod &other)
|
||||
{
|
||||
return (type == other.type && param == other.param);
|
||||
}
|
||||
enum NodeModType type;
|
||||
u16 param;
|
||||
};
|
||||
|
||||
class NodeModMap
|
||||
{
|
||||
public:
|
||||
/*
|
||||
returns true if the mod was different last time
|
||||
*/
|
||||
bool set(v3s16 p, const NodeMod &mod)
|
||||
{
|
||||
// See if old is different, cancel if it is not different.
|
||||
core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
|
||||
if(n)
|
||||
{
|
||||
NodeMod old = n->getValue();
|
||||
if(old == mod)
|
||||
return false;
|
||||
|
||||
n->setValue(mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mods.insert(p, mod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Returns true if there was one
|
||||
bool get(v3s16 p, NodeMod *mod)
|
||||
{
|
||||
core::map<v3s16, NodeMod>::Node *n;
|
||||
n = m_mods.find(p);
|
||||
if(n == NULL)
|
||||
return false;
|
||||
if(mod)
|
||||
*mod = n->getValue();
|
||||
return true;
|
||||
}
|
||||
bool clear(v3s16 p)
|
||||
{
|
||||
if(m_mods.find(p))
|
||||
{
|
||||
m_mods.remove(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool clear()
|
||||
{
|
||||
if(m_mods.size() == 0)
|
||||
return false;
|
||||
m_mods.clear();
|
||||
return true;
|
||||
}
|
||||
void copy(NodeModMap &dest)
|
||||
{
|
||||
dest.m_mods.clear();
|
||||
|
||||
for(core::map<v3s16, NodeMod>::Iterator
|
||||
i = m_mods.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
core::map<v3s16, NodeMod> m_mods;
|
||||
};
|
||||
// Completely non-generated (filled with CONTENT_IGNORE).
|
||||
BLOCKGEN_UNTOUCHED=0,
|
||||
// Trees or similar might have been blitted from other blocks to here.
|
||||
// Otherwise, the block contains CONTENT_IGNORE
|
||||
BLOCKGEN_FROM_NEIGHBORS=2,
|
||||
// Has been generated, but some neighbors might put some stuff in here
|
||||
// when they are generated.
|
||||
// Does not contain any CONTENT_IGNORE
|
||||
BLOCKGEN_SELF_GENERATED=4,
|
||||
// The block and all its neighbors have been generated
|
||||
BLOCKGEN_FULLY_GENERATED=6
|
||||
};*/
|
||||
|
||||
enum
|
||||
{
|
||||
@ -170,35 +109,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Mesh making stuff
|
||||
*/
|
||||
|
||||
class MapBlock;
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
struct MeshMakeData
|
||||
{
|
||||
u32 m_daynight_ratio;
|
||||
NodeModMap m_temp_mods;
|
||||
VoxelManipulator m_vmanip;
|
||||
v3s16 m_blockpos;
|
||||
|
||||
/*
|
||||
Copy central data directly from block, and other data from
|
||||
parent of block.
|
||||
*/
|
||||
void fill(u32 daynight_ratio, MapBlock *block);
|
||||
};
|
||||
|
||||
scene::SMesh* makeMapBlockMesh(MeshMakeData *data);
|
||||
|
||||
#endif
|
||||
|
||||
u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
|
||||
v3s16 face_dir);
|
||||
|
||||
/*
|
||||
MapBlock itself
|
||||
*/
|
||||
@ -226,9 +136,10 @@ public:
|
||||
u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
|
||||
data = new MapNode[l];
|
||||
for(u32 i=0; i<l; i++){
|
||||
data[i] = MapNode();
|
||||
//data[i] = MapNode();
|
||||
data[i] = MapNode(CONTENT_IGNORE);
|
||||
}
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -250,19 +161,43 @@ public:
|
||||
modified, so that the block is saved and possibly not deleted from
|
||||
memory.
|
||||
*/
|
||||
// DEPRECATED, use *Modified()
|
||||
void setChangedFlag()
|
||||
{
|
||||
changed = true;
|
||||
//dstream<<"Deprecated setChangedFlag() called"<<std::endl;
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
// DEPRECATED, use *Modified()
|
||||
void resetChangedFlag()
|
||||
{
|
||||
changed = false;
|
||||
//dstream<<"Deprecated resetChangedFlag() called"<<std::endl;
|
||||
resetModified();
|
||||
}
|
||||
// DEPRECATED, use *Modified()
|
||||
bool getChangedFlag()
|
||||
{
|
||||
return changed;
|
||||
//dstream<<"Deprecated getChangedFlag() called"<<std::endl;
|
||||
if(getModified() == MOD_STATE_CLEAN)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// m_modified methods
|
||||
void raiseModified(u32 mod)
|
||||
{
|
||||
m_modified = MYMAX(m_modified, mod);
|
||||
}
|
||||
u32 getModified()
|
||||
{
|
||||
return m_modified;
|
||||
}
|
||||
void resetModified()
|
||||
{
|
||||
m_modified = MOD_STATE_CLEAN;
|
||||
}
|
||||
|
||||
// is_underground getter/setter
|
||||
bool getIsUnderground()
|
||||
{
|
||||
return is_underground;
|
||||
@ -270,7 +205,7 @@ public:
|
||||
void setIsUnderground(bool a_is_underground)
|
||||
{
|
||||
is_underground = a_is_underground;
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
@ -288,22 +223,22 @@ public:
|
||||
void setLightingExpired(bool expired)
|
||||
{
|
||||
m_lighting_expired = expired;
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
bool getLightingExpired()
|
||||
{
|
||||
return m_lighting_expired;
|
||||
}
|
||||
|
||||
/*bool isFullyGenerated()
|
||||
bool isGenerated()
|
||||
{
|
||||
return !m_not_fully_generated;
|
||||
return m_generated;
|
||||
}
|
||||
void setFullyGenerated(bool b)
|
||||
void setGenerated(bool b)
|
||||
{
|
||||
setChangedFlag();
|
||||
m_not_fully_generated = !b;
|
||||
}*/
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
m_generated = b;
|
||||
}
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
@ -381,7 +316,7 @@ public:
|
||||
if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
|
||||
if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
|
||||
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
|
||||
void setNode(v3s16 p, MapNode & n)
|
||||
@ -410,7 +345,7 @@ public:
|
||||
if(data == NULL)
|
||||
throw InvalidPositionException();
|
||||
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
|
||||
void setNodeNoCheck(v3s16 p, MapNode & n)
|
||||
@ -474,8 +409,7 @@ public:
|
||||
|
||||
// See comments in mapblock.cpp
|
||||
bool propagateSunlight(core::map<v3s16, bool> & light_sources,
|
||||
bool remove_light=false, bool *black_air_left=NULL,
|
||||
bool grow_grass=false);
|
||||
bool remove_light=false, bool *black_air_left=NULL);
|
||||
|
||||
// Copies data to VoxelManipulator to getPosRelative()
|
||||
void copyTo(VoxelManipulator &dst);
|
||||
@ -487,36 +421,36 @@ public:
|
||||
DEPRECATED
|
||||
*/
|
||||
|
||||
void serializeObjects(std::ostream &os, u8 version)
|
||||
/*void serializeObjects(std::ostream &os, u8 version)
|
||||
{
|
||||
m_objects.serialize(os, version);
|
||||
}
|
||||
}*/
|
||||
// If smgr!=NULL, new objects are added to the scene
|
||||
void updateObjects(std::istream &is, u8 version,
|
||||
scene::ISceneManager *smgr, u32 daynight_ratio)
|
||||
{
|
||||
m_objects.update(is, version, smgr, daynight_ratio);
|
||||
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
void clearObjects()
|
||||
{
|
||||
m_objects.clear();
|
||||
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
void addObject(MapBlockObject *object)
|
||||
throw(ContainerFullException, AlreadyExistsException)
|
||||
{
|
||||
m_objects.add(object);
|
||||
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
void removeObject(s16 id)
|
||||
{
|
||||
m_objects.remove(id);
|
||||
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
MapBlockObject * getObject(s16 id)
|
||||
{
|
||||
@ -626,12 +560,32 @@ public:
|
||||
void setTimestamp(u32 time)
|
||||
{
|
||||
m_timestamp = time;
|
||||
setChangedFlag();
|
||||
raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
|
||||
}
|
||||
void setTimestampNoChangedFlag(u32 time)
|
||||
{
|
||||
m_timestamp = time;
|
||||
}
|
||||
u32 getTimestamp()
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
/*
|
||||
See m_usage_timer
|
||||
*/
|
||||
void resetUsageTimer()
|
||||
{
|
||||
m_usage_timer = 0;
|
||||
}
|
||||
void incrementUsageTimer(float dtime)
|
||||
{
|
||||
m_usage_timer += dtime;
|
||||
}
|
||||
u32 getUsageTimer()
|
||||
{
|
||||
return m_usage_timer;
|
||||
}
|
||||
|
||||
/*
|
||||
Serialization
|
||||
@ -698,10 +652,10 @@ private:
|
||||
|
||||
/*
|
||||
- On the server, this is used for telling whether the
|
||||
block has been changed from the one on disk.
|
||||
block has been modified from the one on disk.
|
||||
- On the client, this is used for nothing.
|
||||
*/
|
||||
bool changed;
|
||||
u32 m_modified;
|
||||
|
||||
/*
|
||||
When propagating sunlight and the above block doesn't exist,
|
||||
@ -724,6 +678,8 @@ private:
|
||||
|
||||
// Whether day and night lighting differs
|
||||
bool m_day_night_differs;
|
||||
|
||||
bool m_generated;
|
||||
|
||||
// DEPRECATED
|
||||
MapBlockObjectList m_objects;
|
||||
@ -747,6 +703,12 @@ private:
|
||||
Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
|
||||
*/
|
||||
u32 m_timestamp;
|
||||
|
||||
/*
|
||||
When the block is accessed, this is set to 0.
|
||||
Map will unload the block when this reaches a timeout.
|
||||
*/
|
||||
float m_usage_timer;
|
||||
};
|
||||
|
||||
inline bool blockpos_over_limit(v3s16 p)
|
||||
|
791
src/mapblock_mesh.cpp
Normal file
791
src/mapblock_mesh.cpp
Normal file
@ -0,0 +1,791 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mapblock_mesh.h"
|
||||
#include "light.h"
|
||||
#include "mapblock.h"
|
||||
#include "map.h"
|
||||
#include "main.h" // For g_settings and g_texturesource
|
||||
#include "content_mapblock.h"
|
||||
|
||||
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
|
||||
{
|
||||
m_daynight_ratio = daynight_ratio;
|
||||
m_blockpos = block->getPos();
|
||||
|
||||
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
/*
|
||||
There is no harm not copying the TempMods of the neighbors
|
||||
because they are already copied to this block
|
||||
*/
|
||||
m_temp_mods.clear();
|
||||
block->copyTempMods(m_temp_mods);
|
||||
|
||||
/*
|
||||
Copy data
|
||||
*/
|
||||
|
||||
// Allocate this block + neighbors
|
||||
m_vmanip.clear();
|
||||
m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
|
||||
blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
|
||||
|
||||
{
|
||||
//TimeTaker timer("copy central block data");
|
||||
// 0ms
|
||||
|
||||
// Copy our data
|
||||
block->copyTo(m_vmanip);
|
||||
}
|
||||
{
|
||||
//TimeTaker timer("copy neighbor block data");
|
||||
// 0ms
|
||||
|
||||
/*
|
||||
Copy neighbors. This is lightning fast.
|
||||
Copying only the borders would be *very* slow.
|
||||
*/
|
||||
|
||||
// Get map
|
||||
NodeContainer *parentcontainer = block->getParent();
|
||||
// This will only work if the parent is the map
|
||||
assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP);
|
||||
// OK, we have the map!
|
||||
Map *map = (Map*)parentcontainer;
|
||||
|
||||
for(u16 i=0; i<6; i++)
|
||||
{
|
||||
const v3s16 &dir = g_6dirs[i];
|
||||
v3s16 bp = m_blockpos + dir;
|
||||
MapBlock *b = map->getBlockNoCreateNoEx(bp);
|
||||
if(b)
|
||||
b->copyTo(m_vmanip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
vertex_dirs: v3s16[4]
|
||||
*/
|
||||
void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
|
||||
{
|
||||
/*
|
||||
If looked from outside the node towards the face, the corners are:
|
||||
0: bottom-right
|
||||
1: bottom-left
|
||||
2: top-left
|
||||
3: top-right
|
||||
*/
|
||||
if(dir == v3s16(0,0,1))
|
||||
{
|
||||
// If looking towards z+, this is the face that is behind
|
||||
// the center point, facing towards z+.
|
||||
vertex_dirs[0] = v3s16(-1,-1, 1);
|
||||
vertex_dirs[1] = v3s16( 1,-1, 1);
|
||||
vertex_dirs[2] = v3s16( 1, 1, 1);
|
||||
vertex_dirs[3] = v3s16(-1, 1, 1);
|
||||
}
|
||||
else if(dir == v3s16(0,0,-1))
|
||||
{
|
||||
// faces towards Z-
|
||||
vertex_dirs[0] = v3s16( 1,-1,-1);
|
||||
vertex_dirs[1] = v3s16(-1,-1,-1);
|
||||
vertex_dirs[2] = v3s16(-1, 1,-1);
|
||||
vertex_dirs[3] = v3s16( 1, 1,-1);
|
||||
}
|
||||
else if(dir == v3s16(1,0,0))
|
||||
{
|
||||
// faces towards X+
|
||||
vertex_dirs[0] = v3s16( 1,-1, 1);
|
||||
vertex_dirs[1] = v3s16( 1,-1,-1);
|
||||
vertex_dirs[2] = v3s16( 1, 1,-1);
|
||||
vertex_dirs[3] = v3s16( 1, 1, 1);
|
||||
}
|
||||
else if(dir == v3s16(-1,0,0))
|
||||
{
|
||||
// faces towards X-
|
||||
vertex_dirs[0] = v3s16(-1,-1,-1);
|
||||
vertex_dirs[1] = v3s16(-1,-1, 1);
|
||||
vertex_dirs[2] = v3s16(-1, 1, 1);
|
||||
vertex_dirs[3] = v3s16(-1, 1,-1);
|
||||
}
|
||||
else if(dir == v3s16(0,1,0))
|
||||
{
|
||||
// faces towards Y+ (assume Z- as "down" in texture)
|
||||
vertex_dirs[0] = v3s16( 1, 1,-1);
|
||||
vertex_dirs[1] = v3s16(-1, 1,-1);
|
||||
vertex_dirs[2] = v3s16(-1, 1, 1);
|
||||
vertex_dirs[3] = v3s16( 1, 1, 1);
|
||||
}
|
||||
else if(dir == v3s16(0,-1,0))
|
||||
{
|
||||
// faces towards Y- (assume Z+ as "down" in texture)
|
||||
vertex_dirs[0] = v3s16( 1,-1, 1);
|
||||
vertex_dirs[1] = v3s16(-1,-1, 1);
|
||||
vertex_dirs[2] = v3s16(-1,-1,-1);
|
||||
vertex_dirs[3] = v3s16( 1,-1,-1);
|
||||
}
|
||||
}
|
||||
|
||||
inline video::SColor lightColor(u8 alpha, u8 light)
|
||||
{
|
||||
return video::SColor(alpha,light,light,light);
|
||||
}
|
||||
|
||||
struct FastFace
|
||||
{
|
||||
TileSpec tile;
|
||||
video::S3DVertex vertices[4]; // Precalculated vertices
|
||||
};
|
||||
|
||||
void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
|
||||
v3s16 dir, v3f scale, v3f posRelative_f,
|
||||
core::array<FastFace> &dest)
|
||||
{
|
||||
FastFace face;
|
||||
|
||||
// Position is at the center of the cube.
|
||||
v3f pos = p * BS;
|
||||
posRelative_f *= BS;
|
||||
|
||||
v3f vertex_pos[4];
|
||||
v3s16 vertex_dirs[4];
|
||||
getNodeVertexDirs(dir, vertex_dirs);
|
||||
for(u16 i=0; i<4; i++)
|
||||
{
|
||||
vertex_pos[i] = v3f(
|
||||
BS/2*vertex_dirs[i].X,
|
||||
BS/2*vertex_dirs[i].Y,
|
||||
BS/2*vertex_dirs[i].Z
|
||||
);
|
||||
}
|
||||
|
||||
for(u16 i=0; i<4; i++)
|
||||
{
|
||||
vertex_pos[i].X *= scale.X;
|
||||
vertex_pos[i].Y *= scale.Y;
|
||||
vertex_pos[i].Z *= scale.Z;
|
||||
vertex_pos[i] += pos + posRelative_f;
|
||||
}
|
||||
|
||||
f32 abs_scale = 1.;
|
||||
if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
|
||||
else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
|
||||
else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
|
||||
|
||||
v3f zerovector = v3f(0,0,0);
|
||||
|
||||
u8 alpha = tile.alpha;
|
||||
/*u8 alpha = 255;
|
||||
if(tile.id == TILE_WATER)
|
||||
alpha = WATER_ALPHA;*/
|
||||
|
||||
float x0 = tile.texture.pos.X;
|
||||
float y0 = tile.texture.pos.Y;
|
||||
float w = tile.texture.size.X;
|
||||
float h = tile.texture.size.Y;
|
||||
|
||||
/*video::SColor c = lightColor(alpha, li);
|
||||
|
||||
face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0+h));
|
||||
face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
|
||||
core::vector2d<f32>(x0, y0+h));
|
||||
face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
|
||||
core::vector2d<f32>(x0, y0));
|
||||
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0));*/
|
||||
|
||||
face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
|
||||
lightColor(alpha, li0),
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0+h));
|
||||
face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
|
||||
lightColor(alpha, li1),
|
||||
core::vector2d<f32>(x0, y0+h));
|
||||
face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
|
||||
lightColor(alpha, li2),
|
||||
core::vector2d<f32>(x0, y0));
|
||||
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
|
||||
lightColor(alpha, li3),
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0));
|
||||
|
||||
face.tile = tile;
|
||||
//DEBUG
|
||||
//f->tile = TILE_STONE;
|
||||
|
||||
dest.push_back(face);
|
||||
}
|
||||
|
||||
/*
|
||||
Gets node tile from any place relative to block.
|
||||
Returns TILE_NODE if doesn't exist or should not be drawn.
|
||||
*/
|
||||
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
|
||||
NodeModMap &temp_mods)
|
||||
{
|
||||
TileSpec spec;
|
||||
spec = mn.getTile(face_dir);
|
||||
|
||||
/*
|
||||
Check temporary modifications on this node
|
||||
*/
|
||||
/*core::map<v3s16, NodeMod>::Node *n;
|
||||
n = m_temp_mods.find(p);
|
||||
// If modified
|
||||
if(n != NULL)
|
||||
{
|
||||
struct NodeMod mod = n->getValue();*/
|
||||
NodeMod mod;
|
||||
if(temp_mods.get(p, &mod))
|
||||
{
|
||||
if(mod.type == NODEMOD_CHANGECONTENT)
|
||||
{
|
||||
MapNode mn2(mod.param);
|
||||
spec = mn2.getTile(face_dir);
|
||||
}
|
||||
if(mod.type == NODEMOD_CRACK)
|
||||
{
|
||||
/*
|
||||
Get texture id, translate it to name, append stuff to
|
||||
name, get texture id
|
||||
*/
|
||||
|
||||
// Get original texture name
|
||||
u32 orig_id = spec.texture.id;
|
||||
std::string orig_name = g_texturesource->getTextureName(orig_id);
|
||||
|
||||
// Create new texture name
|
||||
std::ostringstream os;
|
||||
os<<orig_name<<"^[crack"<<mod.param;
|
||||
|
||||
// Get new texture
|
||||
u32 new_id = g_texturesource->getTextureId(os.str());
|
||||
|
||||
/*dstream<<"MapBlock::getNodeTile(): Switching from "
|
||||
<<orig_name<<" to "<<os.str()<<" ("
|
||||
<<orig_id<<" to "<<new_id<<")"<<std::endl;*/
|
||||
|
||||
spec.texture = g_texturesource->getTexture(new_id);
|
||||
}
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
|
||||
{
|
||||
/*
|
||||
Check temporary modifications on this node
|
||||
*/
|
||||
/*core::map<v3s16, NodeMod>::Node *n;
|
||||
n = m_temp_mods.find(p);
|
||||
// If modified
|
||||
if(n != NULL)
|
||||
{
|
||||
struct NodeMod mod = n->getValue();*/
|
||||
NodeMod mod;
|
||||
if(temp_mods.get(p, &mod))
|
||||
{
|
||||
if(mod.type == NODEMOD_CHANGECONTENT)
|
||||
{
|
||||
// Overrides content
|
||||
return mod.param;
|
||||
}
|
||||
if(mod.type == NODEMOD_CRACK)
|
||||
{
|
||||
/*
|
||||
Content doesn't change.
|
||||
|
||||
face_contents works just like it should, because
|
||||
there should not be faces between differently cracked
|
||||
nodes.
|
||||
|
||||
If a semi-transparent node is cracked in front an
|
||||
another one, it really doesn't matter whether there
|
||||
is a cracked face drawn in between or not.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
return mn.d;
|
||||
}
|
||||
|
||||
v3s16 dirs8[8] = {
|
||||
v3s16(0,0,0),
|
||||
v3s16(0,0,1),
|
||||
v3s16(0,1,0),
|
||||
v3s16(0,1,1),
|
||||
v3s16(1,0,0),
|
||||
v3s16(1,1,0),
|
||||
v3s16(1,0,1),
|
||||
v3s16(1,1,1),
|
||||
};
|
||||
|
||||
// Calculate lighting at the XYZ- corner of p
|
||||
u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
|
||||
{
|
||||
u16 ambient_occlusion = 0;
|
||||
u16 light = 0;
|
||||
u16 light_count = 0;
|
||||
for(u32 i=0; i<8; i++)
|
||||
{
|
||||
MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
|
||||
if(content_features(n.d).param_type == CPT_LIGHT
|
||||
// Fast-style leaves look better this way
|
||||
&& content_features(n.d).solidness != 2)
|
||||
{
|
||||
light += decode_light(n.getLightBlend(daynight_ratio));
|
||||
light_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(n.d != CONTENT_IGNORE)
|
||||
ambient_occlusion++;
|
||||
}
|
||||
}
|
||||
|
||||
if(light_count == 0)
|
||||
return 255;
|
||||
|
||||
light /= light_count;
|
||||
|
||||
if(ambient_occlusion > 4)
|
||||
{
|
||||
ambient_occlusion -= 4;
|
||||
light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
|
||||
}
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
// Calculate lighting at the given corner of p
|
||||
u8 getSmoothLight(v3s16 p, v3s16 corner,
|
||||
VoxelManipulator &vmanip, u32 daynight_ratio)
|
||||
{
|
||||
if(corner.X == 1) p.X += 1;
|
||||
else assert(corner.X == -1);
|
||||
if(corner.Y == 1) p.Y += 1;
|
||||
else assert(corner.Y == -1);
|
||||
if(corner.Z == 1) p.Z += 1;
|
||||
else assert(corner.Z == -1);
|
||||
|
||||
return getSmoothLight(p, vmanip, daynight_ratio);
|
||||
}
|
||||
|
||||
void getTileInfo(
|
||||
// Input:
|
||||
v3s16 blockpos_nodes,
|
||||
v3s16 p,
|
||||
v3s16 face_dir,
|
||||
u32 daynight_ratio,
|
||||
VoxelManipulator &vmanip,
|
||||
NodeModMap &temp_mods,
|
||||
bool smooth_lighting,
|
||||
// Output:
|
||||
bool &makes_face,
|
||||
v3s16 &p_corrected,
|
||||
v3s16 &face_dir_corrected,
|
||||
u8 *lights,
|
||||
TileSpec &tile
|
||||
)
|
||||
{
|
||||
MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
|
||||
MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
|
||||
TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
|
||||
TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
|
||||
|
||||
// This is hackish
|
||||
u8 content0 = getNodeContent(p, n0, temp_mods);
|
||||
u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
|
||||
u8 mf = face_contents(content0, content1);
|
||||
|
||||
if(mf == 0)
|
||||
{
|
||||
makes_face = false;
|
||||
return;
|
||||
}
|
||||
|
||||
makes_face = true;
|
||||
|
||||
if(mf == 1)
|
||||
{
|
||||
tile = tile0;
|
||||
p_corrected = p;
|
||||
face_dir_corrected = face_dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile = tile1;
|
||||
p_corrected = p + face_dir;
|
||||
face_dir_corrected = -face_dir;
|
||||
}
|
||||
|
||||
if(smooth_lighting == false)
|
||||
{
|
||||
lights[0] = lights[1] = lights[2] = lights[3] =
|
||||
decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir));
|
||||
}
|
||||
else
|
||||
{
|
||||
v3s16 vertex_dirs[4];
|
||||
getNodeVertexDirs(face_dir_corrected, vertex_dirs);
|
||||
for(u16 i=0; i<4; i++)
|
||||
{
|
||||
lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
|
||||
vertex_dirs[i], vmanip, daynight_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
startpos:
|
||||
translate_dir: unit vector with only one of x, y or z
|
||||
face_dir: unit vector with only one of x, y or z
|
||||
*/
|
||||
void updateFastFaceRow(
|
||||
u32 daynight_ratio,
|
||||
v3f posRelative_f,
|
||||
v3s16 startpos,
|
||||
u16 length,
|
||||
v3s16 translate_dir,
|
||||
v3f translate_dir_f,
|
||||
v3s16 face_dir,
|
||||
v3f face_dir_f,
|
||||
core::array<FastFace> &dest,
|
||||
NodeModMap &temp_mods,
|
||||
VoxelManipulator &vmanip,
|
||||
v3s16 blockpos_nodes,
|
||||
bool smooth_lighting)
|
||||
{
|
||||
v3s16 p = startpos;
|
||||
|
||||
u16 continuous_tiles_count = 0;
|
||||
|
||||
bool makes_face;
|
||||
v3s16 p_corrected;
|
||||
v3s16 face_dir_corrected;
|
||||
u8 lights[4];
|
||||
TileSpec tile;
|
||||
getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
|
||||
vmanip, temp_mods, smooth_lighting,
|
||||
makes_face, p_corrected, face_dir_corrected, lights, tile);
|
||||
|
||||
for(u16 j=0; j<length; j++)
|
||||
{
|
||||
// If tiling can be done, this is set to false in the next step
|
||||
bool next_is_different = true;
|
||||
|
||||
v3s16 p_next;
|
||||
|
||||
bool next_makes_face = false;
|
||||
v3s16 next_p_corrected;
|
||||
v3s16 next_face_dir_corrected;
|
||||
u8 next_lights[4] = {0,0,0,0};
|
||||
TileSpec next_tile;
|
||||
|
||||
// If at last position, there is nothing to compare to and
|
||||
// the face must be drawn anyway
|
||||
if(j != length - 1)
|
||||
{
|
||||
p_next = p + translate_dir;
|
||||
|
||||
getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
|
||||
vmanip, temp_mods, smooth_lighting,
|
||||
next_makes_face, next_p_corrected,
|
||||
next_face_dir_corrected, next_lights,
|
||||
next_tile);
|
||||
|
||||
if(next_makes_face == makes_face
|
||||
&& next_p_corrected == p_corrected
|
||||
&& next_face_dir_corrected == face_dir_corrected
|
||||
&& next_lights[0] == lights[0]
|
||||
&& next_lights[1] == lights[1]
|
||||
&& next_lights[2] == lights[2]
|
||||
&& next_lights[3] == lights[3]
|
||||
&& next_tile == tile)
|
||||
{
|
||||
next_is_different = false;
|
||||
}
|
||||
}
|
||||
|
||||
continuous_tiles_count++;
|
||||
|
||||
// This is set to true if the texture doesn't allow more tiling
|
||||
bool end_of_texture = false;
|
||||
/*
|
||||
If there is no texture, it can be tiled infinitely.
|
||||
If tiled==0, it means the texture can be tiled infinitely.
|
||||
Otherwise check tiled agains continuous_tiles_count.
|
||||
*/
|
||||
if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
|
||||
{
|
||||
if(tile.texture.tiled <= continuous_tiles_count)
|
||||
end_of_texture = true;
|
||||
}
|
||||
|
||||
// Do this to disable tiling textures
|
||||
//end_of_texture = true; //DEBUG
|
||||
|
||||
if(next_is_different || end_of_texture)
|
||||
{
|
||||
/*
|
||||
Create a face if there should be one
|
||||
*/
|
||||
if(makes_face)
|
||||
{
|
||||
// Floating point conversion of the position vector
|
||||
v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
|
||||
// Center point of face (kind of)
|
||||
v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
|
||||
v3f scale(1,1,1);
|
||||
|
||||
if(translate_dir.X != 0)
|
||||
{
|
||||
scale.X = continuous_tiles_count;
|
||||
}
|
||||
if(translate_dir.Y != 0)
|
||||
{
|
||||
scale.Y = continuous_tiles_count;
|
||||
}
|
||||
if(translate_dir.Z != 0)
|
||||
{
|
||||
scale.Z = continuous_tiles_count;
|
||||
}
|
||||
|
||||
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
|
||||
sp, face_dir_corrected, scale,
|
||||
posRelative_f, dest);
|
||||
}
|
||||
|
||||
continuous_tiles_count = 0;
|
||||
|
||||
makes_face = next_makes_face;
|
||||
p_corrected = next_p_corrected;
|
||||
face_dir_corrected = next_face_dir_corrected;
|
||||
lights[0] = next_lights[0];
|
||||
lights[1] = next_lights[1];
|
||||
lights[2] = next_lights[2];
|
||||
lights[3] = next_lights[3];
|
||||
tile = next_tile;
|
||||
}
|
||||
|
||||
p = p_next;
|
||||
}
|
||||
}
|
||||
|
||||
scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
|
||||
{
|
||||
// 4-21ms for MAP_BLOCKSIZE=16
|
||||
// 24-155ms for MAP_BLOCKSIZE=32
|
||||
//TimeTaker timer1("makeMapBlockMesh()");
|
||||
|
||||
core::array<FastFace> fastfaces_new;
|
||||
|
||||
v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
// floating point conversion
|
||||
v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
|
||||
|
||||
/*
|
||||
Some settings
|
||||
*/
|
||||
//bool new_style_water = g_settings.getBool("new_style_water");
|
||||
//bool new_style_leaves = g_settings.getBool("new_style_leaves");
|
||||
bool smooth_lighting = g_settings.getBool("smooth_lighting");
|
||||
|
||||
/*
|
||||
We are including the faces of the trailing edges of the block.
|
||||
This means that when something changes, the caller must
|
||||
also update the meshes of the blocks at the leading edges.
|
||||
|
||||
NOTE: This is the slowest part of this method.
|
||||
*/
|
||||
|
||||
{
|
||||
// 4-23ms for MAP_BLOCKSIZE=16
|
||||
//TimeTaker timer2("updateMesh() collect");
|
||||
|
||||
/*
|
||||
Go through every y,z and get top(y+) faces in rows of x+
|
||||
*/
|
||||
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
|
||||
for(s16 z=0; z<MAP_BLOCKSIZE; z++){
|
||||
updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
|
||||
v3s16(0,y,z), MAP_BLOCKSIZE,
|
||||
v3s16(1,0,0), //dir
|
||||
v3f (1,0,0),
|
||||
v3s16(0,1,0), //face dir
|
||||
v3f (0,1,0),
|
||||
fastfaces_new,
|
||||
data->m_temp_mods,
|
||||
data->m_vmanip,
|
||||
blockpos_nodes,
|
||||
smooth_lighting);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Go through every x,y and get right(x+) faces in rows of z+
|
||||
*/
|
||||
for(s16 x=0; x<MAP_BLOCKSIZE; x++){
|
||||
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
|
||||
updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
|
||||
v3s16(x,y,0), MAP_BLOCKSIZE,
|
||||
v3s16(0,0,1),
|
||||
v3f (0,0,1),
|
||||
v3s16(1,0,0),
|
||||
v3f (1,0,0),
|
||||
fastfaces_new,
|
||||
data->m_temp_mods,
|
||||
data->m_vmanip,
|
||||
blockpos_nodes,
|
||||
smooth_lighting);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Go through every y,z and get back(z+) faces in rows of x+
|
||||
*/
|
||||
for(s16 z=0; z<MAP_BLOCKSIZE; z++){
|
||||
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
|
||||
updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
|
||||
v3s16(0,y,z), MAP_BLOCKSIZE,
|
||||
v3s16(1,0,0),
|
||||
v3f (1,0,0),
|
||||
v3s16(0,0,1),
|
||||
v3f (0,0,1),
|
||||
fastfaces_new,
|
||||
data->m_temp_mods,
|
||||
data->m_vmanip,
|
||||
blockpos_nodes,
|
||||
smooth_lighting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of slow part
|
||||
|
||||
/*
|
||||
Convert FastFaces to SMesh
|
||||
*/
|
||||
|
||||
MeshCollector collector;
|
||||
|
||||
if(fastfaces_new.size() > 0)
|
||||
{
|
||||
// avg 0ms (100ms spikes when loading textures the first time)
|
||||
//TimeTaker timer2("updateMesh() mesh building");
|
||||
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
|
||||
//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
|
||||
|
||||
for(u32 i=0; i<fastfaces_new.size(); i++)
|
||||
{
|
||||
FastFace &f = fastfaces_new[i];
|
||||
|
||||
const u16 indices[] = {0,1,2,2,3,0};
|
||||
const u16 indices_alternate[] = {0,1,3,2,3,1};
|
||||
|
||||
video::ITexture *texture = f.tile.texture.atlas;
|
||||
if(texture == NULL)
|
||||
continue;
|
||||
|
||||
material.setTexture(0, texture);
|
||||
|
||||
f.tile.applyMaterialOptions(material);
|
||||
|
||||
const u16 *indices_p = indices;
|
||||
|
||||
/*
|
||||
Revert triangles for nicer looking gradient if vertices
|
||||
1 and 3 have same color or 0 and 2 have different color.
|
||||
*/
|
||||
if(f.vertices[0].Color != f.vertices[2].Color
|
||||
|| f.vertices[1].Color == f.vertices[3].Color)
|
||||
indices_p = indices_alternate;
|
||||
|
||||
collector.append(material, f.vertices, 4, indices_p, 6);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Add special graphics:
|
||||
- torches
|
||||
- flowing water
|
||||
- fences
|
||||
- whatever
|
||||
*/
|
||||
|
||||
mapblock_mesh_generate_special(data, collector);
|
||||
|
||||
/*
|
||||
Add stuff from collector to mesh
|
||||
*/
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
mesh_new = new scene::SMesh();
|
||||
|
||||
collector.fillMesh(mesh_new);
|
||||
|
||||
/*
|
||||
Do some stuff to the mesh
|
||||
*/
|
||||
|
||||
mesh_new->recalculateBoundingBox();
|
||||
|
||||
/*
|
||||
Delete new mesh if it is empty
|
||||
*/
|
||||
|
||||
if(mesh_new->getMeshBufferCount() == 0)
|
||||
{
|
||||
mesh_new->drop();
|
||||
mesh_new = NULL;
|
||||
}
|
||||
|
||||
if(mesh_new)
|
||||
{
|
||||
#if 0
|
||||
// Usually 1-700 faces and 1-7 materials
|
||||
std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
|
||||
<<"and uses "<<mesh_new->getMeshBufferCount()
|
||||
<<" materials (meshbuffers)"<<std::endl;
|
||||
#endif
|
||||
|
||||
// Use VBO for mesh (this just would set this for ever buffer)
|
||||
// This will lead to infinite memory usage because or irrlicht.
|
||||
//mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
|
||||
/*
|
||||
NOTE: If that is enabled, some kind of a queue to the main
|
||||
thread should be made which would call irrlicht to delete
|
||||
the hardware buffer and then delete the mesh
|
||||
*/
|
||||
}
|
||||
|
||||
return mesh_new;
|
||||
|
||||
//std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
|
||||
}
|
||||
|
143
src/mapblock_mesh.h
Normal file
143
src/mapblock_mesh.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MAPBLOCK_MESH_HEADER
|
||||
#define MAPBLOCK_MESH_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "mapblock_nodemod.h"
|
||||
#include "voxel.h"
|
||||
|
||||
/*
|
||||
Mesh making stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
This is used because CMeshBuffer::append() is very slow
|
||||
*/
|
||||
struct PreMeshBuffer
|
||||
{
|
||||
video::SMaterial material;
|
||||
core::array<u16> indices;
|
||||
core::array<video::S3DVertex> vertices;
|
||||
};
|
||||
|
||||
class MeshCollector
|
||||
{
|
||||
public:
|
||||
void append(
|
||||
video::SMaterial material,
|
||||
const video::S3DVertex* const vertices,
|
||||
u32 numVertices,
|
||||
const u16* const indices,
|
||||
u32 numIndices
|
||||
)
|
||||
{
|
||||
PreMeshBuffer *p = NULL;
|
||||
for(u32 i=0; i<m_prebuffers.size(); i++)
|
||||
{
|
||||
PreMeshBuffer &pp = m_prebuffers[i];
|
||||
if(pp.material != material)
|
||||
continue;
|
||||
|
||||
p = &pp;
|
||||
break;
|
||||
}
|
||||
|
||||
if(p == NULL)
|
||||
{
|
||||
PreMeshBuffer pp;
|
||||
pp.material = material;
|
||||
m_prebuffers.push_back(pp);
|
||||
p = &m_prebuffers[m_prebuffers.size()-1];
|
||||
}
|
||||
|
||||
u32 vertex_count = p->vertices.size();
|
||||
for(u32 i=0; i<numIndices; i++)
|
||||
{
|
||||
u32 j = indices[i] + vertex_count;
|
||||
if(j > 65535)
|
||||
{
|
||||
dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
|
||||
// NOTE: Fix is to just add an another MeshBuffer
|
||||
}
|
||||
p->indices.push_back(j);
|
||||
}
|
||||
for(u32 i=0; i<numVertices; i++)
|
||||
{
|
||||
p->vertices.push_back(vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void fillMesh(scene::SMesh *mesh)
|
||||
{
|
||||
/*dstream<<"Filling mesh with "<<m_prebuffers.size()
|
||||
<<" meshbuffers"<<std::endl;*/
|
||||
for(u32 i=0; i<m_prebuffers.size(); i++)
|
||||
{
|
||||
PreMeshBuffer &p = m_prebuffers[i];
|
||||
|
||||
/*dstream<<"p.vertices.size()="<<p.vertices.size()
|
||||
<<", p.indices.size()="<<p.indices.size()
|
||||
<<std::endl;*/
|
||||
|
||||
// Create meshbuffer
|
||||
|
||||
// This is a "Standard MeshBuffer",
|
||||
// it's a typedeffed CMeshBuffer<video::S3DVertex>
|
||||
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
// Set material
|
||||
buf->Material = p.material;
|
||||
//((scene::SMeshBuffer*)buf)->Material = p.material;
|
||||
// Use VBO
|
||||
//buf->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
// Mesh grabbed it
|
||||
buf->drop();
|
||||
|
||||
buf->append(p.vertices.pointer(), p.vertices.size(),
|
||||
p.indices.pointer(), p.indices.size());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
core::array<PreMeshBuffer> m_prebuffers;
|
||||
};
|
||||
|
||||
class MapBlock;
|
||||
|
||||
struct MeshMakeData
|
||||
{
|
||||
u32 m_daynight_ratio;
|
||||
NodeModMap m_temp_mods;
|
||||
VoxelManipulator m_vmanip;
|
||||
v3s16 m_blockpos;
|
||||
|
||||
/*
|
||||
Copy central data directly from block, and other data from
|
||||
parent of block.
|
||||
*/
|
||||
void fill(u32 daynight_ratio, MapBlock *block);
|
||||
};
|
||||
|
||||
scene::SMesh* makeMapBlockMesh(MeshMakeData *data);
|
||||
|
||||
#endif
|
||||
|
114
src/mapblock_nodemod.h
Normal file
114
src/mapblock_nodemod.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MAPBLOCK_NODEMOD_HEADER
|
||||
#define MAPBLOCK_NODEMOD_HEADER
|
||||
|
||||
enum NodeModType
|
||||
{
|
||||
NODEMOD_NONE,
|
||||
NODEMOD_CHANGECONTENT, //param is content id
|
||||
NODEMOD_CRACK // param is crack progression
|
||||
};
|
||||
|
||||
struct NodeMod
|
||||
{
|
||||
NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
|
||||
{
|
||||
type = a_type;
|
||||
param = a_param;
|
||||
}
|
||||
bool operator==(const NodeMod &other)
|
||||
{
|
||||
return (type == other.type && param == other.param);
|
||||
}
|
||||
enum NodeModType type;
|
||||
u16 param;
|
||||
};
|
||||
|
||||
class NodeModMap
|
||||
{
|
||||
public:
|
||||
/*
|
||||
returns true if the mod was different last time
|
||||
*/
|
||||
bool set(v3s16 p, const NodeMod &mod)
|
||||
{
|
||||
// See if old is different, cancel if it is not different.
|
||||
core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
|
||||
if(n)
|
||||
{
|
||||
NodeMod old = n->getValue();
|
||||
if(old == mod)
|
||||
return false;
|
||||
|
||||
n->setValue(mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mods.insert(p, mod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Returns true if there was one
|
||||
bool get(v3s16 p, NodeMod *mod)
|
||||
{
|
||||
core::map<v3s16, NodeMod>::Node *n;
|
||||
n = m_mods.find(p);
|
||||
if(n == NULL)
|
||||
return false;
|
||||
if(mod)
|
||||
*mod = n->getValue();
|
||||
return true;
|
||||
}
|
||||
bool clear(v3s16 p)
|
||||
{
|
||||
if(m_mods.find(p))
|
||||
{
|
||||
m_mods.remove(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool clear()
|
||||
{
|
||||
if(m_mods.size() == 0)
|
||||
return false;
|
||||
m_mods.clear();
|
||||
return true;
|
||||
}
|
||||
void copy(NodeModMap &dest)
|
||||
{
|
||||
dest.m_mods.clear();
|
||||
|
||||
for(core::map<v3s16, NodeMod>::Iterator
|
||||
i = m_mods.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
core::map<v3s16, NodeMod> m_mods;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
2007
src/mapgen.cpp
Normal file
2007
src/mapgen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
66
src/mapgen.h
Normal file
66
src/mapgen.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MAPGEN_HEADER
|
||||
#define MAPGEN_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "utility.h" // UniqueQueue
|
||||
|
||||
struct BlockMakeData;
|
||||
class MapBlock;
|
||||
class ManualMapVoxelManipulator;
|
||||
|
||||
namespace mapgen
|
||||
{
|
||||
// Finds precise ground level at any position
|
||||
s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision);
|
||||
|
||||
// Find out if block is completely underground
|
||||
bool block_is_underground(u64 seed, v3s16 blockpos);
|
||||
|
||||
// Main map generation routine
|
||||
void make_block(BlockMakeData *data);
|
||||
|
||||
// Add objects according to block content
|
||||
void add_random_objects(MapBlock *block);
|
||||
|
||||
/*
|
||||
These are used by FarMesh
|
||||
*/
|
||||
bool get_have_sand(u64 seed, v2s16 p2d);
|
||||
double tree_amount_2d(u64 seed, v2s16 p);
|
||||
|
||||
|
||||
struct BlockMakeData
|
||||
{
|
||||
bool no_op;
|
||||
ManualMapVoxelManipulator *vmanip;
|
||||
u64 seed;
|
||||
v3s16 blockpos;
|
||||
UniqueQueue<v3s16> transforming_liquid;
|
||||
|
||||
BlockMakeData();
|
||||
~BlockMakeData();
|
||||
};
|
||||
|
||||
}; // namespace mapgen
|
||||
|
||||
#endif
|
||||
|
365
src/mapnode.cpp
365
src/mapnode.cpp
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mineral.h"
|
||||
// For g_settings
|
||||
#include "main.h"
|
||||
#include "content_mapnode.h"
|
||||
#include "nodemetadata.h"
|
||||
|
||||
ContentFeatures::~ContentFeatures()
|
||||
@ -107,9 +108,9 @@ void init_mapnode()
|
||||
"g_texturesource!=NULL"<<std::endl;
|
||||
}
|
||||
|
||||
// Read some settings
|
||||
/*// Read some settings
|
||||
bool new_style_water = g_settings.getBool("new_style_water");
|
||||
bool new_style_leaves = g_settings.getBool("new_style_leaves");
|
||||
bool new_style_leaves = g_settings.getBool("new_style_leaves");*/
|
||||
|
||||
/*
|
||||
Initialize content feature table
|
||||
@ -131,313 +132,17 @@ void init_mapnode()
|
||||
{
|
||||
ContentFeatures *f = &g_content_features[i];
|
||||
// Re-initialize
|
||||
*f = ContentFeatures();
|
||||
f->reset();
|
||||
|
||||
for(u16 j=0; j<6; j++)
|
||||
f->tiles[j].material_type = initial_material_type;
|
||||
}
|
||||
|
||||
u8 i;
|
||||
ContentFeatures *f = NULL;
|
||||
|
||||
i = CONTENT_STONE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("stone.png");
|
||||
f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 1";
|
||||
/*
|
||||
Initialize mapnode content
|
||||
*/
|
||||
content_mapnode_init();
|
||||
|
||||
i = CONTENT_GRASS;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("mud.png^grass_side.png");
|
||||
f->setTexture(0, "grass.png");
|
||||
f->setTexture(1, "mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_MUD)+" 1";
|
||||
|
||||
i = CONTENT_GRASS_FOOTSTEPS;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("mud.png^grass_side.png");
|
||||
f->setTexture(0, "grass_footsteps.png");
|
||||
f->setTexture(1, "mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_MUD)+" 1";
|
||||
|
||||
i = CONTENT_MUD;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("mud.png");
|
||||
f->setInventoryTextureCube("mud.png", "mud.png", "mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_SAND;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("sand.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_SANDSTONE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("sandstone.png");
|
||||
f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_SAND)+" 1";
|
||||
|
||||
i = CONTENT_CLAY;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("clay.png");
|
||||
f->setInventoryTextureCube("clay.png", "clay.png", "clay.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("CraftItem lump_of_clay 4");
|
||||
|
||||
i = CONTENT_BRICK;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("brick.png");
|
||||
f->setInventoryTextureCube("brick.png", "brick.png", "brick.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("CraftItem clay_brick 4");
|
||||
|
||||
i = CONTENT_TREE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("tree.png");
|
||||
f->setTexture(0, "tree_top.png");
|
||||
f->setTexture(1, "tree_top.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_LEAVES;
|
||||
f = &g_content_features[i];
|
||||
f->light_propagates = true;
|
||||
//f->param_type = CPT_MINERAL;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
if(new_style_leaves)
|
||||
{
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
f->setAllTextures("[noalpha:leaves.png");
|
||||
}
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_CACTUS;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("cactus_side.png");
|
||||
f->setTexture(0, "cactus_top.png");
|
||||
f->setTexture(1, "cactus_top.png");
|
||||
f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_PAPYRUS;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture("papyrus.png");
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
|
||||
i = CONTENT_BOOKSHELF;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("bookshelf.png");
|
||||
f->setTexture(0, "wood.png");
|
||||
f->setTexture(1, "wood.png");
|
||||
// FIXME: setInventoryTextureCube() only cares for the first texture
|
||||
f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png");
|
||||
//f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_GLASS;
|
||||
f = &g_content_features[i];
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->setInventoryTextureCube("glass.png", "glass.png", "glass.png");
|
||||
|
||||
i = CONTENT_FENCE;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture("fence.png");
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->air_equivalent = true; // grass grows underneath
|
||||
|
||||
i = CONTENT_RAIL;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture("rail.png");
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->air_equivalent = true; // grass grows underneath
|
||||
f->walkable = false;
|
||||
|
||||
// Deprecated
|
||||
i = CONTENT_COALSTONE;
|
||||
f = &g_content_features[i];
|
||||
//f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
|
||||
f->setAllTextures("stone.png^mineral_coal.png");
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_WOOD;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("wood.png");
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_MESE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("mese.png");
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_CLOUD;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("cloud.png");
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_AIR;
|
||||
f = &g_content_features[i];
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
f->solidness = 0;
|
||||
f->walkable = false;
|
||||
f->pointable = false;
|
||||
f->diggable = false;
|
||||
f->buildable_to = true;
|
||||
f->air_equivalent = true;
|
||||
|
||||
i = CONTENT_WATER;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTextureCube("water.png", "water.png", "water.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->solidness = 0; // Drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
f->pointable = false;
|
||||
f->diggable = false;
|
||||
f->buildable_to = true;
|
||||
f->liquid_type = LIQUID_FLOWING;
|
||||
|
||||
i = CONTENT_WATERSOURCE;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture("water.png");
|
||||
if(new_style_water)
|
||||
{
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
}
|
||||
else // old style
|
||||
{
|
||||
f->solidness = 1;
|
||||
|
||||
TileSpec t;
|
||||
if(g_texturesource)
|
||||
t.texture = g_texturesource->getTexture("water.png");
|
||||
|
||||
t.alpha = WATER_ALPHA;
|
||||
t.material_type = MATERIAL_ALPHA_VERTEX;
|
||||
t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
f->setAllTiles(t);
|
||||
}
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->walkable = false;
|
||||
f->pointable = false;
|
||||
f->diggable = false;
|
||||
f->buildable_to = true;
|
||||
f->liquid_type = LIQUID_SOURCE;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_TORCH;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture("torch_on_floor.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
f->wall_mounted = true;
|
||||
f->air_equivalent = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_SIGN_WALL;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture("sign_wall.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->walkable = false;
|
||||
f->wall_mounted = true;
|
||||
f->air_equivalent = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
if(f->initial_metadata == NULL)
|
||||
f->initial_metadata = new SignNodeMetadata("Some sign");
|
||||
|
||||
i = CONTENT_CHEST;
|
||||
f = &g_content_features[i];
|
||||
f->param_type = CPT_FACEDIR_SIMPLE;
|
||||
f->setAllTextures("chest_side.png");
|
||||
f->setTexture(0, "chest_top.png");
|
||||
f->setTexture(1, "chest_top.png");
|
||||
f->setTexture(5, "chest_front.png"); // Z-
|
||||
f->setInventoryTexture("chest_top.png");
|
||||
//f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
if(f->initial_metadata == NULL)
|
||||
f->initial_metadata = new ChestNodeMetadata();
|
||||
|
||||
i = CONTENT_FURNACE;
|
||||
f = &g_content_features[i];
|
||||
f->param_type = CPT_FACEDIR_SIMPLE;
|
||||
f->setAllTextures("furnace_side.png");
|
||||
f->setTexture(5, "furnace_front.png"); // Z-
|
||||
f->setInventoryTexture("furnace_front.png");
|
||||
//f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 6";
|
||||
if(f->initial_metadata == NULL)
|
||||
f->initial_metadata = new FurnaceNodeMetadata();
|
||||
|
||||
i = CONTENT_COBBLE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("cobble.png");
|
||||
f->setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png");
|
||||
f->param_type = CPT_NONE;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
i = CONTENT_STEEL;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures("steel_block.png");
|
||||
f->setInventoryTextureCube("steel_block.png", "steel_block.png",
|
||||
"steel_block.png");
|
||||
f->param_type = CPT_NONE;
|
||||
f->is_ground_content = true;
|
||||
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
|
||||
|
||||
// NOTE: Remember to add frequently used stuff to the texture atlas in tile.cpp
|
||||
}
|
||||
|
||||
v3s16 facedir_rotate(u8 facedir, v3s16 dir)
|
||||
@ -525,16 +230,54 @@ u8 MapNode::getMineral()
|
||||
return MINERAL_NONE;
|
||||
}
|
||||
|
||||
// Pointers to c_str()s g_content_features[i].inventory_image_path
|
||||
//const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT] = {0};
|
||||
/*
|
||||
Gets lighting value at face of node
|
||||
|
||||
Parameters must consist of air and !air.
|
||||
Order doesn't matter.
|
||||
|
||||
void init_content_inventory_texture_paths()
|
||||
If either of the nodes doesn't exist, light is 0.
|
||||
|
||||
parameters:
|
||||
daynight_ratio: 0...1000
|
||||
n: getNodeParent(p)
|
||||
n2: getNodeParent(p + face_dir)
|
||||
face_dir: axis oriented unit vector from p to p2
|
||||
|
||||
returns encoded light value.
|
||||
*/
|
||||
u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
|
||||
v3s16 face_dir)
|
||||
{
|
||||
dstream<<"DEPRECATED "<<__FUNCTION_NAME<<std::endl;
|
||||
/*for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
|
||||
try{
|
||||
u8 light;
|
||||
u8 l1 = n.getLightBlend(daynight_ratio);
|
||||
u8 l2 = n2.getLightBlend(daynight_ratio);
|
||||
if(l1 > l2)
|
||||
light = l1;
|
||||
else
|
||||
light = l2;
|
||||
|
||||
// Make some nice difference to different sides
|
||||
|
||||
// This makes light come from a corner
|
||||
/*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
|
||||
light = diminish_light(diminish_light(light));
|
||||
else if(face_dir.X == -1 || face_dir.Z == -1)
|
||||
light = diminish_light(light);*/
|
||||
|
||||
// All neighboring faces have different shade (like in minecraft)
|
||||
if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
|
||||
light = diminish_light(diminish_light(light));
|
||||
else if(face_dir.Z == 1 || face_dir.Z == -1)
|
||||
light = diminish_light(light);
|
||||
|
||||
return light;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
g_content_inventory_texture_paths[i] =
|
||||
g_content_features[i].inventory_image_path.c_str();
|
||||
}*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
181
src/mapnode.h
181
src/mapnode.h
@ -27,6 +27,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "exceptions.h"
|
||||
#include "serialization.h"
|
||||
#include "tile.h"
|
||||
#include "materials.h"
|
||||
|
||||
/*
|
||||
Naming scheme:
|
||||
- Material = irrlicht's Material class
|
||||
- Content = (u8) content of a node
|
||||
- Tile = TileSpec at some side of a node of some content type
|
||||
*/
|
||||
|
||||
/*
|
||||
Initializes all kind of stuff in here.
|
||||
@ -42,13 +50,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
void init_mapnode();
|
||||
|
||||
// Initializes g_content_inventory_texture_paths
|
||||
void init_content_inventory_texture_paths();
|
||||
|
||||
|
||||
// NOTE: This is not used appropriately everywhere.
|
||||
#define MATERIALS_COUNT 256
|
||||
|
||||
/*
|
||||
Ignored node.
|
||||
|
||||
@ -67,48 +68,6 @@ void init_content_inventory_texture_paths();
|
||||
*/
|
||||
#define CONTENT_AIR 254
|
||||
|
||||
/*
|
||||
Suggested materials:
|
||||
- Gravel
|
||||
- Sand
|
||||
|
||||
New naming scheme:
|
||||
- Material = irrlicht's Material class
|
||||
- Content = (u8) content of a node
|
||||
- Tile = (u16) Material ID at some side of a node
|
||||
*/
|
||||
|
||||
#define CONTENT_STONE 0
|
||||
#define CONTENT_GRASS 1
|
||||
#define CONTENT_WATER 2
|
||||
#define CONTENT_TORCH 3
|
||||
#define CONTENT_TREE 4
|
||||
#define CONTENT_LEAVES 5
|
||||
#define CONTENT_GRASS_FOOTSTEPS 6
|
||||
#define CONTENT_MESE 7
|
||||
#define CONTENT_MUD 8
|
||||
#define CONTENT_WATERSOURCE 9
|
||||
// Pretty much useless, clouds won't be drawn this way
|
||||
#define CONTENT_CLOUD 10
|
||||
#define CONTENT_COALSTONE 11
|
||||
#define CONTENT_WOOD 12
|
||||
#define CONTENT_SAND 13
|
||||
#define CONTENT_SIGN_WALL 14
|
||||
#define CONTENT_CHEST 15
|
||||
#define CONTENT_FURNACE 16
|
||||
//#define CONTENT_WORKBENCH 17
|
||||
#define CONTENT_COBBLE 18
|
||||
#define CONTENT_STEEL 19
|
||||
#define CONTENT_GLASS 20
|
||||
#define CONTENT_FENCE 21
|
||||
#define CONTENT_SANDSTONE 22
|
||||
#define CONTENT_CACTUS 23
|
||||
#define CONTENT_BRICK 24
|
||||
#define CONTENT_CLAY 25
|
||||
#define CONTENT_PAPYRUS 26
|
||||
#define CONTENT_BOOKSHELF 27
|
||||
#define CONTENT_RAIL 28
|
||||
|
||||
/*
|
||||
Content feature list
|
||||
*/
|
||||
@ -180,10 +139,20 @@ struct ContentFeatures
|
||||
|
||||
// Initial metadata is cloned from this
|
||||
NodeMetadata *initial_metadata;
|
||||
|
||||
// If the content is liquid, this is the flowing version of the liquid.
|
||||
// If content is liquid, this is the same content.
|
||||
u8 liquid_alternative_flowing;
|
||||
|
||||
// Amount of light the node emits
|
||||
u8 light_source;
|
||||
|
||||
// Digging properties for different tools
|
||||
DiggingPropertiesList digging_properties;
|
||||
|
||||
// NOTE: Move relevant properties to here from elsewhere
|
||||
|
||||
//TODO: Move more properties here
|
||||
|
||||
ContentFeatures()
|
||||
void reset()
|
||||
{
|
||||
translate_to = NULL;
|
||||
param_type = CPT_NONE;
|
||||
@ -201,6 +170,14 @@ struct ContentFeatures
|
||||
air_equivalent = false;
|
||||
dug_item = "";
|
||||
initial_metadata = NULL;
|
||||
liquid_alternative_flowing = CONTENT_IGNORE;
|
||||
light_source = 0;
|
||||
digging_properties.clear();
|
||||
}
|
||||
|
||||
ContentFeatures()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
~ContentFeatures();
|
||||
@ -242,6 +219,11 @@ struct ContentFeatures
|
||||
*/
|
||||
ContentFeatures & content_features(u8 i);
|
||||
|
||||
|
||||
/*
|
||||
Here is a bunch of DEPRECATED functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
If true, the material allows light propagation and brightness is stored
|
||||
in param.
|
||||
@ -250,9 +232,7 @@ ContentFeatures & content_features(u8 i);
|
||||
inline bool light_propagates_content(u8 m)
|
||||
{
|
||||
return content_features(m).light_propagates;
|
||||
//return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
/*
|
||||
If true, the material allows lossless sunlight propagation.
|
||||
NOTE: It doesn't seem to go through torches regardlessly of this
|
||||
@ -261,9 +241,7 @@ inline bool light_propagates_content(u8 m)
|
||||
inline bool sunlight_propagates_content(u8 m)
|
||||
{
|
||||
return content_features(m).sunlight_propagates;
|
||||
//return (m == CONTENT_AIR || m == CONTENT_TORCH);
|
||||
}
|
||||
|
||||
/*
|
||||
On a node-node surface, the material of the node with higher solidness
|
||||
is used for drawing.
|
||||
@ -275,83 +253,54 @@ inline bool sunlight_propagates_content(u8 m)
|
||||
inline u8 content_solidness(u8 m)
|
||||
{
|
||||
return content_features(m).solidness;
|
||||
/*// As of now, every pseudo node like torches are added to this
|
||||
if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
|
||||
return 0;
|
||||
if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
|
||||
return 1;
|
||||
return 2;*/
|
||||
}
|
||||
|
||||
// Objects collide with walkable contents
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_walkable(u8 m)
|
||||
{
|
||||
return content_features(m).walkable;
|
||||
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
|
||||
}
|
||||
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_liquid(u8 m)
|
||||
{
|
||||
return content_features(m).liquid_type != LIQUID_NONE;
|
||||
//return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_flowing_liquid(u8 m)
|
||||
{
|
||||
return content_features(m).liquid_type == LIQUID_FLOWING;
|
||||
//return (m == CONTENT_WATER);
|
||||
}
|
||||
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_liquid_source(u8 m)
|
||||
{
|
||||
return content_features(m).liquid_type == LIQUID_SOURCE;
|
||||
//return (m == CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
// CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
|
||||
// CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline u8 make_liquid_flowing(u8 m)
|
||||
{
|
||||
if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
|
||||
return CONTENT_WATER;
|
||||
assert(0);
|
||||
u8 c = content_features(m).liquid_alternative_flowing;
|
||||
assert(c != CONTENT_IGNORE);
|
||||
return c;
|
||||
}
|
||||
|
||||
// Pointable contents can be pointed to in the map
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_pointable(u8 m)
|
||||
{
|
||||
return content_features(m).pointable;
|
||||
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_diggable(u8 m)
|
||||
{
|
||||
return content_features(m).diggable;
|
||||
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
inline bool content_buildable_to(u8 m)
|
||||
{
|
||||
return content_features(m).buildable_to;
|
||||
//return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true for contents that form the base ground that
|
||||
follows the main heightmap
|
||||
*/
|
||||
/*inline bool is_ground_content(u8 m)
|
||||
{
|
||||
return content_features(m).is_ground_content;
|
||||
}*/
|
||||
|
||||
/*
|
||||
Nodes make a face if contents differ and solidness differs.
|
||||
Return value:
|
||||
@ -500,31 +449,25 @@ struct MapNode
|
||||
&& param == other.param
|
||||
&& param2 == other.param2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
These four are DEPRECATED I guess. -c55
|
||||
*/
|
||||
bool light_propagates()
|
||||
{
|
||||
return light_propagates_content(d);
|
||||
}
|
||||
|
||||
bool sunlight_propagates()
|
||||
{
|
||||
return sunlight_propagates_content(d);
|
||||
}
|
||||
|
||||
u8 solidness()
|
||||
{
|
||||
return content_solidness(d);
|
||||
}
|
||||
|
||||
u8 light_source()
|
||||
{
|
||||
/*
|
||||
Note that a block that isn't light_propagates() can be a light source.
|
||||
*/
|
||||
if(d == CONTENT_TORCH)
|
||||
return LIGHT_MAX;
|
||||
|
||||
return 0;
|
||||
return content_features(d).light_source;
|
||||
}
|
||||
|
||||
u8 getLightBanksWithSource()
|
||||
@ -544,11 +487,6 @@ struct MapNode
|
||||
return (lightday&0x0f) | ((lightnight<<4)&0xf0);
|
||||
}
|
||||
|
||||
void setLightBanks(u8 a_light)
|
||||
{
|
||||
param = a_light;
|
||||
}
|
||||
|
||||
u8 getLight(enum LightBank bank)
|
||||
{
|
||||
// Select the brightest of [light source, propagated light]
|
||||
@ -613,13 +551,25 @@ struct MapNode
|
||||
}
|
||||
|
||||
// In mapnode.cpp
|
||||
/*
|
||||
Get tile of a face of the node.
|
||||
dir: direction of face
|
||||
Returns: TileSpec. Can contain miscellaneous texture coordinates,
|
||||
which must be obeyed so that the texture atlas can be used.
|
||||
*/
|
||||
TileSpec getTile(v3s16 dir);
|
||||
|
||||
|
||||
/*
|
||||
Gets mineral content of node, if there is any.
|
||||
MINERAL_NONE if doesn't contain or isn't able to contain mineral.
|
||||
*/
|
||||
u8 getMineral();
|
||||
|
||||
/*
|
||||
These serialization functions are used when informing client
|
||||
of a single node add
|
||||
of a single node add.
|
||||
|
||||
NOTE: When loading a MapBlock, these are not used. Should they?
|
||||
*/
|
||||
|
||||
static u32 serializedLength(u8 version)
|
||||
@ -698,7 +648,24 @@ struct MapNode
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Gets lighting value at face of node
|
||||
|
||||
Parameters must consist of air and !air.
|
||||
Order doesn't matter.
|
||||
|
||||
If either of the nodes doesn't exist, light is 0.
|
||||
|
||||
parameters:
|
||||
daynight_ratio: 0...1000
|
||||
n: getNodeParent(p)
|
||||
n2: getNodeParent(p + face_dir)
|
||||
face_dir: axis oriented unit vector from p to p2
|
||||
|
||||
returns encoded light value.
|
||||
*/
|
||||
u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
|
||||
v3s16 face_dir);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
MapSector::MapSector(NodeContainer *parent, v2s16 pos):
|
||||
differs_from_disk(true),
|
||||
usage_timer(0.0),
|
||||
m_parent(parent),
|
||||
m_pos(pos),
|
||||
m_block_cache(NULL)
|
||||
|
@ -203,13 +203,6 @@ public:
|
||||
// Basically, this should be changed to true in every setter method
|
||||
bool differs_from_disk;
|
||||
|
||||
// Counts seconds from last usage.
|
||||
// Sector can be deleted from memory after some time of inactivity.
|
||||
// NOTE: It has to be made very sure no other thread is accessing
|
||||
// the sector and it doesn't remain in any cache when
|
||||
// deleting it.
|
||||
float usage_timer;
|
||||
|
||||
protected:
|
||||
|
||||
// The pile of MapBlocks
|
||||
|
@ -1,119 +1,20 @@
|
||||
#include "materials.h"
|
||||
#include "mapnode.h"
|
||||
|
||||
#define MATERIAL_PROPERTIES_COUNT 256
|
||||
// NOTE: DEPRECATED
|
||||
|
||||
// These correspond to the CONTENT_* constants
|
||||
MaterialProperties g_material_properties[MATERIAL_PROPERTIES_COUNT];
|
||||
|
||||
bool g_material_properties_initialized = false;
|
||||
|
||||
void setStoneLikeDiggingProperties(u8 material, float toughness)
|
||||
DiggingPropertiesList * getDiggingPropertiesList(u8 content)
|
||||
{
|
||||
g_material_properties[material].setDiggingProperties("",
|
||||
DiggingProperties(true, 15.0*toughness, 0));
|
||||
|
||||
g_material_properties[material].setDiggingProperties("WPick",
|
||||
DiggingProperties(true, 1.3*toughness, 65535./30.*toughness));
|
||||
g_material_properties[material].setDiggingProperties("STPick",
|
||||
DiggingProperties(true, 0.75*toughness, 65535./100.*toughness));
|
||||
g_material_properties[material].setDiggingProperties("SteelPick",
|
||||
DiggingProperties(true, 0.50*toughness, 65535./333.*toughness));
|
||||
|
||||
/*g_material_properties[material].setDiggingProperties("MesePick",
|
||||
DiggingProperties(true, 0.0*toughness, 65535./20.*toughness));*/
|
||||
return &content_features(content).digging_properties;
|
||||
}
|
||||
|
||||
void setDirtLikeDiggingProperties(u8 material, float toughness)
|
||||
DiggingProperties getDiggingProperties(u8 content, const std::string &tool)
|
||||
{
|
||||
g_material_properties[material].setDiggingProperties("",
|
||||
DiggingProperties(true, 0.75*toughness, 0));
|
||||
|
||||
g_material_properties[material].setDiggingProperties("WShovel",
|
||||
DiggingProperties(true, 0.4*toughness, 65535./50.*toughness));
|
||||
g_material_properties[material].setDiggingProperties("STShovel",
|
||||
DiggingProperties(true, 0.2*toughness, 65535./150.*toughness));
|
||||
g_material_properties[material].setDiggingProperties("SteelShovel",
|
||||
DiggingProperties(true, 0.15*toughness, 65535./400.*toughness));
|
||||
}
|
||||
|
||||
void setWoodLikeDiggingProperties(u8 material, float toughness)
|
||||
{
|
||||
g_material_properties[material].setDiggingProperties("",
|
||||
DiggingProperties(true, 3.0*toughness, 0));
|
||||
|
||||
g_material_properties[material].setDiggingProperties("WAxe",
|
||||
DiggingProperties(true, 1.5*toughness, 65535./30.*toughness));
|
||||
g_material_properties[material].setDiggingProperties("STAxe",
|
||||
DiggingProperties(true, 0.75*toughness, 65535./100.*toughness));
|
||||
g_material_properties[material].setDiggingProperties("SteelAxe",
|
||||
DiggingProperties(true, 0.5*toughness, 65535./333.*toughness));
|
||||
}
|
||||
|
||||
void initializeMaterialProperties()
|
||||
{
|
||||
/*
|
||||
Now, the g_material_properties array is already initialized
|
||||
by the constructors to such that no digging is possible.
|
||||
|
||||
Add some digging properties to them.
|
||||
*/
|
||||
|
||||
setStoneLikeDiggingProperties(CONTENT_STONE, 1.0);
|
||||
setStoneLikeDiggingProperties(CONTENT_SANDSTONE, 1.0);
|
||||
setStoneLikeDiggingProperties(CONTENT_BRICK, 3.0);
|
||||
setStoneLikeDiggingProperties(CONTENT_MESE, 0.5);
|
||||
setStoneLikeDiggingProperties(CONTENT_COALSTONE, 1.5);
|
||||
setStoneLikeDiggingProperties(CONTENT_FURNACE, 3.0);
|
||||
setStoneLikeDiggingProperties(CONTENT_COBBLE, 1.0);
|
||||
setStoneLikeDiggingProperties(CONTENT_STEEL, 5.0);
|
||||
|
||||
setDirtLikeDiggingProperties(CONTENT_MUD, 1.0);
|
||||
setDirtLikeDiggingProperties(CONTENT_GRASS, 1.0);
|
||||
setDirtLikeDiggingProperties(CONTENT_GRASS_FOOTSTEPS, 1.0);
|
||||
setDirtLikeDiggingProperties(CONTENT_SAND, 1.0);
|
||||
setDirtLikeDiggingProperties(CONTENT_CLAY, 1.0);
|
||||
|
||||
setWoodLikeDiggingProperties(CONTENT_TREE, 1.0);
|
||||
setWoodLikeDiggingProperties(CONTENT_LEAVES, 0.15);
|
||||
setWoodLikeDiggingProperties(CONTENT_CACTUS, 0.75);
|
||||
setWoodLikeDiggingProperties(CONTENT_PAPYRUS, 0.25);
|
||||
setWoodLikeDiggingProperties(CONTENT_GLASS, 0.15);
|
||||
setWoodLikeDiggingProperties(CONTENT_FENCE, 0.75);
|
||||
setDirtLikeDiggingProperties(CONTENT_RAIL, 0.75);
|
||||
setWoodLikeDiggingProperties(CONTENT_WOOD, 0.75);
|
||||
setWoodLikeDiggingProperties(CONTENT_BOOKSHELF, 0.75);
|
||||
setWoodLikeDiggingProperties(CONTENT_CHEST, 1.0);
|
||||
|
||||
g_material_properties[CONTENT_SIGN_WALL].setDiggingProperties("",
|
||||
DiggingProperties(true, 0.5, 0));
|
||||
g_material_properties[CONTENT_TORCH].setDiggingProperties("",
|
||||
DiggingProperties(true, 0.0, 0));
|
||||
|
||||
/*
|
||||
Add MesePick to everything
|
||||
*/
|
||||
for(u16 i=0; i<MATERIAL_PROPERTIES_COUNT; i++)
|
||||
{
|
||||
g_material_properties[i].setDiggingProperties("MesePick",
|
||||
DiggingProperties(true, 0.0, 65535./1337));
|
||||
}
|
||||
|
||||
g_material_properties_initialized = true;
|
||||
}
|
||||
|
||||
MaterialProperties * getMaterialProperties(u8 material)
|
||||
{
|
||||
assert(g_material_properties_initialized);
|
||||
return &g_material_properties[material];
|
||||
}
|
||||
|
||||
DiggingProperties getDiggingProperties(u8 material, const std::string &tool)
|
||||
{
|
||||
MaterialProperties *mprop = getMaterialProperties(material);
|
||||
DiggingPropertiesList *mprop = getDiggingPropertiesList(content);
|
||||
if(mprop == NULL)
|
||||
// Not diggable
|
||||
return DiggingProperties();
|
||||
|
||||
return mprop->getDiggingProperties(tool);
|
||||
return mprop->get(tool);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "inventory.h"
|
||||
#include <string>
|
||||
|
||||
struct DiggingProperties
|
||||
@ -49,20 +48,26 @@ struct DiggingProperties
|
||||
u16 wear;
|
||||
};
|
||||
|
||||
class MaterialProperties
|
||||
/*
|
||||
This is a bad way of determining mining characteristics.
|
||||
TODO: Get rid of this and set up some attributes like toughness,
|
||||
fluffyness, and a funciton to calculate time and durability loss
|
||||
(and sound? and whatever else) from them
|
||||
*/
|
||||
class DiggingPropertiesList
|
||||
{
|
||||
public:
|
||||
MaterialProperties()
|
||||
DiggingPropertiesList()
|
||||
{
|
||||
}
|
||||
|
||||
void setDiggingProperties(const std::string toolname,
|
||||
void set(const std::string toolname,
|
||||
const DiggingProperties &prop)
|
||||
{
|
||||
m_digging_properties[toolname] = prop;
|
||||
}
|
||||
|
||||
DiggingProperties getDiggingProperties(const std::string toolname)
|
||||
DiggingProperties get(const std::string toolname)
|
||||
{
|
||||
core::map<std::string, DiggingProperties>::Node *n;
|
||||
n = m_digging_properties.find(toolname);
|
||||
@ -80,16 +85,17 @@ public:
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_digging_properties.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
// toolname="": default properties (digging by hand)
|
||||
// Key is toolname
|
||||
core::map<std::string, DiggingProperties> m_digging_properties;
|
||||
};
|
||||
|
||||
void initializeMaterialProperties();
|
||||
|
||||
// Material correspond to the CONTENT_* constants
|
||||
MaterialProperties * getMaterialProperties(u8 material);
|
||||
// For getting the default properties, set tool=""
|
||||
DiggingProperties getDiggingProperties(u8 material, const std::string &tool);
|
||||
|
||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "exceptions.h"
|
||||
#include "inventory.h"
|
||||
#include <sstream>
|
||||
#include "content_mapnode.h"
|
||||
|
||||
/*
|
||||
NodeMetadata
|
||||
@ -96,268 +97,7 @@ void NodeMetadata::registerType(u16 id, Factory f)
|
||||
}
|
||||
|
||||
/*
|
||||
SignNodeMetadata
|
||||
*/
|
||||
|
||||
// Prototype
|
||||
SignNodeMetadata proto_SignNodeMetadata("");
|
||||
|
||||
SignNodeMetadata::SignNodeMetadata(std::string text):
|
||||
m_text(text)
|
||||
{
|
||||
NodeMetadata::registerType(typeId(), create);
|
||||
}
|
||||
u16 SignNodeMetadata::typeId() const
|
||||
{
|
||||
return CONTENT_SIGN_WALL;
|
||||
}
|
||||
NodeMetadata* SignNodeMetadata::create(std::istream &is)
|
||||
{
|
||||
std::string text = deSerializeString(is);
|
||||
return new SignNodeMetadata(text);
|
||||
}
|
||||
NodeMetadata* SignNodeMetadata::clone()
|
||||
{
|
||||
return new SignNodeMetadata(m_text);
|
||||
}
|
||||
void SignNodeMetadata::serializeBody(std::ostream &os)
|
||||
{
|
||||
os<<serializeString(m_text);
|
||||
}
|
||||
std::string SignNodeMetadata::infoText()
|
||||
{
|
||||
return std::string("\"")+m_text+"\"";
|
||||
}
|
||||
|
||||
/*
|
||||
ChestNodeMetadata
|
||||
*/
|
||||
|
||||
// Prototype
|
||||
ChestNodeMetadata proto_ChestNodeMetadata;
|
||||
|
||||
ChestNodeMetadata::ChestNodeMetadata()
|
||||
{
|
||||
NodeMetadata::registerType(typeId(), create);
|
||||
|
||||
m_inventory = new Inventory();
|
||||
m_inventory->addList("0", 8*4);
|
||||
}
|
||||
ChestNodeMetadata::~ChestNodeMetadata()
|
||||
{
|
||||
delete m_inventory;
|
||||
}
|
||||
u16 ChestNodeMetadata::typeId() const
|
||||
{
|
||||
return CONTENT_CHEST;
|
||||
}
|
||||
NodeMetadata* ChestNodeMetadata::create(std::istream &is)
|
||||
{
|
||||
ChestNodeMetadata *d = new ChestNodeMetadata();
|
||||
d->m_inventory->deSerialize(is);
|
||||
return d;
|
||||
}
|
||||
NodeMetadata* ChestNodeMetadata::clone()
|
||||
{
|
||||
ChestNodeMetadata *d = new ChestNodeMetadata();
|
||||
*d->m_inventory = *m_inventory;
|
||||
return d;
|
||||
}
|
||||
void ChestNodeMetadata::serializeBody(std::ostream &os)
|
||||
{
|
||||
m_inventory->serialize(os);
|
||||
}
|
||||
std::string ChestNodeMetadata::infoText()
|
||||
{
|
||||
return "Chest";
|
||||
}
|
||||
bool ChestNodeMetadata::nodeRemovalDisabled()
|
||||
{
|
||||
/*
|
||||
Disable removal if chest contains something
|
||||
*/
|
||||
InventoryList *list = m_inventory->getList("0");
|
||||
if(list == NULL)
|
||||
return false;
|
||||
if(list->getUsedSlots() == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
FurnaceNodeMetadata
|
||||
*/
|
||||
|
||||
// Prototype
|
||||
FurnaceNodeMetadata proto_FurnaceNodeMetadata;
|
||||
|
||||
FurnaceNodeMetadata::FurnaceNodeMetadata()
|
||||
{
|
||||
NodeMetadata::registerType(typeId(), create);
|
||||
|
||||
m_inventory = new Inventory();
|
||||
m_inventory->addList("fuel", 1);
|
||||
m_inventory->addList("src", 1);
|
||||
m_inventory->addList("dst", 4);
|
||||
|
||||
m_step_accumulator = 0;
|
||||
m_fuel_totaltime = 0;
|
||||
m_fuel_time = 0;
|
||||
m_src_totaltime = 0;
|
||||
m_src_time = 0;
|
||||
}
|
||||
FurnaceNodeMetadata::~FurnaceNodeMetadata()
|
||||
{
|
||||
delete m_inventory;
|
||||
}
|
||||
u16 FurnaceNodeMetadata::typeId() const
|
||||
{
|
||||
return CONTENT_FURNACE;
|
||||
}
|
||||
NodeMetadata* FurnaceNodeMetadata::clone()
|
||||
{
|
||||
FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
|
||||
*d->m_inventory = *m_inventory;
|
||||
return d;
|
||||
}
|
||||
NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
|
||||
{
|
||||
FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
|
||||
|
||||
d->m_inventory->deSerialize(is);
|
||||
|
||||
int temp;
|
||||
is>>temp;
|
||||
d->m_fuel_totaltime = (float)temp/10;
|
||||
is>>temp;
|
||||
d->m_fuel_time = (float)temp/10;
|
||||
|
||||
return d;
|
||||
}
|
||||
void FurnaceNodeMetadata::serializeBody(std::ostream &os)
|
||||
{
|
||||
m_inventory->serialize(os);
|
||||
os<<itos(m_fuel_totaltime*10)<<" ";
|
||||
os<<itos(m_fuel_time*10)<<" ";
|
||||
}
|
||||
std::string FurnaceNodeMetadata::infoText()
|
||||
{
|
||||
//return "Furnace";
|
||||
if(m_fuel_time >= m_fuel_totaltime)
|
||||
{
|
||||
InventoryList *src_list = m_inventory->getList("src");
|
||||
assert(src_list);
|
||||
InventoryItem *src_item = src_list->getItem(0);
|
||||
|
||||
if(src_item)
|
||||
return "Furnace is out of fuel";
|
||||
else
|
||||
return "Furnace is inactive";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string s = "Furnace is active (";
|
||||
s += itos(m_fuel_time/m_fuel_totaltime*100);
|
||||
s += "%)";
|
||||
return s;
|
||||
}
|
||||
}
|
||||
void FurnaceNodeMetadata::inventoryModified()
|
||||
{
|
||||
dstream<<"Furnace inventory modification callback"<<std::endl;
|
||||
}
|
||||
bool FurnaceNodeMetadata::step(float dtime)
|
||||
{
|
||||
// Update at a fixed frequency
|
||||
const float interval = 0.5;
|
||||
m_step_accumulator += dtime;
|
||||
if(m_step_accumulator < interval)
|
||||
return false;
|
||||
m_step_accumulator -= interval;
|
||||
dtime = interval;
|
||||
|
||||
//dstream<<"Furnace step dtime="<<dtime<<std::endl;
|
||||
|
||||
InventoryList *dst_list = m_inventory->getList("dst");
|
||||
assert(dst_list);
|
||||
|
||||
InventoryList *src_list = m_inventory->getList("src");
|
||||
assert(src_list);
|
||||
InventoryItem *src_item = src_list->getItem(0);
|
||||
|
||||
// Start only if there are free slots in dst, so that it can
|
||||
// accomodate any result item
|
||||
if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable())
|
||||
{
|
||||
m_src_totaltime = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_src_time = 0;
|
||||
m_src_totaltime = 0;
|
||||
}
|
||||
|
||||
if(m_fuel_time < m_fuel_totaltime)
|
||||
{
|
||||
//dstream<<"Furnace is active"<<std::endl;
|
||||
m_fuel_time += dtime;
|
||||
m_src_time += dtime;
|
||||
if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
|
||||
&& src_item)
|
||||
{
|
||||
InventoryItem *cookresult = src_item->createCookResult();
|
||||
dst_list->addItem(cookresult);
|
||||
src_list->decrementMaterials(1);
|
||||
m_src_time = 0;
|
||||
m_src_totaltime = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(src_item == NULL || m_src_totaltime < 0.001)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
//dstream<<"Furnace is out of fuel"<<std::endl;
|
||||
|
||||
InventoryList *fuel_list = m_inventory->getList("fuel");
|
||||
assert(fuel_list);
|
||||
InventoryItem *fuel_item = fuel_list->getItem(0);
|
||||
|
||||
if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 10;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 5;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
|
||||
{
|
||||
m_fuel_totaltime = 10;
|
||||
m_fuel_time = 0;
|
||||
fuel_list->decrementMaterials(1);
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//dstream<<"No fuel found"<<std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*
|
||||
NodeMetadatalist
|
||||
NodeMetadataList
|
||||
*/
|
||||
|
||||
void NodeMetadataList::serialize(std::ostream &os)
|
||||
@ -484,19 +224,6 @@ bool NodeMetadataList::step(float dtime)
|
||||
bool changed = meta->step(dtime);
|
||||
if(changed)
|
||||
something_changed = true;
|
||||
/*if(res.inventory_changed)
|
||||
{
|
||||
std::string inv_id;
|
||||
inv_id += "nodemeta:";
|
||||
inv_id += itos(p.X);
|
||||
inv_id += ",";
|
||||
inv_id += itos(p.Y);
|
||||
inv_id += ",";
|
||||
inv_id += itos(p.Z);
|
||||
InventoryContext c;
|
||||
c.current_player = NULL;
|
||||
inv_mgr->inventoryModified(&c, inv_id);
|
||||
}*/
|
||||
}
|
||||
return something_changed;
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ public:
|
||||
// A step in time. Returns true if metadata changed.
|
||||
virtual bool step(float dtime) {return false;}
|
||||
virtual bool nodeRemovalDisabled(){return false;}
|
||||
// Used to make custom inventory menus.
|
||||
// See format in guiInventoryMenu.cpp.
|
||||
virtual std::string getInventoryDrawSpecString(){return "";}
|
||||
|
||||
protected:
|
||||
static void registerType(u16 id, Factory f);
|
||||
@ -69,74 +72,10 @@ private:
|
||||
static core::map<u16, Factory> m_types;
|
||||
};
|
||||
|
||||
class SignNodeMetadata : public NodeMetadata
|
||||
{
|
||||
public:
|
||||
SignNodeMetadata(std::string text);
|
||||
//~SignNodeMetadata();
|
||||
|
||||
virtual u16 typeId() const;
|
||||
static NodeMetadata* create(std::istream &is);
|
||||
virtual NodeMetadata* clone();
|
||||
virtual void serializeBody(std::ostream &os);
|
||||
virtual std::string infoText();
|
||||
|
||||
std::string getText(){ return m_text; }
|
||||
void setText(std::string t){ m_text = t; }
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
};
|
||||
|
||||
class ChestNodeMetadata : public NodeMetadata
|
||||
{
|
||||
public:
|
||||
ChestNodeMetadata();
|
||||
~ChestNodeMetadata();
|
||||
|
||||
virtual u16 typeId() const;
|
||||
static NodeMetadata* create(std::istream &is);
|
||||
virtual NodeMetadata* clone();
|
||||
virtual void serializeBody(std::ostream &os);
|
||||
virtual std::string infoText();
|
||||
virtual Inventory* getInventory() {return m_inventory;}
|
||||
|
||||
virtual bool nodeRemovalDisabled();
|
||||
|
||||
private:
|
||||
Inventory *m_inventory;
|
||||
};
|
||||
|
||||
class FurnaceNodeMetadata : public NodeMetadata
|
||||
{
|
||||
public:
|
||||
FurnaceNodeMetadata();
|
||||
~FurnaceNodeMetadata();
|
||||
|
||||
virtual u16 typeId() const;
|
||||
virtual NodeMetadata* clone();
|
||||
static NodeMetadata* create(std::istream &is);
|
||||
virtual void serializeBody(std::ostream &os);
|
||||
virtual std::string infoText();
|
||||
virtual Inventory* getInventory() {return m_inventory;}
|
||||
virtual void inventoryModified();
|
||||
virtual bool step(float dtime);
|
||||
|
||||
private:
|
||||
Inventory *m_inventory;
|
||||
float m_step_accumulator;
|
||||
float m_fuel_totaltime;
|
||||
float m_fuel_time;
|
||||
float m_src_totaltime;
|
||||
float m_src_time;
|
||||
};
|
||||
|
||||
/*
|
||||
List of metadata of all the nodes of a block
|
||||
*/
|
||||
|
||||
class InventoryManager;
|
||||
|
||||
class NodeMetadataList
|
||||
{
|
||||
public:
|
||||
|
111
src/noise.cpp
111
src/noise.cpp
@ -222,6 +222,49 @@ double noise3d_perlin_abs(double x, double y, double z, int seed,
|
||||
return a;
|
||||
}
|
||||
|
||||
// -1->0, 0->1, 1->0
|
||||
double contour(double v)
|
||||
{
|
||||
v = fabs(v);
|
||||
if(v >= 1.0)
|
||||
return 0.0;
|
||||
return (1.0-v);
|
||||
}
|
||||
|
||||
double noise3d_param(const NoiseParams ¶m, double x, double y, double z)
|
||||
{
|
||||
double s = param.pos_scale;
|
||||
x /= s;
|
||||
y /= s;
|
||||
z /= s;
|
||||
|
||||
if(param.type == NOISE_PERLIN)
|
||||
{
|
||||
return param.noise_scale*noise3d_perlin(x,y,z, param.seed,
|
||||
param.octaves,
|
||||
param.persistence);
|
||||
}
|
||||
else if(param.type == NOISE_PERLIN_ABS)
|
||||
{
|
||||
return param.noise_scale*noise3d_perlin_abs(x,y,z, param.seed,
|
||||
param.octaves,
|
||||
param.persistence);
|
||||
}
|
||||
else if(param.type == NOISE_PERLIN_CONTOUR)
|
||||
{
|
||||
return contour(param.noise_scale*noise3d_perlin(x,y,z,
|
||||
param.seed, param.octaves,
|
||||
param.persistence));
|
||||
}
|
||||
else if(param.type == NOISE_PERLIN_CONTOUR_FLIP_YZ)
|
||||
{
|
||||
return contour(param.noise_scale*noise3d_perlin(x,z,y,
|
||||
param.seed, param.octaves,
|
||||
param.persistence));
|
||||
}
|
||||
else assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
NoiseBuffer
|
||||
*/
|
||||
@ -246,8 +289,7 @@ void NoiseBuffer::clear()
|
||||
m_size_z = 0;
|
||||
}
|
||||
|
||||
void NoiseBuffer::create(int seed, int octaves, double persistence,
|
||||
double pos_scale,
|
||||
void NoiseBuffer::create(const NoiseParams ¶m,
|
||||
double first_x, double first_y, double first_z,
|
||||
double last_x, double last_y, double last_z,
|
||||
double samplelength_x, double samplelength_y, double samplelength_z)
|
||||
@ -265,22 +307,54 @@ void NoiseBuffer::create(int seed, int octaves, double persistence,
|
||||
m_size_y = (last_y - m_start_y)/samplelength_y + 2;
|
||||
m_size_z = (last_z - m_start_z)/samplelength_z + 2;
|
||||
|
||||
/*dstream<<"m_size_x="<<m_size_x<<", m_size_y="<<m_size_y
|
||||
<<", m_size_z="<<m_size_z<<std::endl;*/
|
||||
|
||||
m_data = new double[m_size_x*m_size_y*m_size_z];
|
||||
|
||||
for(int x=0; x<m_size_x; x++)
|
||||
for(int y=0; y<m_size_y; y++)
|
||||
for(int z=0; z<m_size_z; z++)
|
||||
{
|
||||
double xd = (m_start_x + (double)x*m_samplelength_x)/pos_scale;
|
||||
double yd = (m_start_y + (double)y*m_samplelength_y)/pos_scale;
|
||||
double zd = (m_start_z + (double)z*m_samplelength_z)/pos_scale;
|
||||
intSet(x,y,z, noise3d_perlin(xd,yd,zd,seed,octaves,persistence));
|
||||
double xd = (m_start_x + (double)x*m_samplelength_x);
|
||||
double yd = (m_start_y + (double)y*m_samplelength_y);
|
||||
double zd = (m_start_z + (double)z*m_samplelength_z);
|
||||
double a = noise3d_param(param, xd,yd,zd);
|
||||
intSet(x,y,z, a);
|
||||
}
|
||||
}
|
||||
|
||||
void NoiseBuffer::multiply(const NoiseParams ¶m)
|
||||
{
|
||||
assert(m_data != NULL);
|
||||
|
||||
for(int x=0; x<m_size_x; x++)
|
||||
for(int y=0; y<m_size_y; y++)
|
||||
for(int z=0; z<m_size_z; z++)
|
||||
{
|
||||
double xd = (m_start_x + (double)x*m_samplelength_x);
|
||||
double yd = (m_start_y + (double)y*m_samplelength_y);
|
||||
double zd = (m_start_z + (double)z*m_samplelength_z);
|
||||
double a = noise3d_param(param, xd,yd,zd);
|
||||
intMultiply(x,y,z, a);
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
void NoiseBuffer::create(int seed, int octaves, double persistence,
|
||||
bool abs,
|
||||
double first_x, double first_y, double first_z,
|
||||
double last_x, double last_y, double last_z,
|
||||
double samplelength_x, double samplelength_y, double samplelength_z)
|
||||
{
|
||||
NoiseParams param;
|
||||
param.type = abs ? NOISE_PERLIN_ABS : NOISE_PERLIN;
|
||||
param.seed = seed;
|
||||
param.octaves = octaves;
|
||||
param.persistence = persistence;
|
||||
|
||||
create(param, first_x, first_y, first_z,
|
||||
last_x, last_y, last_z,
|
||||
samplelength_x, samplelength_y, samplelength_z);
|
||||
}
|
||||
|
||||
void NoiseBuffer::intSet(int x, int y, int z, double d)
|
||||
{
|
||||
int i = m_size_x*m_size_y*z + m_size_x*y + x;
|
||||
@ -289,6 +363,14 @@ void NoiseBuffer::intSet(int x, int y, int z, double d)
|
||||
m_data[i] = d;
|
||||
}
|
||||
|
||||
void NoiseBuffer::intMultiply(int x, int y, int z, double d)
|
||||
{
|
||||
int i = m_size_x*m_size_y*z + m_size_x*y + x;
|
||||
assert(i >= 0);
|
||||
assert(i < m_size_x*m_size_y*m_size_z);
|
||||
m_data[i] = m_data[i] * d;
|
||||
}
|
||||
|
||||
double NoiseBuffer::intGet(int x, int y, int z)
|
||||
{
|
||||
int i = m_size_x*m_size_y*z + m_size_x*y + x;
|
||||
@ -326,3 +408,14 @@ double NoiseBuffer::get(double x, double y, double z)
|
||||
return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
|
||||
}
|
||||
|
||||
/*bool NoiseBuffer::contains(double x, double y, double z)
|
||||
{
|
||||
x -= m_start_x;
|
||||
y -= m_start_y;
|
||||
z -= m_start_z;
|
||||
x /= m_samplelength_x;
|
||||
y /= m_samplelength_y;
|
||||
z /= m_samplelength_z;
|
||||
if(x <= 0.0 || x >= m_size_x)
|
||||
}*/
|
||||
|
||||
|
81
src/noise.h
81
src/noise.h
@ -20,6 +20,45 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef NOISE_HEADER
|
||||
#define NOISE_HEADER
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
class PseudoRandom
|
||||
{
|
||||
public:
|
||||
PseudoRandom(): m_next(0)
|
||||
{
|
||||
}
|
||||
PseudoRandom(int seed): m_next(seed)
|
||||
{
|
||||
}
|
||||
void seed(int seed)
|
||||
{
|
||||
m_next = seed;
|
||||
}
|
||||
// Returns 0...32767
|
||||
int next()
|
||||
{
|
||||
m_next = m_next * 1103515245 + 12345;
|
||||
return((unsigned)(m_next/65536) % 32768);
|
||||
}
|
||||
int range(int min, int max)
|
||||
{
|
||||
if(max-min > 32768/10)
|
||||
{
|
||||
//dstream<<"WARNING: PseudoRandom::range: max > 32767"<<std::endl;
|
||||
assert(0);
|
||||
}
|
||||
if(min > max)
|
||||
{
|
||||
assert(0);
|
||||
return max;
|
||||
}
|
||||
return (next()%(max-min+1))+min;
|
||||
}
|
||||
private:
|
||||
int m_next;
|
||||
};
|
||||
|
||||
double easeCurve(double t);
|
||||
|
||||
// Return value: -1 ... 1
|
||||
@ -41,6 +80,38 @@ double noise3d_perlin(double x, double y, double z, int seed,
|
||||
double noise3d_perlin_abs(double x, double y, double z, int seed,
|
||||
int octaves, double persistence);
|
||||
|
||||
enum NoiseType
|
||||
{
|
||||
NOISE_PERLIN,
|
||||
NOISE_PERLIN_ABS,
|
||||
NOISE_PERLIN_CONTOUR,
|
||||
NOISE_PERLIN_CONTOUR_FLIP_YZ
|
||||
};
|
||||
|
||||
struct NoiseParams
|
||||
{
|
||||
NoiseType type;
|
||||
int seed;
|
||||
int octaves;
|
||||
double persistence;
|
||||
double pos_scale;
|
||||
double noise_scale; // Useful for contour noises
|
||||
|
||||
NoiseParams(NoiseType type_=NOISE_PERLIN, int seed_=0,
|
||||
int octaves_=3, double persistence_=0.5,
|
||||
double pos_scale_=100.0, double noise_scale_=1.0):
|
||||
type(type_),
|
||||
seed(seed_),
|
||||
octaves(octaves_),
|
||||
persistence(persistence_),
|
||||
pos_scale(pos_scale_),
|
||||
noise_scale(noise_scale_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
double noise3d_param(const NoiseParams ¶m, double x, double y, double z);
|
||||
|
||||
class NoiseBuffer
|
||||
{
|
||||
public:
|
||||
@ -48,15 +119,23 @@ public:
|
||||
~NoiseBuffer();
|
||||
|
||||
void clear();
|
||||
void create(const NoiseParams ¶m,
|
||||
double first_x, double first_y, double first_z,
|
||||
double last_x, double last_y, double last_z,
|
||||
double samplelength_x, double samplelength_y, double samplelength_z);
|
||||
void multiply(const NoiseParams ¶m);
|
||||
// Deprecated
|
||||
void create(int seed, int octaves, double persistence,
|
||||
double pos_scale,
|
||||
bool abs,
|
||||
double first_x, double first_y, double first_z,
|
||||
double last_x, double last_y, double last_z,
|
||||
double samplelength_x, double samplelength_y, double samplelength_z);
|
||||
|
||||
void intSet(int x, int y, int z, double d);
|
||||
void intMultiply(int x, int y, int z, double d);
|
||||
double intGet(int x, int y, int z);
|
||||
double get(double x, double y, double z);
|
||||
//bool contains(double x, double y, double z);
|
||||
|
||||
private:
|
||||
double *m_data;
|
||||
|
@ -23,58 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "constants.h"
|
||||
#include "utility.h"
|
||||
|
||||
// Convert a privileges value into a human-readable string,
|
||||
// with each component separated by a comma.
|
||||
std::wstring privsToString(u64 privs)
|
||||
{
|
||||
std::wostringstream os(std::ios_base::binary);
|
||||
if(privs & PRIV_BUILD)
|
||||
os<<L"build,";
|
||||
if(privs & PRIV_TELEPORT)
|
||||
os<<L"teleport,";
|
||||
if(privs & PRIV_SETTIME)
|
||||
os<<L"settime,";
|
||||
if(privs & PRIV_PRIVS)
|
||||
os<<L"privs,";
|
||||
if(privs & PRIV_SHOUT)
|
||||
os<<L"shout,";
|
||||
if(os.tellp())
|
||||
{
|
||||
// Drop the trailing comma. (Why on earth can't
|
||||
// you truncate a C++ stream anyway???)
|
||||
std::wstring tmp = os.str();
|
||||
return tmp.substr(0, tmp.length() -1);
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
// Converts a comma-seperated list of privilege values into a
|
||||
// privileges value. The reverse of privsToString(). Returns
|
||||
// PRIV_INVALID if there is anything wrong with the input.
|
||||
u64 stringToPrivs(std::wstring str)
|
||||
{
|
||||
u64 privs=0;
|
||||
std::vector<std::wstring> pr;
|
||||
pr=str_split(str, ',');
|
||||
for(std::vector<std::wstring>::iterator i = pr.begin();
|
||||
i != pr.end(); ++i)
|
||||
{
|
||||
if(*i == L"build")
|
||||
privs |= PRIV_BUILD;
|
||||
else if(*i == L"teleport")
|
||||
privs |= PRIV_TELEPORT;
|
||||
else if(*i == L"settime")
|
||||
privs |= PRIV_SETTIME;
|
||||
else if(*i == L"privs")
|
||||
privs |= PRIV_PRIVS;
|
||||
else if(*i == L"shout")
|
||||
privs |= PRIV_SHOUT;
|
||||
else
|
||||
return PRIV_INVALID;
|
||||
}
|
||||
return privs;
|
||||
}
|
||||
|
||||
|
||||
Player::Player():
|
||||
touching_ground(false),
|
||||
@ -83,7 +31,6 @@ Player::Player():
|
||||
swimming_up(false),
|
||||
craftresult_is_preview(true),
|
||||
hp(20),
|
||||
privs(PRIV_DEFAULT),
|
||||
peer_id(PEER_ID_INEXISTENT),
|
||||
m_pitch(0),
|
||||
m_yaw(0),
|
||||
@ -91,7 +38,6 @@ Player::Player():
|
||||
m_position(0,0,0)
|
||||
{
|
||||
updateName("<not set>");
|
||||
updatePassword("");
|
||||
resetInventory();
|
||||
}
|
||||
|
||||
@ -150,13 +96,12 @@ void Player::serialize(std::ostream &os)
|
||||
Settings args;
|
||||
args.setS32("version", 1);
|
||||
args.set("name", m_name);
|
||||
args.set("password", m_password);
|
||||
//args.set("password", m_password);
|
||||
args.setFloat("pitch", m_pitch);
|
||||
args.setFloat("yaw", m_yaw);
|
||||
args.setV3F("position", m_position);
|
||||
args.setBool("craftresult_is_preview", craftresult_is_preview);
|
||||
args.setS32("hp", hp);
|
||||
args.setU64("privs", privs);
|
||||
|
||||
args.writeLines(os);
|
||||
|
||||
@ -185,10 +130,10 @@ void Player::deSerialize(std::istream &is)
|
||||
//args.getS32("version");
|
||||
std::string name = args.get("name");
|
||||
updateName(name.c_str());
|
||||
std::string password = "";
|
||||
/*std::string password = "";
|
||||
if(args.exists("password"))
|
||||
password = args.get("password");
|
||||
updatePassword(password.c_str());
|
||||
updatePassword(password.c_str());*/
|
||||
m_pitch = args.getFloat("pitch");
|
||||
m_yaw = args.getFloat("yaw");
|
||||
m_position = args.getV3F("position");
|
||||
@ -202,7 +147,7 @@ void Player::deSerialize(std::istream &is)
|
||||
}catch(SettingNotFoundException &e){
|
||||
hp = 20;
|
||||
}
|
||||
try{
|
||||
/*try{
|
||||
std::string sprivs = args.get("privs");
|
||||
if(sprivs == "all")
|
||||
{
|
||||
@ -215,7 +160,7 @@ void Player::deSerialize(std::istream &is)
|
||||
}
|
||||
}catch(SettingNotFoundException &e){
|
||||
privs = PRIV_DEFAULT;
|
||||
}
|
||||
}*/
|
||||
|
||||
inventory.deSerialize(is);
|
||||
}
|
||||
|
47
src/player.h
47
src/player.h
@ -25,39 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "collision.h"
|
||||
|
||||
#define PLAYERNAME_SIZE 20
|
||||
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||
// base64-encoded SHA-1.
|
||||
|
||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
|
||||
|
||||
// Player privileges. These form a bitmask stored in the privs field
|
||||
// of the player, and define things they're allowed to do. See also
|
||||
// the static methods Player::privsToString and stringToPrivs that
|
||||
// convert these to human-readable form.
|
||||
const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world
|
||||
const u64 PRIV_TELEPORT = 2; // Can teleport
|
||||
const u64 PRIV_SETTIME = 4; // Can set the time
|
||||
const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges
|
||||
const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn
|
||||
// ,settings)
|
||||
const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all
|
||||
// players
|
||||
|
||||
// Default privileges - these can be overriden for new players using the
|
||||
// config option "default_privs" - however, this value still applies for
|
||||
// players that existed before the privileges system was added.
|
||||
const u64 PRIV_DEFAULT = PRIV_BUILD|PRIV_SHOUT;
|
||||
const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
|
||||
const u64 PRIV_INVALID = 0x8000000000000000ULL;
|
||||
|
||||
// Convert a privileges value into a human-readable string,
|
||||
// with each component separated by a comma.
|
||||
std::wstring privsToString(u64 privs);
|
||||
|
||||
// Converts a comma-seperated list of privilege values into a
|
||||
// privileges value. The reverse of privsToString(). Returns
|
||||
// PRIV_INVALID if there is anything wrong with the input.
|
||||
u64 stringToPrivs(std::wstring str);
|
||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
||||
|
||||
|
||||
class Map;
|
||||
@ -128,16 +97,6 @@ public:
|
||||
return m_name;
|
||||
}
|
||||
|
||||
virtual void updatePassword(const char *password)
|
||||
{
|
||||
snprintf(m_password, PASSWORD_SIZE, "%s", password);
|
||||
}
|
||||
|
||||
const char * getPassword()
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
virtual bool isLocal() const = 0;
|
||||
|
||||
virtual void updateLight(u8 light_at_pos) {};
|
||||
@ -167,14 +126,10 @@ public:
|
||||
|
||||
u16 hp;
|
||||
|
||||
// Player's privileges - a bitmaps of PRIV_xxxx.
|
||||
u64 privs;
|
||||
|
||||
u16 peer_id;
|
||||
|
||||
protected:
|
||||
char m_name[PLAYERNAME_SIZE];
|
||||
char m_password[PASSWORD_SIZE];
|
||||
f32 m_pitch;
|
||||
f32 m_yaw;
|
||||
v3f m_speed;
|
||||
|
@ -27,6 +27,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "CoreFoundation/CoreFoundation.h"
|
||||
#endif
|
||||
|
||||
namespace porting
|
||||
{
|
||||
|
||||
@ -215,9 +219,26 @@ void initializePaths()
|
||||
#elif defined(__APPLE__)
|
||||
#include <unistd.h>
|
||||
|
||||
// Code based on
|
||||
// http://stackoverflow.com/questions/516200/relative-paths-not-working-in-xcode-c
|
||||
CFBundleRef main_bundle = CFBundleGetMainBundle();
|
||||
CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(main_bundle);
|
||||
char path[PATH_MAX];
|
||||
if(CFURLGetFileSystemRepresentation(resources_url, TRUE, (UInt8 *)path, PATH_MAX))
|
||||
{
|
||||
dstream<<"Bundle resource path: "<<path<<std::endl;
|
||||
//chdir(path);
|
||||
path_data = std::string(path) + "/data";
|
||||
}
|
||||
else
|
||||
{
|
||||
// error!
|
||||
dstream<<"WARNING: Could not determine bundle resource path"<<std::endl;
|
||||
}
|
||||
CFRelease(resources_url);
|
||||
|
||||
path_userdata = std::string(getenv("HOME")) + "/Library/Application Support/" + APPNAME;
|
||||
path_data = std::string("minetest-mac.app/Contents/Resources/data/");
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif // RUN_IN_PLACE
|
||||
|
131
src/profiler.h
Normal file
131
src/profiler.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef PROFILER_HEADER
|
||||
#define PROFILER_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include <string>
|
||||
#include "utility.h"
|
||||
#include <jmutex.h>
|
||||
#include <jmutexautolock.h>
|
||||
|
||||
/*
|
||||
Time profiler
|
||||
*/
|
||||
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
Profiler()
|
||||
{
|
||||
m_mutex.Init();
|
||||
}
|
||||
|
||||
void add(const std::string &name, u32 duration)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
core::map<std::string, u32>::Node *n = m_data.find(name);
|
||||
if(n == NULL)
|
||||
{
|
||||
m_data[name] = duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->setValue(n->getValue()+duration);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
for(core::map<std::string, u32>::Iterator
|
||||
i = m_data.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
i.getNode()->setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
void print(std::ostream &o)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
for(core::map<std::string, u32>::Iterator
|
||||
i = m_data.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
std::string name = i.getNode()->getKey();
|
||||
o<<name<<": ";
|
||||
s32 clampsize = 40;
|
||||
s32 space = clampsize-name.size();
|
||||
for(s32 j=0; j<space; j++)
|
||||
{
|
||||
if(j%2 == 0 && j < space - 1)
|
||||
o<<"-";
|
||||
else
|
||||
o<<" ";
|
||||
}
|
||||
o<<i.getNode()->getValue();
|
||||
o<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
JMutex m_mutex;
|
||||
core::map<std::string, u32> m_data;
|
||||
};
|
||||
|
||||
class ScopeProfiler
|
||||
{
|
||||
public:
|
||||
ScopeProfiler(Profiler *profiler, const std::string &name):
|
||||
m_profiler(profiler),
|
||||
m_name(name),
|
||||
m_timer(NULL)
|
||||
{
|
||||
if(m_profiler)
|
||||
m_timer = new TimeTaker(m_name.c_str());
|
||||
}
|
||||
// name is copied
|
||||
ScopeProfiler(Profiler *profiler, const char *name):
|
||||
m_profiler(profiler),
|
||||
m_name(name),
|
||||
m_timer(NULL)
|
||||
{
|
||||
if(m_profiler)
|
||||
m_timer = new TimeTaker(m_name.c_str());
|
||||
}
|
||||
~ScopeProfiler()
|
||||
{
|
||||
if(m_timer)
|
||||
{
|
||||
u32 duration = m_timer->stop(true);
|
||||
if(m_profiler)
|
||||
m_profiler->add(m_name, duration);
|
||||
delete m_timer;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Profiler *m_profiler;
|
||||
std::string m_name;
|
||||
TimeTaker *m_timer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -128,7 +128,7 @@ void decompressZlib(std::istream &is, std::ostream &os)
|
||||
|
||||
ret = inflateInit(&z);
|
||||
if(ret != Z_OK)
|
||||
throw SerializationError("compressZlib: inflateInit failed");
|
||||
throw SerializationError("dcompressZlib: inflateInit failed");
|
||||
|
||||
z.avail_in = 0;
|
||||
|
||||
@ -162,7 +162,7 @@ void decompressZlib(std::istream &is, std::ostream &os)
|
||||
|| status == Z_MEM_ERROR)
|
||||
{
|
||||
zerr(status);
|
||||
throw SerializationError("compressZlib: inflate failed");
|
||||
throw SerializationError("decompressZlib: inflate failed");
|
||||
}
|
||||
int count = bufsize - z.avail_out;
|
||||
//dstream<<"count="<<count<<std::endl;
|
||||
@ -182,7 +182,7 @@ void decompressZlib(std::istream &is, std::ostream &os)
|
||||
{
|
||||
dstream<<"unget #"<<i<<" failed"<<std::endl;
|
||||
dstream<<"fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
|
||||
throw SerializationError("compressZlib: unget failed");
|
||||
throw SerializationError("decompressZlib: unget failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,11 +53,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
15: StaticObjects
|
||||
16: larger maximum size of node metadata, and compression
|
||||
17: MapBlocks contain timestamp
|
||||
18: sqlite/new generator/whatever
|
||||
*/
|
||||
// This represents an uninitialized or invalid format
|
||||
#define SER_FMT_VER_INVALID 255
|
||||
// Highest supported serialization version
|
||||
#define SER_FMT_VER_HIGHEST 17
|
||||
#define SER_FMT_VER_HIGHEST 18
|
||||
// Lowest supported serialization version
|
||||
#define SER_FMT_VER_LOWEST 0
|
||||
|
||||
|
1192
src/server.cpp
1192
src/server.cpp
File diff suppressed because it is too large
Load Diff
50
src/server.h
50
src/server.h
@ -17,10 +17,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
(c) 2010 Perttu Ahola <celeron55@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef SERVER_HEADER
|
||||
#define SERVER_HEADER
|
||||
|
||||
@ -32,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "porting.h"
|
||||
#include "map.h"
|
||||
#include "inventory.h"
|
||||
#include "auth.h"
|
||||
|
||||
/*
|
||||
Some random functions
|
||||
@ -423,7 +420,29 @@ public:
|
||||
|
||||
// Envlock and conlock should be locked when calling this
|
||||
void SendMovePlayer(Player *player);
|
||||
|
||||
u64 getPlayerAuthPrivs(const std::string &name)
|
||||
{
|
||||
try{
|
||||
return m_authmanager.getPrivs(name);
|
||||
}
|
||||
catch(AuthNotFoundException &e)
|
||||
{
|
||||
dstream<<"WARNING: Auth not found for "<<name<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setPlayerAuthPrivs(const std::string &name, u64 privs)
|
||||
{
|
||||
try{
|
||||
return m_authmanager.setPrivs(name, privs);
|
||||
}
|
||||
catch(AuthNotFoundException &e)
|
||||
{
|
||||
dstream<<"WARNING: Auth not found for "<<name<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@ -438,7 +457,8 @@ private:
|
||||
*/
|
||||
|
||||
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
|
||||
static void SendAccessDenied(con::Connection &con, u16 peer_id);
|
||||
static void SendAccessDenied(con::Connection &con, u16 peer_id,
|
||||
const std::wstring &reason);
|
||||
|
||||
/*
|
||||
Non-static send methods
|
||||
@ -456,15 +476,17 @@ private:
|
||||
Additionally, if far_players!=NULL, players further away than
|
||||
far_d_nodes are ignored and their peer_ids are added to far_players
|
||||
*/
|
||||
// Envlock and conlock should be locked when calling these
|
||||
void sendRemoveNode(v3s16 p, u16 ignore_id=0,
|
||||
core::list<u16> *far_players=NULL, float far_d_nodes=100);
|
||||
void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
|
||||
core::list<u16> *far_players=NULL, float far_d_nodes=100);
|
||||
void setBlockNotSent(v3s16 p);
|
||||
|
||||
// Environment and Connection must be locked when called
|
||||
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
|
||||
|
||||
// Sends blocks to clients
|
||||
// Sends blocks to clients (locks env and con on its own)
|
||||
void SendBlocks(float dtime);
|
||||
|
||||
/*
|
||||
@ -476,6 +498,15 @@ private:
|
||||
// When called, connection mutex should be locked
|
||||
RemoteClient* getClient(u16 peer_id);
|
||||
|
||||
// When called, environment mutex should be locked
|
||||
std::string getPlayerName(u16 peer_id)
|
||||
{
|
||||
Player *player = m_env.getPlayer(peer_id);
|
||||
if(player == NULL)
|
||||
return "[id="+itos(peer_id);
|
||||
return player->getName();
|
||||
}
|
||||
|
||||
/*
|
||||
Get a player from memory or creates one.
|
||||
If player is already connected, return NULL
|
||||
@ -491,6 +522,8 @@ private:
|
||||
void handlePeerChange(PeerChange &c);
|
||||
void handlePeerChanges();
|
||||
|
||||
u64 getPlayerPrivs(Player *player);
|
||||
|
||||
/*
|
||||
Variables
|
||||
*/
|
||||
@ -514,6 +547,9 @@ private:
|
||||
JMutex m_con_mutex;
|
||||
// Connected clients (behind the con mutex)
|
||||
core::map<u16, RemoteClient*> m_clients;
|
||||
|
||||
// User authentication
|
||||
AuthManager m_authmanager;
|
||||
|
||||
/*
|
||||
Threads
|
||||
@ -598,6 +634,8 @@ private:
|
||||
*/
|
||||
u16 m_ignore_map_edit_events_peer_id;
|
||||
|
||||
Profiler *m_profiler;
|
||||
|
||||
friend class EmergeThread;
|
||||
friend class RemoteClient;
|
||||
};
|
||||
|
@ -1,24 +1,21 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Part of Minetest-c55
|
||||
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "servercommand.h"
|
||||
#include "utility.h"
|
||||
|
||||
@ -35,7 +32,8 @@ void cmd_privs(std::wostringstream &os,
|
||||
{
|
||||
// Show our own real privs, without any adjustments
|
||||
// made for admin status
|
||||
os<<L"-!- " + privsToString(ctx->player->privs);
|
||||
os<<L"-!- " + narrow_to_wide(privsToString(
|
||||
ctx->server->getPlayerAuthPrivs(ctx->player->getName())));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -52,7 +50,7 @@ void cmd_privs(std::wostringstream &os,
|
||||
return;
|
||||
}
|
||||
|
||||
os<<L"-!- " + privsToString(tp->privs);
|
||||
os<<L"-!- " + narrow_to_wide(privsToString(ctx->server->getPlayerAuthPrivs(tp->getName())));
|
||||
}
|
||||
|
||||
void cmd_grantrevoke(std::wostringstream &os,
|
||||
@ -70,7 +68,7 @@ void cmd_grantrevoke(std::wostringstream &os,
|
||||
return;
|
||||
}
|
||||
|
||||
u64 newprivs = stringToPrivs(ctx->parms[2]);
|
||||
u64 newprivs = stringToPrivs(wide_to_narrow(ctx->parms[2]));
|
||||
if(newprivs == PRIV_INVALID)
|
||||
{
|
||||
os<<L"-!- Invalid privileges specified";
|
||||
@ -83,14 +81,19 @@ void cmd_grantrevoke(std::wostringstream &os,
|
||||
os<<L"-!- No such player";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string playername = wide_to_narrow(ctx->parms[1]);
|
||||
u64 privs = ctx->server->getPlayerAuthPrivs(playername);
|
||||
|
||||
if(ctx->parms[0] == L"grant")
|
||||
tp->privs |= newprivs;
|
||||
privs |= newprivs;
|
||||
else
|
||||
tp->privs &= ~newprivs;
|
||||
privs &= ~newprivs;
|
||||
|
||||
ctx->server->setPlayerAuthPrivs(playername, privs);
|
||||
|
||||
os<<L"-!- Privileges change to ";
|
||||
os<<privsToString(tp->privs);
|
||||
os<<narrow_to_wide(privsToString(privs));
|
||||
}
|
||||
|
||||
void cmd_time(std::wostringstream &os,
|
||||
|
@ -1,21 +1,19 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Part of Minetest-c55
|
||||
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SERVERCOMMAND_HEADER
|
||||
|
@ -69,6 +69,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "materials.h"
|
||||
#include "config.h"
|
||||
#include "mineral.h"
|
||||
#include "filesys.h"
|
||||
|
||||
/*
|
||||
Settings.
|
||||
@ -79,6 +80,9 @@ Settings g_settings;
|
||||
|
||||
extern void set_default_settings();
|
||||
|
||||
// Global profiler
|
||||
Profiler g_profiler;
|
||||
|
||||
// A dummy thing
|
||||
ITextureSource *g_texturesource = NULL;
|
||||
|
||||
@ -112,6 +116,15 @@ u32 getTimeMs()
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
Initialization
|
||||
*/
|
||||
|
||||
// Set locale. This is for forcing '.' as the decimal point.
|
||||
std::locale::global(std::locale("C"));
|
||||
// This enables printing all characters in bitmap font
|
||||
setlocale(LC_CTYPE, "en_US");
|
||||
|
||||
/*
|
||||
Low-level initialization
|
||||
*/
|
||||
@ -121,20 +134,31 @@ int main(int argc, char *argv[])
|
||||
disable_stderr = true;
|
||||
#endif
|
||||
|
||||
porting::signal_handler_init();
|
||||
bool &kill = *porting::signal_handler_killstatus();
|
||||
|
||||
// Initialize porting::path_data and porting::path_userdata
|
||||
porting::initializePaths();
|
||||
|
||||
// Create user data directory
|
||||
fs::CreateDir(porting::path_userdata);
|
||||
|
||||
// Initialize debug streams
|
||||
debugstreams_init(disable_stderr, DEBUGFILE);
|
||||
#ifdef RUN_IN_PLACE
|
||||
std::string debugfile = DEBUGFILE;
|
||||
#else
|
||||
std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;
|
||||
#endif
|
||||
debugstreams_init(disable_stderr, debugfile.c_str());
|
||||
// Initialize debug stacks
|
||||
debug_stacks_init();
|
||||
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
porting::signal_handler_init();
|
||||
bool &kill = *porting::signal_handler_killstatus();
|
||||
|
||||
porting::initializePaths();
|
||||
|
||||
initializeMaterialProperties();
|
||||
// Init material properties table
|
||||
//initializeMaterialProperties();
|
||||
|
||||
// Debug handler
|
||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||
|
||||
// Print startup message
|
||||
@ -199,19 +223,10 @@ int main(int argc, char *argv[])
|
||||
// Initialize default settings
|
||||
set_default_settings();
|
||||
|
||||
// Set locale. This is for forcing '.' as the decimal point.
|
||||
std::locale::global(std::locale("C"));
|
||||
// This enables printing all characters in bitmap font
|
||||
setlocale(LC_CTYPE, "en_US");
|
||||
|
||||
// Initialize sockets
|
||||
sockets_init();
|
||||
atexit(sockets_cleanup);
|
||||
|
||||
/*
|
||||
Initialization
|
||||
*/
|
||||
|
||||
/*
|
||||
Read config file
|
||||
*/
|
||||
@ -301,7 +316,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Figure out path to map
|
||||
std::string map_dir = porting::path_userdata+"/map";
|
||||
std::string map_dir = porting::path_userdata+"/world";
|
||||
if(cmd_args.exists("map-dir"))
|
||||
map_dir = cmd_args.get("map-dir");
|
||||
else if(g_settings.exists("map-dir"))
|
||||
|
16
src/sqlite/CMakeLists.txt
Normal file
16
src/sqlite/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
if( UNIX )
|
||||
set(sqlite3_SRCS sqlite3.c)
|
||||
set(sqlite3_platform_LIBS "")
|
||||
else( UNIX )
|
||||
set(sqlite3_SRCS sqlite3.c)
|
||||
set(sqlite3_platform_LIBS "")
|
||||
endif( UNIX )
|
||||
|
||||
add_library(sqlite3 ${sqlite3_SRCS})
|
||||
|
||||
target_link_libraries(
|
||||
sqlite3
|
||||
${sqlite3_platform_LIBS}
|
||||
)
|
||||
|
||||
|
125968
src/sqlite/sqlite3.c
Normal file
125968
src/sqlite/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
6464
src/sqlite/sqlite3.h
Normal file
6464
src/sqlite/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
16
src/test.cpp
16
src/test.cpp
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "voxel.h"
|
||||
#include <sstream>
|
||||
#include "porting.h"
|
||||
#include "content_mapnode.h"
|
||||
|
||||
/*
|
||||
Asserts that the exception occurs
|
||||
@ -424,16 +425,27 @@ struct TestMapBlock
|
||||
assert(b.getChangedFlag() == false);
|
||||
|
||||
// All nodes should have been set to
|
||||
// .d=CONTENT_AIR and .getLight() = 0
|
||||
// .d=CONTENT_IGNORE and .getLight() = 0
|
||||
for(u16 z=0; z<MAP_BLOCKSIZE; z++)
|
||||
for(u16 y=0; y<MAP_BLOCKSIZE; y++)
|
||||
for(u16 x=0; x<MAP_BLOCKSIZE; x++)
|
||||
{
|
||||
assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
|
||||
//assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
|
||||
assert(b.getNode(v3s16(x,y,z)).d == CONTENT_IGNORE);
|
||||
assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0);
|
||||
assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
MapNode n(CONTENT_AIR);
|
||||
for(u16 z=0; z<MAP_BLOCKSIZE; z++)
|
||||
for(u16 y=0; y<MAP_BLOCKSIZE; y++)
|
||||
for(u16 x=0; x<MAP_BLOCKSIZE; x++)
|
||||
{
|
||||
b.setNode(v3s16(x,y,z), n);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Parent fetch functions
|
||||
*/
|
||||
|
11
src/tile.cpp
11
src/tile.cpp
@ -506,22 +506,17 @@ void TextureSource::buildMainAtlas()
|
||||
sourcelist.push_back("stone.png");
|
||||
sourcelist.push_back("mud.png");
|
||||
sourcelist.push_back("sand.png");
|
||||
sourcelist.push_back("sandstone.png");
|
||||
sourcelist.push_back("clay.png");
|
||||
sourcelist.push_back("brick.png");
|
||||
sourcelist.push_back("grass.png");
|
||||
sourcelist.push_back("grass_footsteps.png");
|
||||
sourcelist.push_back("tree.png");
|
||||
sourcelist.push_back("tree_top.png");
|
||||
sourcelist.push_back("water.png");
|
||||
sourcelist.push_back("leaves.png");
|
||||
sourcelist.push_back("cactus_side.png");
|
||||
sourcelist.push_back("cactus_top.png");
|
||||
sourcelist.push_back("papyrus.png");
|
||||
sourcelist.push_back("bookshelf.png");
|
||||
sourcelist.push_back("glass.png");
|
||||
sourcelist.push_back("mud.png^grass_side.png");
|
||||
sourcelist.push_back("cobble.png");
|
||||
sourcelist.push_back("mossycobble.png");
|
||||
sourcelist.push_back("gravel.png");
|
||||
|
||||
sourcelist.push_back("stone.png^mineral_coal.png");
|
||||
sourcelist.push_back("stone.png^mineral_iron.png");
|
||||
@ -1092,7 +1087,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
imagename_right, device);
|
||||
assert(img_top && img_left && img_right);
|
||||
|
||||
// FIXME: Create textures from left and right images
|
||||
// TODO: Create textures from images
|
||||
video::ITexture *texture_top = driver->addTexture(
|
||||
(imagename_top + "__temp__").c_str(), img_top);
|
||||
assert(texture_top);
|
||||
|
@ -229,10 +229,10 @@ std::string translatePassword(std::string playername, std::wstring password)
|
||||
if(password.length() == 0)
|
||||
return "";
|
||||
|
||||
std::string slt=playername + wide_to_narrow(password);
|
||||
SHA1 *sha1 = new SHA1();
|
||||
sha1->addBytes(slt.c_str(), slt.length());
|
||||
unsigned char *digest = sha1->getDigest();
|
||||
std::string slt = playername + wide_to_narrow(password);
|
||||
SHA1 sha1;
|
||||
sha1.addBytes(slt.c_str(), slt.length());
|
||||
unsigned char *digest = sha1.getDigest();
|
||||
std::string pwd = base64_encode(digest, 20);
|
||||
free(digest);
|
||||
return pwd;
|
||||
|
@ -244,6 +244,9 @@ inline f32 readF1000(std::istream &is)
|
||||
{
|
||||
char buf[2];
|
||||
is.read(buf, 2);
|
||||
// TODO: verify if this gets rid of the valgrind warning
|
||||
//if(is.gcount() != 2)
|
||||
// return 0;
|
||||
return readF1000((u8*)buf);
|
||||
}
|
||||
|
||||
@ -1738,6 +1741,11 @@ void mysrand(unsigned seed);
|
||||
|
||||
inline int myrand_range(int min, int max)
|
||||
{
|
||||
if(max-min > MYRAND_MAX)
|
||||
{
|
||||
dstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl;
|
||||
assert(0);
|
||||
}
|
||||
if(min > max)
|
||||
{
|
||||
assert(0);
|
||||
@ -1984,17 +1992,23 @@ inline std::string serializeString(const std::string &plain)
|
||||
return s;
|
||||
}
|
||||
|
||||
/*// Reads a string with the length as the first two bytes
|
||||
inline std::string deSerializeString(const std::string encoded)
|
||||
// Creates a string with the length as the first two bytes from wide string
|
||||
inline std::string serializeWideString(const std::wstring &plain)
|
||||
{
|
||||
u16 s_size = readU16((u8*)&encoded.c_str()[0]);
|
||||
if(s_size > encoded.length() - 2)
|
||||
return "";
|
||||
//assert(plain.size() <= 65535);
|
||||
if(plain.size() > 65535)
|
||||
throw SerializationError("String too long for serializeString");
|
||||
char buf[2];
|
||||
writeU16((u8*)buf, plain.size());
|
||||
std::string s;
|
||||
s.reserve(s_size);
|
||||
s.append(&encoded.c_str()[2], s_size);
|
||||
s.append(buf, 2);
|
||||
for(u32 i=0; i<plain.size(); i++)
|
||||
{
|
||||
writeU16((u8*)buf, plain[i]);
|
||||
s.append(buf, 2);
|
||||
}
|
||||
return s;
|
||||
}*/
|
||||
}
|
||||
|
||||
// Reads a string with the length as the first two bytes
|
||||
inline std::string deSerializeString(std::istream &is)
|
||||
@ -2014,6 +2028,27 @@ inline std::string deSerializeString(std::istream &is)
|
||||
return s;
|
||||
}
|
||||
|
||||
// Reads a wide string with the length as the first two bytes
|
||||
inline std::wstring deSerializeWideString(std::istream &is)
|
||||
{
|
||||
char buf[2];
|
||||
is.read(buf, 2);
|
||||
if(is.gcount() != 2)
|
||||
throw SerializationError("deSerializeString: size not read");
|
||||
u16 s_size = readU16((u8*)buf);
|
||||
if(s_size == 0)
|
||||
return L"";
|
||||
std::wstring s;
|
||||
s.reserve(s_size);
|
||||
for(u32 i=0; i<s_size; i++)
|
||||
{
|
||||
is.read(&buf[0], 2);
|
||||
wchar_t c16 = readU16((u8*)buf);
|
||||
s.append(&c16, 1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// Creates a string with the length as the first four bytes
|
||||
inline std::string serializeLongString(const std::string &plain)
|
||||
{
|
||||
@ -2025,18 +2060,6 @@ inline std::string serializeLongString(const std::string &plain)
|
||||
return s;
|
||||
}
|
||||
|
||||
/*// Reads a string with the length as the first four bytes
|
||||
inline std::string deSerializeLongString(const std::string encoded)
|
||||
{
|
||||
u32 s_size = readU32((u8*)&encoded.c_str()[0]);
|
||||
if(s_size > encoded.length() - 4)
|
||||
return "";
|
||||
std::string s;
|
||||
s.reserve(s_size);
|
||||
s.append(&encoded.c_str()[4], s_size);
|
||||
return s;
|
||||
}*/
|
||||
|
||||
// Reads a string with the length as the first four bytes
|
||||
inline std::string deSerializeLongString(std::istream &is)
|
||||
{
|
||||
|
@ -19,10 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "voxel.h"
|
||||
#include "map.h"
|
||||
|
||||
// For TimeTaker
|
||||
#include "utility.h"
|
||||
#include "utility.h" // For TimeTaker
|
||||
#include "gettime.h"
|
||||
#include "content_mapnode.h"
|
||||
|
||||
/*
|
||||
Debug stuff
|
||||
|
@ -384,6 +384,14 @@ public:
|
||||
|
||||
return m_data[m_area.index(p)];
|
||||
}
|
||||
MapNode getNodeNoExNoEmerge(v3s16 p)
|
||||
{
|
||||
if(m_area.contains(p) == false)
|
||||
return MapNode(CONTENT_IGNORE);
|
||||
if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
|
||||
return MapNode(CONTENT_IGNORE);
|
||||
return m_data[m_area.index(p)];
|
||||
}
|
||||
MapNode & getNodeRef(v3s16 p)
|
||||
{
|
||||
emerge(p);
|
||||
|
21
util/colors.txt
Normal file
21
util/colors.txt
Normal file
@ -0,0 +1,21 @@
|
||||
0 128 128 128
|
||||
1 107 134 51
|
||||
2 39 66 106
|
||||
3 255 255 0
|
||||
4 86 58 31
|
||||
5 48 95 8
|
||||
6 102 129 38
|
||||
7 178 178 0
|
||||
8 101 84 36
|
||||
9 39 66 106
|
||||
12 104 78 42
|
||||
13 210 194 156
|
||||
14 117 86 41
|
||||
15 128 79 0
|
||||
16 118 118 118
|
||||
18 123 123 123
|
||||
19 199 199 199
|
||||
20 183 183 222
|
||||
21 103 78 42
|
||||
22 108 138 108
|
||||
23 90 90 90
|
271
util/genmap.py
Executable file
271
util/genmap.py
Executable file
@ -0,0 +1,271 @@
|
||||
#!/usr/bin/python2
|
||||
|
||||
# This is an example script that generates some valid map data.
|
||||
|
||||
import struct
|
||||
import random
|
||||
import os
|
||||
import sys
|
||||
import zlib
|
||||
import array
|
||||
from pnoise import pnoise
|
||||
|
||||
# Old directory format:
|
||||
# world/sectors/XXXXZZZZ/YYYY
|
||||
# XXXX,YYYY,ZZZZ = coordinates in hexadecimal
|
||||
# fffe = -2
|
||||
# ffff = -1
|
||||
# 0000 = 0
|
||||
# 0001 = 1
|
||||
#
|
||||
# New directory format:
|
||||
# world/sectors2/XXX/ZZZ/YYYY
|
||||
# XXX,YYYY,ZZZ = coordinates in hexadecimal
|
||||
# fffe = -2
|
||||
# ffff = -1
|
||||
# 0000 = 0
|
||||
# 0001 = 1
|
||||
# ffe = -2
|
||||
# fff = -1
|
||||
# 000 = 0
|
||||
# 001 = 1
|
||||
#
|
||||
# For more proper file format documentation, refer to mapformat.txt
|
||||
# For node type documentation, refer to mapnode.h
|
||||
# NodeMetadata documentation is not complete, refer to nodemeta.cpp
|
||||
#
|
||||
|
||||
# Seed for generating terrain
|
||||
SEED = 0
|
||||
|
||||
# 0=old, 1=new
|
||||
SECTOR_DIR_FORMAT = 1
|
||||
|
||||
mapdir = "../world"
|
||||
|
||||
def to4h(i):
|
||||
s = "";
|
||||
s += '{0:1x}'.format((i>>12) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>8) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>4) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>0) & 0x000f)
|
||||
return s
|
||||
|
||||
def to3h(i):
|
||||
s = "";
|
||||
s += '{0:1x}'.format((i>>8) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>4) & 0x000f)
|
||||
s += '{0:1x}'.format((i>>0) & 0x000f)
|
||||
return s
|
||||
|
||||
def get_sector_dir(px, pz):
|
||||
global SECTOR_DIR_FORMAT
|
||||
if SECTOR_DIR_FORMAT == 0:
|
||||
return "/sectors/"+to4h(px)+to4h(pz)
|
||||
elif SECTOR_DIR_FORMAT == 1:
|
||||
return "/sectors2/"+to3h(px)+"/"+to3h(pz)
|
||||
else:
|
||||
assert(0)
|
||||
|
||||
def getrand_air_stone():
|
||||
i = random.randrange(0,2)
|
||||
if i==0:
|
||||
return 0
|
||||
return 254
|
||||
|
||||
# 3-dimensional vector (position)
|
||||
class v3:
|
||||
def __init__(self, x=0, y=0, z=0):
|
||||
self.X = x
|
||||
self.Y = y
|
||||
self.Z = z
|
||||
|
||||
class NodeMeta:
|
||||
def __init__(self, type_id, data):
|
||||
self.type_id = type_id
|
||||
self.data = data
|
||||
|
||||
class StaticObject:
|
||||
def __init__(self):
|
||||
self.type_id = 0
|
||||
self.data = ""
|
||||
|
||||
def ser_u16(i):
|
||||
return chr((i>>8)&0xff) + chr((i>>0)&0xff)
|
||||
def ser_u32(i):
|
||||
return (chr((i>>24)&0xff) + chr((i>>16)&0xff)
|
||||
+ chr((i>>8)&0xff) + chr((i>>0)&0xff))
|
||||
|
||||
# A 16x16x16 chunk of map
|
||||
class MapBlock:
|
||||
def __init__(self):
|
||||
self.content = array.array('B')
|
||||
self.param1 = array.array('B')
|
||||
self.param2 = array.array('B')
|
||||
for i in range(16*16*16):
|
||||
# Initialize to air
|
||||
self.content.append(254)
|
||||
# Full light on sunlight, none when no sunlight
|
||||
self.param1.append(15)
|
||||
# No additional parameters
|
||||
self.param2.append(0)
|
||||
|
||||
# key = v3 pos
|
||||
# value = NodeMeta
|
||||
self.nodemeta = {}
|
||||
|
||||
# key = v3 pos
|
||||
# value = StaticObject
|
||||
self.static_objects = {}
|
||||
|
||||
def set_content(self, v3, b):
|
||||
self.content[v3.Z*16*16+v3.Y*16+v3.X] = b
|
||||
def set_param1(self, v3, b):
|
||||
self.param1[v3.Z*16*16+v3.Y*16+v3.X] = b
|
||||
def set_param2(self, v3, b):
|
||||
self.param2[v3.Z*16*16+v3.Y*16+v3.X] = b
|
||||
|
||||
# Get data for serialization. Returns a string.
|
||||
def serialize_data(self):
|
||||
s = ""
|
||||
for i in range(16*16*16):
|
||||
s += chr(self.content[i])
|
||||
for i in range(16*16*16):
|
||||
s += chr(self.param1[i])
|
||||
for i in range(16*16*16):
|
||||
s += chr(self.param2[i])
|
||||
return s
|
||||
|
||||
def serialize_nodemeta(self):
|
||||
s = ""
|
||||
s += ser_u16(1)
|
||||
s += ser_u16(len(self.nodemeta))
|
||||
for pos, meta in self.nodemeta.items():
|
||||
pos_i = pos.Z*16*16 + pos.Y*16 + pos.X
|
||||
s += ser_u16(pos_i)
|
||||
s += ser_u16(meta.type_id)
|
||||
s += ser_u16(len(meta.data))
|
||||
s += meta.data
|
||||
return s
|
||||
|
||||
def serialize_staticobj(self):
|
||||
s = ""
|
||||
s += chr(0)
|
||||
s += ser_u16(len(self.static_objects))
|
||||
for pos, obj in self.static_objects.items():
|
||||
pos_i = pos.Z*16*16 + pos.Y*16 + pos.X
|
||||
s += ser_s32(pos.X*1000)
|
||||
s += ser_s32(pos.Y*1000)
|
||||
s += ser_s32(pos.Z*1000)
|
||||
s += ser_u16(obj.type_id)
|
||||
s += ser_u16(len(obj.data))
|
||||
s += obj.data
|
||||
return s
|
||||
|
||||
def writeblock(mapdir, px,py,pz, block):
|
||||
|
||||
sectordir = mapdir + get_sector_dir(px, pz);
|
||||
|
||||
try:
|
||||
os.makedirs(sectordir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
path = sectordir+"/"+to4h(py)
|
||||
|
||||
print("writing block file "+path)
|
||||
|
||||
f = open(sectordir+"/"+to4h(py), "wb")
|
||||
|
||||
if f == None:
|
||||
return
|
||||
|
||||
# version
|
||||
version = 17
|
||||
f.write(struct.pack('B', version))
|
||||
|
||||
# flags
|
||||
# 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired
|
||||
flags = 0 + 0x02 + 0x04
|
||||
f.write(struct.pack('B', flags))
|
||||
|
||||
# data
|
||||
c_obj = zlib.compressobj()
|
||||
c_obj.compress(block.serialize_data())
|
||||
f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number
|
||||
f.write(c_obj.flush())
|
||||
|
||||
# node metadata
|
||||
c_obj = zlib.compressobj()
|
||||
c_obj.compress(block.serialize_nodemeta())
|
||||
f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number
|
||||
f.write(c_obj.flush())
|
||||
|
||||
# mapblockobject count
|
||||
f.write(ser_u16(0))
|
||||
|
||||
# static objects
|
||||
f.write(block.serialize_staticobj())
|
||||
|
||||
# timestamp
|
||||
f.write(ser_u32(0xffffffff))
|
||||
|
||||
f.close()
|
||||
|
||||
for z0 in range(-1,3):
|
||||
for x0 in range(-1,3):
|
||||
for y0 in range(-1,3):
|
||||
print("generating block "+str(x0)+","+str(y0)+","+str(z0))
|
||||
#v3 blockp = v3(x0,y0,z0)
|
||||
|
||||
# Create a MapBlock
|
||||
block = MapBlock()
|
||||
|
||||
# Generate stuff in it
|
||||
for z in range(0,16):
|
||||
for x in range(0,16):
|
||||
h = 20.0*pnoise((x0*16+x)/100.,(z0*16+z)/100.,SEED+0)
|
||||
h += 5.0*pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+0)
|
||||
if pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+92412) > 0.05:
|
||||
h += 10
|
||||
#print("r="+str(r))
|
||||
# This enables comparison by ==
|
||||
h = int(h)
|
||||
for y in range(0,16):
|
||||
p = v3(x,y,z)
|
||||
b = 254
|
||||
y1 = y0*16+y
|
||||
if y1 <= h-3:
|
||||
b = 0 #stone
|
||||
elif y1 <= h and y1 <= 0:
|
||||
b = 8 #mud
|
||||
elif y1 == h:
|
||||
b = 1 #grass
|
||||
elif y1 < h:
|
||||
b = 8 #mud
|
||||
elif y1 <= 1:
|
||||
b = 9 #water
|
||||
|
||||
# Material content
|
||||
block.set_content(p, b)
|
||||
|
||||
# Place a sign at the center at surface level.
|
||||
# Placing a sign means placing the sign node and
|
||||
# adding node metadata to the mapblock.
|
||||
if x == 8 and z == 8 and y0*16 <= h-1 and (y0+1)*16-1 > h:
|
||||
p = v3(8,h+1-y0*16,8)
|
||||
# 14 = Sign
|
||||
content_type = 14
|
||||
block.set_content(p, content_type)
|
||||
# This places the sign to the bottom of the cube.
|
||||
# Working values: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20
|
||||
block.set_param2(p, 0x08)
|
||||
# Then add metadata to hold the text of the sign
|
||||
s = "Hello at sector ("+str(x0)+","+str(z0)+")"
|
||||
meta = NodeMeta(content_type, ser_u16(len(s))+s)
|
||||
block.nodemeta[p] = meta
|
||||
|
||||
# Write it on disk
|
||||
writeblock(mapdir, x0,y0,z0, block)
|
||||
|
||||
#END
|
444
util/minetestmapper.py
Executable file
444
util/minetestmapper.py
Executable file
@ -0,0 +1,444 @@
|
||||
#!/usr/bin/python2
|
||||
# -*- coding: windows-1252 -*-
|
||||
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# COPYING for more details.
|
||||
|
||||
# Made by Jogge, modified by celeron55
|
||||
# 2011-05-29: j0gge: initial release
|
||||
# 2011-05-30: celeron55: simultaneous support for sectors/sectors2, removed
|
||||
# 2011-06-02: j0gge: command line parameters, coordinates, players, ...
|
||||
# 2011-06-04: celeron55: added #!/usr/bin/python2 and converted \r\n to \n
|
||||
# to make it easily executable on Linux
|
||||
|
||||
# Requires Python Imaging Library: http://www.pythonware.com/products/pil/
|
||||
|
||||
# Some speed-up: ...lol, actually it slows it down.
|
||||
#import psyco ; psyco.full()
|
||||
#from psyco.classes import *
|
||||
|
||||
import zlib
|
||||
import Image, ImageDraw, ImageFont, ImageColor
|
||||
import os
|
||||
import string
|
||||
import time
|
||||
import getopt
|
||||
import sys
|
||||
|
||||
def hex_to_int(h):
|
||||
i = int(h, 16)
|
||||
if(i > 2047):
|
||||
i -= 4096
|
||||
return i
|
||||
|
||||
def hex4_to_int(h):
|
||||
i = int(h, 16)
|
||||
if(i > 32767):
|
||||
i -= 65536
|
||||
return i
|
||||
|
||||
def int_to_hex3(i):
|
||||
if(i < 0):
|
||||
return "%03X" % (i + 4096)
|
||||
else:
|
||||
return "%03X" % i
|
||||
|
||||
def int_to_hex4(i):
|
||||
if(i < 0):
|
||||
return "%04X" % (i + 65536)
|
||||
else:
|
||||
return "%04X" % i
|
||||
|
||||
def limit(i, l, h):
|
||||
if(i > h):
|
||||
i = h
|
||||
if(i < l):
|
||||
i = l
|
||||
return i
|
||||
|
||||
def usage():
|
||||
print "TODO: Help"
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "hi:o:", ["help", "input=", "output=", "bgcolor=", "scalecolor=", "origincolor=", "playercolor=", "draworigin", "drawplayers", "drawscale"])
|
||||
except getopt.GetoptError, err:
|
||||
# print help information and exit:
|
||||
print str(err) # will print something like "option -a not recognized"
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
path = "../world/"
|
||||
output = "uloste.png"
|
||||
border = 0
|
||||
scalecolor = "black"
|
||||
bgcolor = "white"
|
||||
origincolor = "red"
|
||||
playercolor = "red"
|
||||
drawscale = False
|
||||
drawplayers = False
|
||||
draworigin = False
|
||||
|
||||
sector_xmin = -1500 / 16
|
||||
sector_xmax = 1500 / 16
|
||||
sector_zmin = -1500 / 16
|
||||
sector_zmax = 1500 / 16
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-h", "--help"):
|
||||
usage()
|
||||
sys.exit()
|
||||
elif o in ("-i", "--input"):
|
||||
path = a
|
||||
elif o in ("-o", "--output"):
|
||||
output = a
|
||||
elif o == "--bgcolor":
|
||||
bgcolor = ImageColor.getrgb(a)
|
||||
elif o == "--scalecolor":
|
||||
scalecolor = ImageColor.getrgb(a)
|
||||
elif o == "--playercolor":
|
||||
playercolor = ImageColor.getrgb(a)
|
||||
elif o == "--origincolor":
|
||||
origincolor = ImageColor.getrgb(a)
|
||||
elif o == "--drawscale":
|
||||
drawscale = True
|
||||
border = 40
|
||||
elif o == "--drawplayers":
|
||||
drawplayers = True
|
||||
elif o == "--draworigin":
|
||||
draworigin = True
|
||||
else:
|
||||
assert False, "unhandled option"
|
||||
|
||||
if path[-1:]!="/" and path[-1:]!="\\":
|
||||
path = path + "/"
|
||||
|
||||
# Load color information for the blocks.
|
||||
colors = {}
|
||||
f = file("colors.txt")
|
||||
for line in f:
|
||||
values = string.split(line)
|
||||
colors[int(values[0])] = (int(values[1]), int(values[2]), int(values[3]))
|
||||
f.close()
|
||||
|
||||
xlist = []
|
||||
zlist = []
|
||||
|
||||
# List all sectors to memory and calculate the width and heigth of the resulting picture.
|
||||
try:
|
||||
for filename in os.listdir(path + "sectors2"):
|
||||
for filename2 in os.listdir(path + "sectors2/" + filename):
|
||||
x = hex_to_int(filename)
|
||||
z = hex_to_int(filename2)
|
||||
if x < sector_xmin or x > sector_xmax:
|
||||
continue
|
||||
if z < sector_zmin or z > sector_zmax:
|
||||
continue
|
||||
xlist.append(x)
|
||||
zlist.append(z)
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
for filename in os.listdir(path + "sectors"):
|
||||
x = hex4_to_int(filename[:4])
|
||||
z = hex4_to_int(filename[-4:])
|
||||
if x < sector_xmin or x > sector_xmax:
|
||||
continue
|
||||
if z < sector_zmin or z > sector_zmax:
|
||||
continue
|
||||
xlist.append(x)
|
||||
zlist.append(z)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
minx = min(xlist)
|
||||
minz = min(zlist)
|
||||
maxx = max(xlist)
|
||||
maxz = max(zlist)
|
||||
|
||||
w = (maxx - minx) * 16 + 16
|
||||
h = (maxz - minz) * 16 + 16
|
||||
|
||||
print "w="+str(w)+" h="+str(h)
|
||||
|
||||
im = Image.new("RGB", (w + border, h + border), bgcolor)
|
||||
draw = ImageDraw.Draw(im)
|
||||
impix = im.load()
|
||||
|
||||
stuff = {}
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
# Go through all sectors.
|
||||
for n in range(len(xlist)):
|
||||
#if n > 500:
|
||||
# break
|
||||
if n % 200 == 0:
|
||||
nowtime = time.time()
|
||||
dtime = nowtime - starttime
|
||||
try:
|
||||
n_per_second = 1.0 * n / dtime
|
||||
except ZeroDivisionError:
|
||||
n_per_second = 0
|
||||
if n_per_second != 0:
|
||||
seconds_per_n = 1.0 / n_per_second
|
||||
time_guess = seconds_per_n * len(xlist)
|
||||
remaining_s = time_guess - dtime
|
||||
remaining_minutes = int(remaining_s / 60)
|
||||
remaining_s -= remaining_minutes * 60;
|
||||
print("Processing sector "+str(n)+" of "+str(len(xlist))
|
||||
+" ("+str(round(100.0*n/len(xlist), 1))+"%)"
|
||||
+" (ETA: "+str(remaining_minutes)+"m "
|
||||
+str(int(remaining_s))+"s)")
|
||||
|
||||
xpos = xlist[n]
|
||||
zpos = zlist[n]
|
||||
|
||||
xhex = int_to_hex3(xpos)
|
||||
zhex = int_to_hex3(zpos)
|
||||
xhex4 = int_to_hex4(xpos)
|
||||
zhex4 = int_to_hex4(zpos)
|
||||
|
||||
sector1 = xhex4.lower() + zhex4.lower()
|
||||
sector2 = xhex.lower() + "/" + zhex.lower()
|
||||
|
||||
ylist = []
|
||||
|
||||
sectortype = ""
|
||||
|
||||
try:
|
||||
for filename in os.listdir(path + "sectors/" + sector1):
|
||||
if(filename != "meta"):
|
||||
pos = int(filename, 16)
|
||||
if(pos > 32767):
|
||||
pos -= 65536
|
||||
ylist.append(pos)
|
||||
sectortype = "old"
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if sectortype != "old":
|
||||
try:
|
||||
for filename in os.listdir(path + "sectors2/" + sector2):
|
||||
if(filename != "meta"):
|
||||
pos = int(filename, 16)
|
||||
if(pos > 32767):
|
||||
pos -= 65536
|
||||
ylist.append(pos)
|
||||
sectortype = "new"
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if sectortype == "":
|
||||
continue
|
||||
|
||||
ylist.sort()
|
||||
|
||||
# Make a list of pixels of the sector that are to be looked for.
|
||||
pixellist = []
|
||||
water = {}
|
||||
for x in range(16):
|
||||
for z in range(16):
|
||||
pixellist.append((x, z))
|
||||
water[(x, z)] = 0
|
||||
|
||||
# Go through the Y axis from top to bottom.
|
||||
ylist2=[]
|
||||
for ypos in reversed(ylist):
|
||||
|
||||
yhex = int_to_hex4(ypos)
|
||||
|
||||
filename = ""
|
||||
if sectortype == "old":
|
||||
filename = path + "sectors/" + sector1 + "/" + yhex.lower()
|
||||
else:
|
||||
filename = path + "sectors2/" + sector2 + "/" + yhex.lower()
|
||||
|
||||
f = file(filename, "rb")
|
||||
|
||||
version = f.read(1)
|
||||
flags = f.read(1)
|
||||
|
||||
# Checking day and night differs -flag
|
||||
if not ord(flags) & 2:
|
||||
ylist2.append((ypos,filename))
|
||||
f.close()
|
||||
continue
|
||||
|
||||
dec_o = zlib.decompressobj()
|
||||
try:
|
||||
mapdata = dec_o.decompress(f.read())
|
||||
except:
|
||||
mapdata = []
|
||||
|
||||
f.close()
|
||||
|
||||
if(len(mapdata) < 4096):
|
||||
print "bad: " + xhex + "/" + zhex + "/" + yhex + " " + str(len(mapdata))
|
||||
else:
|
||||
chunkxpos = xpos * 16
|
||||
chunkypos = ypos * 16
|
||||
chunkzpos = zpos * 16
|
||||
for (x, z) in reversed(pixellist):
|
||||
for y in reversed(range(16)):
|
||||
datapos = x + y * 16 + z * 256
|
||||
if(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) in colors):
|
||||
if(ord(mapdata[datapos]) == 2 or ord(mapdata[datapos]) == 9):
|
||||
water[(x, z)] += 1
|
||||
# Add dummy stuff for drawing sea without seabed
|
||||
stuff[(chunkxpos + x, chunkzpos + z)] = (chunkypos + y, ord(mapdata[datapos]), water[(x, z)])
|
||||
else:
|
||||
pixellist.remove((x, z))
|
||||
# Memorize information on the type and height of the block and for drawing the picture.
|
||||
stuff[(chunkxpos + x, chunkzpos + z)] = (chunkypos + y, ord(mapdata[datapos]), water[(x, z)])
|
||||
break
|
||||
elif(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) not in colors):
|
||||
print "strange block: " + xhex + "/" + zhex + "/" + yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " palikka: " + str(ord(mapdata[datapos]))
|
||||
|
||||
# After finding all the pixels in the sector, we can move on to the next sector without having to continue the Y axis.
|
||||
if(len(pixellist) == 0):
|
||||
break
|
||||
|
||||
if len(pixellist) > 0:
|
||||
for (ypos, filename) in ylist2:
|
||||
f = file(filename, "rb")
|
||||
|
||||
version = f.read(1)
|
||||
flags = f.read(1)
|
||||
|
||||
dec_o = zlib.decompressobj()
|
||||
try:
|
||||
mapdata = dec_o.decompress(f.read())
|
||||
except:
|
||||
mapdata = []
|
||||
|
||||
f.close()
|
||||
|
||||
if(len(mapdata) < 4096):
|
||||
print "bad: " + xhex + "/" + zhex + "/" + yhex + " " + str(len(mapdata))
|
||||
else:
|
||||
chunkxpos = xpos * 16
|
||||
chunkypos = ypos * 16
|
||||
chunkzpos = zpos * 16
|
||||
for (x, z) in reversed(pixellist):
|
||||
for y in reversed(range(16)):
|
||||
datapos = x + y * 16 + z * 256
|
||||
if(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) in colors):
|
||||
if(ord(mapdata[datapos]) == 2 or ord(mapdata[datapos]) == 9):
|
||||
water[(x, z)] += 1
|
||||
# Add dummy stuff for drawing sea without seabed
|
||||
stuff[(chunkxpos + x, chunkzpos + z)] = (chunkypos + y, ord(mapdata[datapos]), water[(x, z)])
|
||||
else:
|
||||
pixellist.remove((x, z))
|
||||
# Memorize information on the type and height of the block and for drawing the picture.
|
||||
stuff[(chunkxpos + x, chunkzpos + z)] = (chunkypos + y, ord(mapdata[datapos]), water[(x, z)])
|
||||
break
|
||||
elif(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) not in colors):
|
||||
print "outo palikka: " + xhex + "/" + zhex + "/" + yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " palikka: " + str(ord(mapdata[datapos]))
|
||||
|
||||
# After finding all the pixels in the sector, we can move on to the next sector without having to continue the Y axis.
|
||||
if(len(pixellist) == 0):
|
||||
break
|
||||
|
||||
print "Drawing image"
|
||||
# Drawing the picture
|
||||
starttime = time.time()
|
||||
n = 0
|
||||
for (x, z) in stuff.iterkeys():
|
||||
if n % 500000 == 0:
|
||||
nowtime = time.time()
|
||||
dtime = nowtime - starttime
|
||||
try:
|
||||
n_per_second = 1.0 * n / dtime
|
||||
except ZeroDivisionError:
|
||||
n_per_second = 0
|
||||
if n_per_second != 0:
|
||||
listlen = len(stuff)
|
||||
seconds_per_n = 1.0 / n_per_second
|
||||
time_guess = seconds_per_n * listlen
|
||||
remaining_s = time_guess - dtime
|
||||
remaining_minutes = int(remaining_s / 60)
|
||||
remaining_s -= remaining_minutes * 60;
|
||||
print("Drawing pixel "+str(n)+" of "+str(listlen)
|
||||
+" ("+str(round(100.0*n/listlen, 1))+"%)"
|
||||
+" (ETA: "+str(remaining_minutes)+"m "
|
||||
+str(int(remaining_s))+"s)")
|
||||
n += 1
|
||||
|
||||
(r, g, b) = colors[stuff[(x,z)][1]]
|
||||
# Comparing heights of a couple of adjacent blocks and changing brightness accordingly.
|
||||
try:
|
||||
c1 = stuff[(x - 1, z)][1]
|
||||
c2 = stuff[(x, z + 1)][1]
|
||||
c = stuff[(x, z)][1]
|
||||
if c1 != 2 and c1 != 9 and c2 != 2 and c2 != 9 and c != 2 and c != 9:
|
||||
y1 = stuff[(x - 1, z)][0]
|
||||
y2 = stuff[(x, z + 1)][0]
|
||||
y = stuff[(x, z)][0]
|
||||
|
||||
d = ((y - y1) + (y - y2)) * 12
|
||||
else:
|
||||
d = 0
|
||||
|
||||
if(d > 36):
|
||||
d = 36
|
||||
|
||||
r = limit(r + d, 0, 255)
|
||||
g = limit(g + d, 0, 255)
|
||||
b = limit(b + d, 0, 255)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Water
|
||||
if(stuff[(x,z)][2] > 0):
|
||||
r=int(r * .15 + colors[2][0] * .85)
|
||||
g=int(g * .15 + colors[2][1] * .85)
|
||||
b=int(b * .15 + colors[2][2] * .85)
|
||||
|
||||
impix[x - minx * 16 + border, h - 1 - (z - minz * 16) + border] = (r, g, b)
|
||||
|
||||
|
||||
if draworigin:
|
||||
draw.ellipse((minx * -16 - 5 + border, h - minz * -16 - 6 + border, minx * -16 + 5 + border, h - minz * -16 + 4 + border), outline = origincolor)
|
||||
|
||||
font = ImageFont.load_default()
|
||||
|
||||
if drawscale:
|
||||
draw.text((24, 0), "X", font = font, fill = scalecolor)
|
||||
draw.text((2, 24), "Z", font = font, fill = scalecolor)
|
||||
|
||||
for n in range(int(minx / -4) * -4, maxx, 4):
|
||||
draw.text((minx * -16 + n * 16 + 2 + border, 0), str(n * 16), font = font, fill = scalecolor)
|
||||
draw.line((minx * -16 + n * 16 + border, 0, minx * -16 + n * 16 + border, border - 1), fill = scalecolor)
|
||||
|
||||
for n in range(int(maxz / 4) * 4, minz, -4):
|
||||
draw.text((2, h - 1 - (n * 16 - minz * 16) + border), str(n * 16), font = font, fill = scalecolor)
|
||||
draw.line((0, h - 1 - (n * 16 - minz * 16) + border, border - 1, h - 1 - (n * 16 - minz * 16) + border), fill = scalecolor)
|
||||
|
||||
if drawplayers:
|
||||
try:
|
||||
for filename in os.listdir(path + "players"):
|
||||
f = file(path + "players/" + filename)
|
||||
lines = f.readlines()
|
||||
name=""
|
||||
position=[]
|
||||
for line in lines:
|
||||
p = string.split(line)
|
||||
if p[0] == "name":
|
||||
name = p[2]
|
||||
print filename + ": name = " + name
|
||||
if p[0] == "position":
|
||||
position = string.split(p[2][1:-1], ",")
|
||||
print filename + ": position = " + p[2]
|
||||
if len(name) > 0 and len(position) == 3:
|
||||
x=(int(float(position[0]) / 10 - minx * 16))
|
||||
z=int(h - (float(position[2]) / 10 - minz * 16))
|
||||
draw.ellipse((x - 2 + border, z - 2 + border, x + 2 + border, z + 2 + border), outline = playercolor)
|
||||
draw.text((x + 2 + border, z + 2 + border), name, font = font, fill = playercolor)
|
||||
f.close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
print "Saving"
|
||||
im.save(output)
|
102
util/pnoise.py
Normal file
102
util/pnoise.py
Normal file
@ -0,0 +1,102 @@
|
||||
#
|
||||
# A python perlin noise implementation, from
|
||||
# http://www.fundza.com/c4serious/noise/perlin/perlin.html
|
||||
#
|
||||
# This is used for testing how to create maps with a python script.
|
||||
#
|
||||
|
||||
import math
|
||||
p = (
|
||||
151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,
|
||||
30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,
|
||||
62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,
|
||||
125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,
|
||||
83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,
|
||||
143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,
|
||||
196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,
|
||||
250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,
|
||||
58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,
|
||||
221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,
|
||||
224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,
|
||||
12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,
|
||||
199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,
|
||||
205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
|
||||
151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,
|
||||
30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,
|
||||
62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,
|
||||
125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,
|
||||
83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,
|
||||
143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,
|
||||
196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,
|
||||
250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,
|
||||
58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,
|
||||
221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,
|
||||
224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,
|
||||
12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,
|
||||
199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,
|
||||
205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180)
|
||||
|
||||
def lerp(t, a, b):
|
||||
return a + t * (b - a)
|
||||
|
||||
def fade(t):
|
||||
return t * t * t * (t * (t * 6 - 15) + 10)
|
||||
|
||||
def grad(hash, x, y, z):
|
||||
h = hash & 15
|
||||
if h < 8:
|
||||
u = x
|
||||
else:
|
||||
u = y
|
||||
if h < 4:
|
||||
v = y
|
||||
elif h == 12 or h == 14:
|
||||
v = x
|
||||
else:
|
||||
v = z
|
||||
if h & 1 != 0:
|
||||
u = -u
|
||||
if h & 2 != 0:
|
||||
v = -v
|
||||
return u + v
|
||||
|
||||
def pnoise(x, y, z):
|
||||
global p
|
||||
X = int(math.floor(x)) & 255
|
||||
Y = int(math.floor(y)) & 255
|
||||
Z = int(math.floor(z)) & 255
|
||||
x -= math.floor(x)
|
||||
y -= math.floor(y)
|
||||
z -= math.floor(z)
|
||||
|
||||
u = fade(x)
|
||||
v = fade(y)
|
||||
w = fade(z)
|
||||
|
||||
A = p[X] + Y
|
||||
AA = p[A] + Z
|
||||
AB = p[A + 1] + Z
|
||||
B = p[X + 1] + Y
|
||||
BA = p[B] + Z
|
||||
BB = p[B + 1] + Z
|
||||
|
||||
pAA = p[AA]
|
||||
pAB = p[AB]
|
||||
pBA = p[BA]
|
||||
pBB = p[BB]
|
||||
pAA1 = p[AA + 1]
|
||||
pBA1 = p[BA + 1]
|
||||
pAB1 = p[AB + 1]
|
||||
pBB1 = p[BB + 1]
|
||||
|
||||
gradAA = grad(pAA, x, y, z)
|
||||
gradBA = grad(pBA, x-1, y, z)
|
||||
gradAB = grad(pAB, x, y-1, z)
|
||||
gradBB = grad(pBB, x-1, y-1, z)
|
||||
gradAA1 = grad(pAA1,x, y, z-1)
|
||||
gradBA1 = grad(pBA1,x-1, y, z-1)
|
||||
gradAB1 = grad(pAB1,x, y-1, z-1)
|
||||
gradBB1 = grad(pBB1,x-1, y-1, z-1)
|
||||
return lerp(w,
|
||||
lerp(v, lerp(u, gradAA, gradBA), lerp(u, gradAB, gradBB)),
|
||||
lerp(v, lerp(u, gradAA1,gradBA1),lerp(u, gradAB1,gradBB1)))
|
Loading…
Reference in New Issue
Block a user