master
Maksim Gamarnik 2015-12-09 12:56:21 +02:00
parent 1797862bf9
commit ba2e36fd37
19 changed files with 279 additions and 90 deletions

View File

@ -1305,10 +1305,12 @@ mentioned in "Nodes". However, it is possible to insert extra data into a
node. It is called "node metadata"; See "`NodeMetaRef`".
Metadata contains two things:
* A key-value store
* An inventory
Some of the values in the key-value store are handled specially:
* `formspec`: Defines a right-click inventory menu. See "Formspec".
* `infotext`: Text shown on the screen when the node is pointed at
@ -2938,6 +2940,7 @@ core.CONTENT_IGNORE (ID for "ignore" nodes)
Inside of `on_generated()` callbacks, it is possible to retrieve the same VoxelManip object used by the
core's Map Generator (commonly abbreviated Mapgen). Most of the rules previously described still apply
but with a few differences:
* The Mapgen VoxelManip object is retrieved using: `minetest.get_mapgen_object("voxelmanip")`
* This VoxelManip object already has the region of map just generated loaded into it; it's not necessary
to call `VoxelManip:read_from_map()` before using a Mapgen VoxelManip.
@ -2996,7 +2999,7 @@ will place the schematic inside of the VoxelManip.
* `update_map()`: Update map after writing chunk back to map.
* To be used only by `VoxelManip` objects created by the mod itself;
not a `VoxelManip` that was retrieved from `minetest.get_mapgen_object`
* `set_lighting(light, p1, p2)`: Set the lighting within the `VoxelManip` to a uniform value
* `set_lighting(light, [p1, p2])`: Set the lighting within the `VoxelManip` to a uniform value
* `light` is a table, `{day=<0...15>, night=<0...15>}`
* To be used only by a `VoxelManip` object from `minetest.get_mapgen_object`
* (`p1`, `p2`) is the area in which lighting is set;
@ -3010,10 +3013,12 @@ will place the schematic inside of the VoxelManip.
* expects lighting data in the same format that `get_light_data()` returns
* `get_param2_data()`: Gets the raw `param2` data read into the `VoxelManip` object
* `set_param2_data(param2_data)`: Sets the `param2` contents of each node in the `VoxelManip`
* `calc_lighting(p1, p2)`: Calculate lighting within the `VoxelManip`
* `calc_lighting([p1, p2], [propagate_shadow])`: Calculate lighting within the `VoxelManip`
* To be used only by a `VoxelManip` object from `minetest.get_mapgen_object`
* (`p1`, `p2`) is the area in which lighting is set; defaults to the whole area
if left out
if left out or nil
* `propagate_shadow` is an optional boolean deciding whether shadows in a generated
mapchunk above are propagated down into the mapchunk; defaults to `true` if left out
* `update_liquids()`: Update liquid flow
* `was_modified()`: Returns `true` or `false` if the data in the voxel manipulator
had been modified since the last read from map, due to a call to

View File

@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
static std::string getMediaCacheDir()
{
return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "media";
return porting::path_cache + DIR_DELIM + "media";
}
/*

View File

@ -707,5 +707,10 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
}
}
bool Rename(const std::string &from, const std::string &to)
{
return rename(from.c_str(), to.c_str()) == 0;
}
} // namespace fs

View File

@ -115,6 +115,8 @@ const char *GetFilenameFromPath(const char *path);
bool safeWriteToFile(const std::string &path, const std::string &content);
bool Rename(const std::string &from, const std::string &to);
} // namespace fs
#endif

View File

@ -164,7 +164,13 @@ int main(int argc, char *argv[])
setup_log_params(cmd_args);
porting::signal_handler_init();
#ifdef __ANDROID__
porting::initAndroid();
porting::initializePathsAndroid();
#else
porting::initializePaths();
#endif
if (!create_userdata_path()) {
errorstream << "Cannot create user data directory" << std::endl;
@ -422,9 +428,6 @@ static bool create_userdata_path()
bool success;
#ifdef __ANDROID__
porting::initAndroid();
porting::setExternalStorageDir(porting::jnienv);
if (!fs::PathExists(porting::path_user)) {
success = fs::CreateDir(porting::path_user);
} else {
@ -436,9 +439,6 @@ static bool create_userdata_path()
success = fs::CreateDir(porting::path_user);
#endif
infostream << "path_share = " << porting::path_share << std::endl;
infostream << "path_user = " << porting::path_user << std::endl;
return success;
}

View File

@ -264,37 +264,20 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
}
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax)
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
bool propagate_shadow)
{
ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
//TimeTaker t("updateLighting");
propagateSunlight(nmin, nmax);
propagateSunlight(nmin, nmax, propagate_shadow);
spreadLight(full_nmin, full_nmax);
//printf("updateLighting: %dms\n", t.stop());
}
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax)
{
ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
//TimeTaker t("updateLighting");
propagateSunlight(
nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
nmax + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
spreadLight(
nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
nmax + v3s16(1, 1, 1) * MAP_BLOCKSIZE);
//printf("updateLighting: %dms\n", t.stop());
}
void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax)
void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
{
//TimeTaker t("propagateSunlight");
VoxelArea a(nmin, nmax);
@ -308,7 +291,8 @@ void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax)
if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
if (block_is_underground)
continue;
} else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN) {
} else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN &&
propagate_shadow) {
continue;
}
vm->m_area.add_y(em, i, -1);
@ -326,7 +310,6 @@ void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax)
}
void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
{
//TimeTaker t("spreadLight");

View File

@ -173,12 +173,9 @@ public:
void setLighting(u8 light, v3s16 nmin, v3s16 nmax);
void lightSpread(VoxelArea &a, v3s16 p, u8 light);
void calcLighting(v3s16 nmin, v3s16 nmax);
void calcLighting(v3s16 nmin, v3s16 nmax,
v3s16 full_nmin, v3s16 full_nmax);
void propagateSunlight(v3s16 nmin, v3s16 nmax);
void calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
bool propagate_shadow = true);
void propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow);
void spreadLight(v3s16 nmin, v3s16 nmax);
virtual void makeChunk(BlockMakeData *data) {}

View File

@ -38,6 +38,9 @@ MapgenSinglenode::MapgenSinglenode(int mapgenid,
c_node = ndef->getId("mapgen_singlenode");
if (c_node == CONTENT_IGNORE)
c_node = CONTENT_AIR;
MapNode n_node(c_node);
set_light = (ndef->get(n_node).sunlight_propagates) ? LIGHT_SUN : 0x00;
}
@ -45,6 +48,7 @@ MapgenSinglenode::~MapgenSinglenode()
{
}
//////////////////////// Map generator
void MapgenSinglenode::makeChunk(BlockMakeData *data)
@ -53,11 +57,11 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data)
assert(data->vmanip);
assert(data->nodedef);
assert(data->blockpos_requested.X >= data->blockpos_min.X &&
data->blockpos_requested.Y >= data->blockpos_min.Y &&
data->blockpos_requested.Z >= data->blockpos_min.Z);
data->blockpos_requested.Y >= data->blockpos_min.Y &&
data->blockpos_requested.Z >= data->blockpos_min.Z);
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
this->generating = true;
this->vm = data->vmanip;
@ -67,8 +71,8 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data)
v3s16 blockpos_max = data->blockpos_max;
// Area of central chunk
v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
v3s16 node_min = blockpos_min * MAP_BLOCKSIZE;
v3s16 node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
blockseed = getBlockSeed2(node_min, data->seed);
@ -87,15 +91,15 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data)
// Add top and bottom side of water to transforming_liquid queue
updateLiquid(&data->transforming_liquid, node_min, node_max);
// Calculate lighting
if (flags & MG_LIGHT)
calcLighting(node_min, node_max);
// Set lighting
if ((flags & MG_LIGHT) && set_light == LIGHT_SUN)
setLighting(LIGHT_SUN, node_min, node_max);
this->generating = false;
}
int MapgenSinglenode::getGroundLevelAtPoint(v2s16 p)
{
return 0;
}

View File

@ -35,6 +35,7 @@ class MapgenSinglenode : public Mapgen {
public:
u32 flags;
content_t c_node;
u8 set_light;
MapgenSinglenode(int mapgenid, MapgenParams *params, EmergeManager *emerge);
~MapgenSinglenode();

View File

@ -593,7 +593,9 @@ void MapgenV6::makeChunk(BlockMakeData *data)
// Calculate lighting
if (flags & MG_LIGHT)
calcLighting(node_min, node_max);
calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE,
full_node_min, full_node_max);
this->generating = false;
}

View File

@ -139,6 +139,7 @@ void signal_handler_init(void)
std::string path_share = "..";
std::string path_user = "..";
std::string path_locale = path_share + DIR_DELIM + "locale";
std::string path_cache = path_user + DIR_DELIM + "cache";
std::string getDataPath(const char *subpath)
@ -463,6 +464,25 @@ bool setSystemPaths()
#endif
void migrateCachePath()
{
const std::string local_cache_path = path_user + DIR_DELIM + "cache";
// Delete tmp folder if it exists (it only ever contained
// a temporary ogg file, which is no longer used).
if (fs::PathExists(local_cache_path + DIR_DELIM + "tmp"))
fs::RecursiveDelete(local_cache_path + DIR_DELIM + "tmp");
// Bail if migration impossible
if (path_cache == local_cache_path || !fs::PathExists(local_cache_path)
|| fs::PathExists(path_cache)) {
return;
}
if (!fs::Rename(local_cache_path, path_cache)) {
errorstream << "Failed to migrate local cache path "
"to system path!" << std::endl;
}
}
void initializePaths()
{
@ -513,10 +533,27 @@ void initializePaths()
if (!setSystemPaths())
errorstream << "Failed to get one or more system-wide path" << std::endl;
// Initialize path_cache
// First try $XDG_CACHE_HOME/PROJECT_NAME
const char *cache_dir = getenv("XDG_CACHE_HOME");
if (cache_dir) {
path_cache = std::string(cache_dir) + DIR_DELIM + PROJECT_NAME;
} else {
// Then try $HOME/.cache/PROJECT_NAME
const char *home_dir = getenv("HOME");
if (home_dir) {
path_cache = std::string(home_dir) + DIR_DELIM + ".cache"
+ DIR_DELIM + PROJECT_NAME;
}
// If neither works, leave it at $PATH_USER/cache
}
// Migrate cache folder to new location if possible
migrateCachePath();
#endif
infostream << "Detected share path: " << path_share << std::endl;
infostream << "Detected user path: " << path_user << std::endl;
infostream << "Detected cache path: " << path_cache << std::endl;
bool found_localedir = false;
#ifdef STATIC_LOCALEDIR
@ -542,7 +579,6 @@ void initializePaths()
if (!found_localedir) {
errorstream << "Couldn't find a locale directory!" << std::endl;
}
}

View File

@ -147,12 +147,23 @@ extern std::string path_user;
*/
extern std::string path_locale;
/*
Path to directory for storing caches.
*/
extern std::string path_cache;
/*
Get full path of stuff in data directory.
Example: "stone.png" -> "../data/stone.png"
*/
std::string getDataPath(const char *subpath);
/*
Move cache folder from path_user to the
system cache location if possible.
*/
void migrateCachePath();
/*
Initialize path_*.
*/

View File

@ -177,29 +177,63 @@ void cleanupAndroid()
ANativeActivity_finish(app_global->activity);
}
void setExternalStorageDir(JNIEnv* lJNIEnv)
static std::string javaStringToUTF8(jstring js)
{
// Android: Retrieve ablsolute path to external storage device (sdcard)
jclass ClassEnv = lJNIEnv->FindClass("android/os/Environment");
jmethodID MethodDir =
lJNIEnv->GetStaticMethodID(ClassEnv,
"getExternalStorageDirectory","()Ljava/io/File;");
jobject ObjectFile = lJNIEnv->CallStaticObjectMethod(ClassEnv, MethodDir);
jclass ClassFile = lJNIEnv->FindClass("java/io/File");
std::string str;
// Get string as a UTF-8 c-string
const char *c_str = jnienv->GetStringUTFChars(js, NULL);
// Save it
str = c_str;
// And free the c-string
jnienv->ReleaseStringUTFChars(js, c_str);
return str;
}
jmethodID MethodPath =
lJNIEnv->GetMethodID(ClassFile, "getAbsolutePath",
"()Ljava/lang/String;");
jstring StringPath =
(jstring) lJNIEnv->CallObjectMethod(ObjectFile, MethodPath);
// Calls static method if obj is NULL
static std::string getAndroidPath(jclass cls, jobject obj, jclass cls_File,
jmethodID mt_getAbsPath, const char *getter)
{
// Get getter method
jmethodID mt_getter;
if (obj)
mt_getter = jnienv->GetMethodID(cls, getter,
"()Ljava/io/File;");
else
mt_getter = jnienv->GetStaticMethodID(cls, getter,
"()Ljava/io/File;");
const char *externalPath = lJNIEnv->GetStringUTFChars(StringPath, NULL);
std::string userPath(externalPath);
lJNIEnv->ReleaseStringUTFChars(StringPath, externalPath);
// Call getter
jobject ob_file;
if (obj)
ob_file = jnienv->CallObjectMethod(obj, mt_getter);
else
ob_file = jnienv->CallStaticObjectMethod(cls, mt_getter);
path_storage = userPath;
path_user = userPath + DIR_DELIM + PROJECT_NAME_C;
path_share = userPath + DIR_DELIM + PROJECT_NAME_C;
// Call getAbsolutePath
jstring js_path = (jstring) jnienv->CallObjectMethod(ob_file,
mt_getAbsPath);
return javaStringToUTF8(js_path);
}
void initializePathsAndroid()
{
// Get Environment class
jclass cls_Env = jnienv->FindClass("android/os/Environment");
// Get File class
jclass cls_File = jnienv->FindClass("java/io/File");
// Get getAbsolutePath method
jmethodID mt_getAbsPath = jnienv->GetMethodID(cls_File,
"getAbsolutePath", "()Ljava/lang/String;");
path_cache = getAndroidPath(nativeActivity, app_global->activity->clazz,
cls_File, mt_getAbsPath, "getCacheDir");
path_storage = getAndroidPath(cls_Env, NULL, cls_File, mt_getAbsPath,
"getExternalStorageDirectory");
path_user = path_storage + DIR_DELIM + PROJECT_NAME_C;
path_share = path_storage + DIR_DELIM + PROJECT_NAME_C;
migrateCachePath();
}
void showInputDialog(const std::string& acceptButton, const std::string& hint,

View File

@ -43,10 +43,10 @@ void initAndroid();
void cleanupAndroid();
/**
* set storage dir on external sdcard#
* @param lJNIEnv environment from android
* Initializes path_* variables for Android
* @param env Android JNI environment
*/
void setExternalStorageDir(JNIEnv* lJNIEnv);
void initializePathsAndroid();
/**
* use java function to copy media from assets to external storage

View File

@ -951,9 +951,9 @@ int ModApiMapgen::l_register_ore(lua_State *L)
warn_if_field_exists(L, index, "noise_threshhold",
"Deprecated: new name is \"noise_threshold\".");
int nthresh;
if (!getintfield(L, index, "noise_threshold", nthresh) &&
!getintfield(L, index, "noise_threshhold", nthresh))
float nthresh;
if (!getfloatfield(L, index, "noise_threshold", nthresh) &&
!getfloatfield(L, index, "noise_threshhold", nthresh))
nthresh = 0;
ore->nthresh = nthresh;

View File

@ -181,6 +181,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
v3s16 fpmax = vm->m_area.MaxEdge;
v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
bool propagate_shadow = lua_isboolean(L, 4) ? lua_toboolean(L, 4) : true;
sortBoxVerticies(pmin, pmax);
if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
@ -191,7 +192,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
mg.ndef = ndef;
mg.water_level = emerge->params.water_level;
mg.calcLighting(pmin, pmax, fpmin, fpmax);
mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);
return 0;
}

View File

@ -1,4 +1,5 @@
set(JTHREAD_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/event.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mutex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp

95
src/threading/event.cpp Normal file
View File

@ -0,0 +1,95 @@
/*
This file is a part of the JThread package, which contains some object-
oriented thread wrappers for different thread implementations.
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.
*/
#include "threading/event.h"
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
#if __cplusplus < 201103L
Event::Event()
{
#ifdef _WIN32
event = CreateEvent(NULL, false, false, NULL);
#else
pthread_cond_init(&cv, NULL);
pthread_mutex_init(&mutex, NULL);
#endif
}
Event::~Event()
{
#ifdef _WIN32
CloseHandle(event);
#else
pthread_cond_destroy(&cv);
pthread_mutex_destroy(&mutex);
#endif
}
#endif
void Event::wait()
{
#if __cplusplus >= 201103L
MutexAutoLock lock(mutex);
while (!notified) {
cv.wait(lock);
}
notified = false;
#elif defined(_WIN32)
WaitForSingleObject(event, INFINITE);
#else
pthread_mutex_lock(&mutex);
while (!notified) {
pthread_cond_wait(&cv, &mutex);
}
notified = false;
pthread_mutex_unlock(&mutex);
#endif
}
void Event::signal()
{
#if __cplusplus >= 201103L
MutexAutoLock lock(mutex);
notified = true;
cv.notify_one();
#elif defined(_WIN32)
SetEvent(event);
#else
pthread_mutex_lock(&mutex);
notified = true;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mutex);
#endif
}

View File

@ -26,30 +26,42 @@ DEALINGS IN THE SOFTWARE.
#ifndef THREADING_EVENT_H
#define THREADING_EVENT_H
#ifdef _WIN32
#include <windows.h>
#if __cplusplus >= 201103L
#include <condition_variable>
#include "threading/mutex.h"
#elif defined(_WIN32)
#include <windef.h>
#else
#include "threading/semaphore.h"
#include <pthread.h>
#endif
/** A syncronization primitive that will wake up one waiting thread when signaled.
* Calling @c signal() multiple times before a waiting thread has had a chance
* to notice the signal will wake only one thread. Additionally, if no threads
* are waiting on the event when it is signaled, the next call to @c wait()
* will return (almost) immediately.
*/
class Event {
public:
#ifdef _WIN32
Event() { event = CreateEvent(NULL, false, false, NULL); }
~Event() { CloseHandle(event); }
void wait() { WaitForSingleObject(event, INFINITE); }
void signal() { SetEvent(event); }
#else
void wait() { sem.wait(); }
void signal() { sem.post(); }
#if __cplusplus < 201103L
Event();
~Event();
#endif
void wait();
void signal();
private:
#ifdef _WIN32
#if __cplusplus >= 201103L
std::condition_variable cv;
Mutex mutex;
bool notified;
#elif defined(_WIN32)
HANDLE event;
#else
Semaphore sem;
pthread_cond_t cv;
pthread_mutex_t mutex;
bool notified;
#endif
};