Merge branch 'develop' of https://github.com/DFHack/dfhack into Units

develop
PatrikLundell 2020-05-23 10:25:08 +02:00
commit 4e97269312
20 changed files with 250 additions and 359 deletions

@ -89,6 +89,10 @@ if(MSVC)
# a smaller type, and most of the time this is just conversion from 64 to 32 bits # a smaller type, and most of the time this is just conversion from 64 to 32 bits
# for things like vector sizes, which are never that big anyway. # for things like vector sizes, which are never that big anyway.
add_definitions("/wd4267") add_definitions("/wd4267")
# MSVC panics if an object file contains more than 65,279 sections. this
# happens quite frequently with code that uses templates, such as vectors.
add_definitions("/bigobj")
endif() endif()
# Automatically detect architecture based on Visual Studio generator # Automatically detect architecture based on Visual Studio generator

@ -1,5 +1,5 @@
project(dfhack-tinythread) project(dfhack-tinythread)
add_library(dfhack-tinythread STATIC EXCLUDE_FROM_ALL tinythread.cpp tinythread.h fast_mutex.h) add_library(dfhack-tinythread STATIC EXCLUDE_FROM_ALL tinythread.cpp tinythread.h)
if(UNIX) if(UNIX)
target_link_libraries(dfhack-tinythread pthread) target_link_libraries(dfhack-tinythread pthread)
endif() endif()

@ -1,249 +0,0 @@
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
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.
*/
#ifndef _FAST_MUTEX_H_
#define _FAST_MUTEX_H_
/// @file
// Which platform are we on?
#if !defined(_TTHREAD_PLATFORM_DEFINED_)
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
#define _TTHREAD_WIN32_
#else
#define _TTHREAD_POSIX_
#endif
#define _TTHREAD_PLATFORM_DEFINED_
#endif
// Check if we can support the assembly language level implementation (otherwise
// revert to the system API)
#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \
(defined(_MSC_VER) && (defined(_M_IX86) /*|| defined(_M_X64)*/)) || \
(defined(__GNUC__) && (defined(__ppc__)))
#define _FAST_MUTEX_ASM_
#else
#define _FAST_MUTEX_SYS_
#endif
#if defined(_TTHREAD_WIN32_)
#define NOMINMAX
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define __UNDEF_LEAN_AND_MEAN
#endif
#include <windows.h>
#ifdef __UNDEF_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef __UNDEF_LEAN_AND_MEAN
#endif
#else
#ifdef _FAST_MUTEX_ASM_
#include <sched.h>
#else
#include <pthread.h>
#endif
#endif
namespace tthread {
/// Fast mutex class.
/// This is a mutual exclusion object for synchronizing access to shared
/// memory areas for several threads. It is similar to the tthread::mutex class,
/// but instead of using system level functions, it is implemented as an atomic
/// spin lock with very low CPU overhead.
///
/// The \c fast_mutex class is NOT compatible with the \c condition_variable
/// class (however, it IS compatible with the \c lock_guard class). It should
/// also be noted that the \c fast_mutex class typically does not provide
/// as accurate thread scheduling as a the standard \c mutex class does.
///
/// Because of the limitations of the class, it should only be used in
/// situations where the mutex needs to be locked/unlocked very frequently.
///
/// @note The "fast" version of this class relies on inline assembler language,
/// which is currently only supported for 32/64-bit Intel x86/AMD64 and
/// PowerPC architectures on a limited number of compilers (GNU g++ and MS
/// Visual C++).
/// For other architectures/compilers, system functions are used instead.
class fast_mutex {
public:
/// Constructor.
#if defined(_FAST_MUTEX_ASM_)
fast_mutex() : mLock(0) {}
#else
fast_mutex()
{
#if defined(_TTHREAD_WIN32_)
InitializeCriticalSection(&mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_mutex_init(&mHandle, NULL);
#endif
}
#endif
#if !defined(_FAST_MUTEX_ASM_)
/// Destructor.
~fast_mutex()
{
#if defined(_TTHREAD_WIN32_)
DeleteCriticalSection(&mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_mutex_destroy(&mHandle);
#endif
}
#endif
/// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until \c unlock() is called.
/// @see lock_guard
inline void lock()
{
#if defined(_FAST_MUTEX_ASM_)
bool gotLock;
do {
gotLock = try_lock();
if(!gotLock)
{
#if defined(_TTHREAD_WIN32_)
Sleep(0);
#elif defined(_TTHREAD_POSIX_)
sched_yield();
#endif
}
} while(!gotLock);
#else
#if defined(_TTHREAD_WIN32_)
EnterCriticalSection(&mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_mutex_lock(&mHandle);
#endif
#endif
}
/// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking).
/// @return \c true if the lock was acquired, or \c false if the lock could
/// not be acquired.
inline bool try_lock()
{
#if defined(_FAST_MUTEX_ASM_)
int oldLock;
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
asm volatile (
"movl $1,%%eax\n\t"
"xchg %%eax,%0\n\t"
"movl %%eax,%1\n\t"
: "=m" (mLock), "=m" (oldLock)
:
: "%eax", "memory"
);
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
int *ptrLock = &mLock;
__asm {
mov eax,1
mov ecx,ptrLock
xchg eax,[ecx]
mov oldLock,eax
}
#elif defined(__GNUC__) && (defined(__ppc__))
int newLock = 1;
asm volatile (
"\n1:\n\t"
"lwarx %0,0,%1\n\t"
"cmpwi 0,%0,0\n\t"
"bne- 2f\n\t"
"stwcx. %2,0,%1\n\t"
"bne- 1b\n\t"
"isync\n"
"2:\n\t"
: "=&r" (oldLock)
: "r" (&mLock), "r" (newLock)
: "cr0", "memory"
);
#endif
return (oldLock == 0);
#else
#if defined(_TTHREAD_WIN32_)
return TryEnterCriticalSection(&mHandle) ? true : false;
#elif defined(_TTHREAD_POSIX_)
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
#endif
#endif
}
/// Unlock the mutex.
/// If any threads are waiting for the lock on this mutex, one of them will
/// be unblocked.
inline void unlock()
{
#if defined(_FAST_MUTEX_ASM_)
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
asm volatile (
"movl $0,%%eax\n\t"
"xchg %%eax,%0\n\t"
: "=m" (mLock)
:
: "%eax", "memory"
);
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
int *ptrLock = &mLock;
__asm {
mov eax,0
mov ecx,ptrLock
xchg eax,[ecx]
}
#elif defined(__GNUC__) && (defined(__ppc__))
asm volatile (
"sync\n\t" // Replace with lwsync where possible?
: : : "memory"
);
mLock = 0;
#endif
#else
#if defined(_TTHREAD_WIN32_)
LeaveCriticalSection(&mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_mutex_unlock(&mHandle);
#endif
#endif
}
private:
#if defined(_FAST_MUTEX_ASM_)
int mLock;
#else
#if defined(_TTHREAD_WIN32_)
CRITICAL_SECTION mHandle;
#elif defined(_TTHREAD_POSIX_)
pthread_mutex_t mHandle;
#endif
#endif
};
}
#endif // _FAST_MUTEX_H_

@ -46,7 +46,6 @@ freely, subject to the following restrictions:
/// @li tthread::recursive_mutex /// @li tthread::recursive_mutex
/// @li tthread::condition_variable /// @li tthread::condition_variable
/// @li tthread::lock_guard /// @li tthread::lock_guard
/// @li tthread::fast_mutex
/// ///
/// @section misc_sec Miscellaneous /// @section misc_sec Miscellaneous
/// The following special keywords are available: #thread_local. /// The following special keywords are available: #thread_local.

@ -2,10 +2,16 @@
Compiling DFHack Compiling DFHack
################ ################
You don't need to compile DFHack unless you're developing plugins or working on the core. DFHack builds are available for all supported platforms; see `installing` for
installation instructions. If you are a DFHack end-user, modder, or plan on
writing scripts (not plugins), it is generally recommended (and easier) to use
these builds instead of compiling DFHack from source.
For users, modders, and authors of scripts it's better to download However, if you are looking to develop plugins, work on the DFHack core, make
and `install the latest release instead <installing>`. complex changes to DF-structures, or anything else that requires compiling
DFHack from source, this document will walk you through the build process. Note
that some steps may be unconventional compared to other projects, so be sure to
pay close attention if this is your first time compiling DFHack.
.. contents:: .. contents::
:depth: 2 :depth: 2
@ -14,35 +20,60 @@ and `install the latest release instead <installing>`.
How to get the code How to get the code
=================== ===================
DFHack doesn't have any kind of system of code snapshots in place, so you will have to DFHack uses Git for source control; instructions for installing Git can be found
get code from the GitHub repository using Git. How to get Git is described under in the platform-specific sections below. The code is hosted on
the instructions for each platform. `GitHub <https://github.com/DFHack/dfhack>`_, and can be downloaded with::
To get the latest release code (master branch)::
git clone --recursive https://github.com/DFHack/dfhack git clone --recursive https://github.com/DFHack/dfhack
cd dfhack cd dfhack
If your version of Git does not support the ``--recursive`` flag, you will need to omit it and run If your version of Git does not support the ``--recursive`` flag, you will need
``git submodule update --init`` after entering the dfhack directory. to omit it and run ``git submodule update --init`` after entering the dfhack
directory.
To get the latest development code (develop branch), clone as above and then:: This will check out the code on the default branch of the GitHub repo, currently
``develop``, which may be unstable. If you want code for the latest stable
release, you can check out the ``master`` branch instead::
git checkout develop git checkout master
git submodule update git submodule update
Generally, you should only need to clone DFHack once. In general, a single DFHack clone is suitable for development - most Git
operations such as switching branches can be done on an existing clone. If you
**Important note regarding submodule update after pulling or changing branches**: find yourself cloning DFHack frequently as part of your development process, or
getting stuck on anything else Git-related, feel free to reach out to us for
You must run ``git submodule update`` every time you change branches, such as assistance.
when switching between the master and develop branches or vice versa. You also
must run it after pulling any changes to submodules from the DFHack repo. If a .. admonition:: A note on submodules
submodule only exists on the newer branch, or if a commit you just pulled
contains a new submodule, you need to run ``git submodule update --init``. DFHack uses submodules extensively to manage its subprojects (including the
Failure to do this may result in a variety of errors, including ``fatal: <path> ``scripts`` folder and DF-structures in ``library/xml``). Failing to keep
does not exist`` when using Git, errors when building DFHack, and ``not a known submodules in sync when switching between branches can result in build errors
DF version`` when starting DF. or scripts that don't work. In general, you should always update submodules
whenever you switch between branches in the main DFHack repo with
``git submodule update``. (If you are working on bleeding-edge DFHack and
have checked out the master branch of some submodules, running ``git pull``
in those submodules is also an option.)
Rarely, we add or remove submodules. If there are any changes to the existence
of submodules when you switch between branches, you should run
``git submodule update --init`` instead (adding ``--init`` to the above
command).
Some common errors that can arise when failing to update submodules include:
* ``fatal: <some path> does not exist`` when performing Git operations
* Build errors, particularly referring to structures in the ``df::`` namespace
or the ``library/include/df`` folder
* ``Not a known DF version`` when starting DF
* ``Run 'git submodule update --init'`` when running CMake
Submodules are a particularly confusing feature of Git. The
`Git Book <https://git-scm.com/book/en/v2/Git-Tools-Submodules>`_ has a
thorough explanation of them (as well as of many other aspects of Git) and
is a recommended resource if you run into any issues. Other DFHack developers
are also able to help with any submodule-related (or Git-related) issues
you may encounter.
**More notes**: **More notes**:
@ -51,18 +82,21 @@ DF version`` when starting DF.
Contributing to DFHack Contributing to DFHack
====================== ======================
If you want to get involved with the development, create an account on To contribute to DFHack on GitHub, you will need a GitHub account. Only some
GitHub, make a clone there and then use that as your remote repository instead. DFHack developers can push directly to the DFHack repositories; we recommend
making a fork of whatever repos you are interested in contributing to, making
We'd love that; join us on IRC_ (#dfhack channel on freenode) for discussion, changes there, and submitting pull requests. `GitHub's pull request tutorial
and whenever you need help. <https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests>`_
is a good resource for getting started with pull requests (some things to note:
our work mainly happens on the ``develop`` branch, and you will need to use
your own fork, assuming that you don't have write access to the DFHack repos).
.. _IRC: https://webchat.freenode.net/?channels=dfhack Most development-related discussion happens on IRC or in individual GitHub
issues and pull requests, but there are also other ways to reach out - see
`support` for details.
(Note: for submodule issues, please see the above instructions first!) For more details on contributing to DFHack, including pull requests, code
format, and more, please see `contributing-code`.
For lots more details on contributing to DFHack, including pull requests, code format,
and more, please see `contributing-code`.
Build settings Build settings
@ -78,7 +112,8 @@ Generator
The ``Ninja`` CMake build generator is the prefered build method on Linux and The ``Ninja`` CMake build generator is the prefered build method on Linux and
macOS, instead of ``Unix Makefiles``, which is the default. You can select Ninja macOS, instead of ``Unix Makefiles``, which is the default. You can select Ninja
by passing ``-G Ninja`` to CMake. Incremental builds using Unix Makefiles can be by passing ``-G Ninja`` to CMake. Incremental builds using Unix Makefiles can be
much slower than Ninja builds. much slower than Ninja builds. Note that you will probably need to install
Ninja; see the platform-specific sections for details.
:: ::
@ -133,6 +168,9 @@ your build folder or by running ``ccmake`` (or another CMake GUI). Most
DFHack-specific settings begin with ``BUILD_`` and control which parts of DFHack DFHack-specific settings begin with ``BUILD_`` and control which parts of DFHack
are built. are built.
.. _compile-linux:
Linux Linux
===== =====
On Linux, DFHack acts as a library that shadows parts of the SDL API using LD_PRELOAD. On Linux, DFHack acts as a library that shadows parts of the SDL API using LD_PRELOAD.
@ -144,13 +182,18 @@ DFHack is meant to be installed into an existing DF folder, so get one ready.
We assume that any Linux platform will have ``git`` available (though it may We assume that any Linux platform will have ``git`` available (though it may
need to be installed with your package manager.) need to be installed with your package manager.)
To build DFHack you need GCC version 4.8 or later. GCC 4.8 is easiest to work To build DFHack, you need GCC 4.8 or newer. GCC 4.8 has the benefit of avoiding
with due to avoiding libstdc++ issues (see below), but any version from 4.8 `libstdc++ compatibility issues <linux-incompatible-libstdcxx>`, but can be hard
onwards (including 5.x) will work. to obtain on modern distributions, and working around these issues is done
automatically by the ``dfhack`` launcher script. As long as your system-provided
GCC is new enough, it should work. Note that extremely new GCC versions may not
have been used to build DFHack yet, so if you run into issues with these, please
let us know (e.g. by opening a GitHub issue).
Before you can build anything, you'll also need ``cmake``. It is advisable to Before you can build anything, you'll also need ``cmake``. It is advisable to
also get ``ccmake`` on distributions that split the cmake package into multiple also get ``ccmake`` on distributions that split the cmake package into multiple
parts. parts. As mentioned above, ``ninja`` is recommended (many distributions call
this package ``ninja-build``).
You will need pthread; most systems should have this already. Note that older You will need pthread; most systems should have this already. Note that older
CMake versions may have trouble detecting pthread, so if you run into CMake versions may have trouble detecting pthread, so if you run into
@ -226,37 +269,42 @@ This will show a curses-based interface that lets you set all of the
extra options. You can also use a cmake-friendly IDE like KDevelop 4 extra options. You can also use a cmake-friendly IDE like KDevelop 4
or the cmake-gui program. or the cmake-gui program.
.. _linux-incompatible-libstdcxx:
Incompatible libstdc++ Incompatible libstdc++
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
When compiling dfhack yourself, it builds against your system libstdc++. When When compiling DFHack yourself, it builds against your system libstdc++. When
Dwarf Fortress runs, it uses a libstdc++ shipped with the binary, which comes Dwarf Fortress runs, it uses a libstdc++ shipped in the ``libs`` folder, which
from GCC 4.8 and is incompatible with code compiled with newer GCC versions. If comes from GCC 4.8 and is incompatible with code compiled with newer GCC
you compile DFHack with a GCC version newer than 4.8, you will see an error versions. As of DFHack 0.42.05-alpha1, the ``dfhack`` launcher script attempts
message such as:: to fix this by automatically removing the DF-provided libstdc++ on startup.
In rare cases, this may fail and cause errors such as::
./libs/Dwarf_Fortress: /pathToDF/libs/libstdc++.so.6: version ./libs/Dwarf_Fortress: /pathToDF/libs/libstdc++.so.6: version
`GLIBCXX_3.4.18' not found (required by ./hack/libdfhack.so) `GLIBCXX_3.4.18' not found (required by ./hack/libdfhack.so)
To fix this you can compile with GCC 4.8 or remove the libstdc++ shipped with The easiest way to fix this is generally removing the libstdc++ shipped with
DF, which causes DF to use your system libstdc++ instead:: DF, which causes DF to use your system libstdc++ instead::
cd /path/to/DF/ cd /path/to/DF/
rm libs/libstdc++.so.6 rm libs/libstdc++.so.6
Note that distributing binaries compiled with newer GCC versions requires end- Note that distributing binaries compiled with newer GCC versions may result in
users to delete libstdc++ themselves and have a libstdc++ on their system from the opposite compatibily issue: users with *older* GCC versions may encounter
the same GCC version or newer. For this reason, distributing anything compiled similar errors. This is why DFHack distributes both GCC 4.8 and GCC 7 builds. If
with GCC versions newer than 4.8 is discouraged. In the future we may start you are planning on distributing binaries to other users, we recommend using an
bundling a later libstdc++ as part of the DFHack package, so as to enable older GCC (but still at least 4.8) version if possible.
compilation-for-distribution with a GCC newer than 4.8.
Mac OS X .. _compile-macos:
========
DFHack functions similarly on OS X and Linux, and the majority of the macOS
information above regarding the build process (cmake and ninja) applies here =====
DFHack functions similarly on macOS and Linux, and the majority of the
information above regarding the build process (CMake and Ninja) applies here
as well. as well.
DFHack can officially be built on OS X with GCC 4.8 or 7. Anything newer than 7 DFHack can officially be built on macOS only with GCC 4.8 or 7. Anything newer than 7
will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`),
and your build will likely not be redistributable. and your build will likely not be redistributable.
@ -309,7 +357,7 @@ Dependencies and system set-up
cleaner, quicker, and smarter. For example, installing MacPort's GCC will cleaner, quicker, and smarter. For example, installing MacPort's GCC will
install more than twice as many dependencies as Homebrew's will, and all in install more than twice as many dependencies as Homebrew's will, and all in
both 32-bit and 64-bit variants. Homebrew also doesn't require constant use both 32-bit and 64-bit variants. Homebrew also doesn't require constant use
of sudo. of ``sudo``.
Using `Homebrew <http://brew.sh/>`_ (recommended):: Using `Homebrew <http://brew.sh/>`_ (recommended)::
@ -378,9 +426,9 @@ Building
export CC=gcc-7 export CC=gcc-7
export CXX=g++-7 export CXX=g++-7
etc. (adjust as needed for different GCC installations)
* Build dfhack:: * Build DFHack::
mkdir build-osx mkdir build-osx
cd build-osx cd build-osx
@ -390,6 +438,7 @@ Building
<path to DF> should be a path to a copy of Dwarf Fortress, of the appropriate <path to DF> should be a path to a copy of Dwarf Fortress, of the appropriate
version for the DFHack you are building. version for the DFHack you are building.
.. _compile-windows: .. _compile-windows:
Windows Windows
@ -682,9 +731,9 @@ It may be installed in a directory such as ``~/.local/bin/``, so after pip
install, find ``sphinx-build`` and ensure its directory is in your local ``$PATH``. install, find ``sphinx-build`` and ensure its directory is in your local ``$PATH``.
Mac OS X macOS
-------- -----
OS X has Python 2.7 installed by default, but it does not have the pip package manager. macOS has Python 2.7 installed by default, but it does not have the pip package manager.
You can install Homebrew's Python 3, which includes pip, and then install the You can install Homebrew's Python 3, which includes pip, and then install the
latest Sphinx using pip:: latest Sphinx using pip::
@ -696,11 +745,11 @@ Alternatively, you can simply install Sphinx 1.3.x directly from Homebrew::
brew install sphinx-doc brew install sphinx-doc
This will install Sphinx for OS X's system Python 2.7, without needing pip. This will install Sphinx for macOS's system Python 2.7, without needing pip.
Either method works; if you plan to use Python for other purposes, it might best Either method works; if you plan to use Python for other purposes, it might best
to install Homebrew's Python 3 so that you have the latest Python as well as pip. to install Homebrew's Python 3 so that you have the latest Python as well as pip.
If not, just installing sphinx-doc for OS X's system Python 2.7 is fine. If not, just installing sphinx-doc for macOS's system Python 2.7 is fine.
Windows Windows
@ -767,7 +816,7 @@ files alphabetically, so all the files you need should be next to each other.
It is recommended that you create a build folder and run CMake to verify that It is recommended that you create a build folder and run CMake to verify that
you have downloaded everything at this point, assuming your download machine has you have downloaded everything at this point, assuming your download machine has
CMake installed. This involves running a "generate" batch script on Windows, or CMake installed. This involves running a "generate" batch script on Windows, or
a command starting with ``cmake .. -G Ninja`` on Linux and OS X, following the a command starting with ``cmake .. -G Ninja`` on Linux and macOS, following the
instructions in the sections above. CMake should automatically locate files that instructions in the sections above. CMake should automatically locate files that
you placed in ``CMake/downloads``, and use them instead of attempting to you placed in ``CMake/downloads``, and use them instead of attempting to
download them. download them.

@ -87,6 +87,7 @@ the console.
.. _troubleshooting: .. _troubleshooting:
.. _support:
Troubleshooting Troubleshooting
=============== ===============
@ -101,7 +102,7 @@ If the search function in this documentation isn't enough and
:wiki:`the DF Wiki <>` hasn't helped, try asking in: :wiki:`the DF Wiki <>` hasn't helped, try asking in:
- the `#dfhack IRC channel on freenode <https://webchat.freenode.net/?channels=dfhack>`_ - the `#dfhack IRC channel on freenode <https://webchat.freenode.net/?channels=dfhack>`_
- the :forums:`Bay12 DFHack thread <139553>` - the `Bay12 DFHack thread <https://dfhack.org/bay12>`_
- the `/r/dwarffortress <https://dwarffortress.reddit.com>`_ questions thread - the `/r/dwarffortress <https://dwarffortress.reddit.com>`_ questions thread
- the thread for the mod or Starter Pack you're using (if any) - the thread for the mod or Starter Pack you're using (if any)

@ -39,6 +39,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# Future # Future
## Fixes
- Fixed a segfault when attempting to start a headless session with a graphical PRINT_MODE setting
- `labormanager`: fixed handling of new jobs in 0.47
## Ruby
- Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens
# 0.47.04-r1 # 0.47.04-r1
## Fixes ## Fixes

@ -1422,6 +1422,28 @@ void struct_identity::build_metatable(lua_State *state)
SetPtrMethods(state, base+1, base+2); SetPtrMethods(state, base+1, base+2);
} }
void other_vectors_identity::build_metatable(lua_State *state)
{
int base = lua_gettop(state);
MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex);
EnableMetaField(state, base+2, "_enum");
LookupInTable(state, index_enum, &DFHACK_TYPEID_TABLE_TOKEN);
lua_setfield(state, base+1, "_enum");
auto keys = &index_enum->getKeys()[-index_enum->getFirstItem()];
for (int64_t i = 0; i < index_enum->getLastItem(); i++)
{
lua_getfield(state, base+2, keys[i]);
lua_rawseti(state, base+2, int(i));
}
SetStructMethod(state, base+1, base+2, meta_struct_field_reference, "_field");
SetPtrMethods(state, base+1, base+2);
}
void global_identity::build_metatable(lua_State *state) void global_identity::build_metatable(lua_State *state)
{ {
int base = lua_gettop(state); int base = lua_gettop(state);

@ -568,4 +568,16 @@ namespace DFHack
root->next = link; root->next = link;
} }
}; };
template<typename T, typename O, typename I>
struct DfOtherVectors
{
std::vector<I *> & operator[](O other_id)
{
CHECK_INVALID_ARGUMENT(size_t(other_id) < sizeof(T) / sizeof(std::vector<I *>));
auto vectors = reinterpret_cast<std::vector<I *> *>(this);
return vectors[other_id];
}
};
} }

@ -334,6 +334,23 @@ namespace DFHack
virtual identity_type type() { return IDTYPE_UNION; } virtual identity_type type() { return IDTYPE_UNION; }
}; };
class DFHACK_EXPORT other_vectors_identity : public struct_identity {
enum_identity *index_enum;
public:
other_vectors_identity(size_t size, TAllocateFn alloc,
compound_identity *scope_parent, const char *dfhack_name,
struct_identity *parent, const struct_field_info *fields,
enum_identity *index_enum) :
struct_identity(size, alloc, scope_parent, dfhack_name, parent, fields),
index_enum(index_enum)
{}
enum_identity *getIndexEnum() { return index_enum; }
virtual void build_metatable(lua_State *state);
};
#ifdef _MSC_VER #ifdef _MSC_VER
typedef void *virtual_ptr; typedef void *virtual_ptr;
#else #else
@ -465,6 +482,7 @@ namespace df
using DFHack::global_identity; using DFHack::global_identity;
using DFHack::struct_identity; using DFHack::struct_identity;
using DFHack::union_identity; using DFHack::union_identity;
using DFHack::other_vectors_identity;
using DFHack::struct_field_info; using DFHack::struct_field_info;
using DFHack::struct_field_info_extra; using DFHack::struct_field_info_extra;
using DFHack::bitfield_item_info; using DFHack::bitfield_item_info;
@ -474,6 +492,7 @@ namespace df
using DFHack::BitArray; using DFHack::BitArray;
using DFHack::DfArray; using DFHack::DfArray;
using DFHack::DfLinkedList; using DFHack::DfLinkedList;
using DFHack::DfOtherVectors;
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"

@ -1 +1 @@
Subproject commit b4dfab6d08635da8b01504a289e8cf4e62c859c5 Subproject commit cbeed8b52482ce749fc2ff13a9db9733931e7da0

@ -896,6 +896,10 @@ JobLaborMapper::JobLaborMapper()
job_to_labor_table[df::job_type::PutItemOnDisplay] = jlf_const(df::unit_labor::HAUL_ITEM); job_to_labor_table[df::job_type::PutItemOnDisplay] = jlf_const(df::unit_labor::HAUL_ITEM);
job_to_labor_table[df::job_type::StoreItemInLocation] = jlf_no_labor; // StoreItemInLocation job_to_labor_table[df::job_type::StoreItemInLocation] = jlf_no_labor; // StoreItemInLocation
job_to_labor_table[df::job_type::unk_fake_no_job] = jlf_no_labor; // added for 47.04 - see #1561
job_to_labor_table[df::job_type::InterrogateSubject] = jlf_no_labor; // added for 47.04 - see #1561
job_to_labor_table[df::job_type::unk_fake_no_activity] = jlf_no_labor; // added for 47.04 - see #1561
}; };
df::unit_labor JobLaborMapper::find_job_labor(df::job* j) df::unit_labor JobLaborMapper::find_job_labor(df::job* j)

@ -385,6 +385,9 @@ static const dwarf_state dwarf_states[] = {
BUSY /* MakeBracelet */, BUSY /* MakeBracelet */,
BUSY /* MakeGem */, BUSY /* MakeGem */,
BUSY /* PutItemOnDisplay */, BUSY /* PutItemOnDisplay */,
OTHER /* unk_fake_no_job */,
OTHER /* InterrogateSubject */,
OTHER /* unk_fake_no_activity */,
}; };
struct labor_info struct labor_info

@ -270,7 +270,7 @@ rgbf blend(const rgbf& a,const rgbf& b)
void lightingEngineViewscreen::clear() void lightingEngineViewscreen::clear()
{ {
lightMap.assign(lightMap.size(),rgbf(1,1,1)); lightMap.assign(lightMap.size(),rgbf(1,1,1));
tthread::lock_guard<tthread::fast_mutex> guard(myRenderer->dataMutex); std::lock_guard<std::mutex> guard{myRenderer->dataMutex};
if(lightMap.size()==myRenderer->lightGrid.size()) if(lightMap.size()==myRenderer->lightGrid.size())
{ {
std::swap(myRenderer->lightGrid,lightMap); std::swap(myRenderer->lightGrid,lightMap);
@ -299,7 +299,7 @@ void lightingEngineViewscreen::calculate()
} }
void lightingEngineViewscreen::updateWindow() void lightingEngineViewscreen::updateWindow()
{ {
tthread::lock_guard<tthread::fast_mutex> guard(myRenderer->dataMutex); std::lock_guard<std::mutex> guard{myRenderer->dataMutex};
if(lightMap.size()!=myRenderer->lightGrid.size()) if(lightMap.size()!=myRenderer->lightGrid.size())
{ {
reinit(); reinit();

@ -1,11 +1,14 @@
#ifndef RENDERER_LIGHT_INCLUDED #pragma once
#define RENDERER_LIGHT_INCLUDED
#include "renderer_opengl.hpp"
#include "Types.h"
#include <tuple>
#include <stack>
#include <memory> #include <memory>
#include <mutex>
#include <stack>
#include <tuple>
#include <unordered_map> #include <unordered_map>
#include "renderer_opengl.hpp"
#include "Types.h"
// we are not using boost so let's cheat: // we are not using boost so let's cheat:
template <class T> template <class T>
inline void hash_combine(std::size_t & seed, const T & v) inline void hash_combine(std::size_t & seed, const T & v)
@ -91,7 +94,7 @@ private:
} }
void reinitLightGrid(int w,int h) void reinitLightGrid(int w,int h)
{ {
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
lightGrid.resize(w*h,rgbf(1,1,1)); lightGrid.resize(w*h,rgbf(1,1,1));
} }
void reinitLightGrid() void reinitLightGrid()
@ -100,7 +103,7 @@ private:
} }
public: public:
tthread::fast_mutex dataMutex; std::mutex dataMutex;
std::vector<rgbf> lightGrid; std::vector<rgbf> lightGrid;
renderer_light(renderer* parent):renderer_wrap(parent),light_adaptation(1) renderer_light(renderer* parent):renderer_wrap(parent),light_adaptation(1)
{ {
@ -108,12 +111,12 @@ public:
} }
virtual void update_tile(int32_t x, int32_t y) { virtual void update_tile(int32_t x, int32_t y) {
renderer_wrap::update_tile(x,y); renderer_wrap::update_tile(x,y);
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
colorizeTile(x,y); colorizeTile(x,y);
}; };
virtual void update_all() { virtual void update_all() {
renderer_wrap::update_all(); renderer_wrap::update_all();
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
for (int x = 0; x < df::global::gps->dimx; x++) for (int x = 0; x < df::global::gps->dimx; x++)
for (int y = 0; y < df::global::gps->dimy; y++) for (int y = 0; y < df::global::gps->dimy; y++)
colorizeTile(x,y); colorizeTile(x,y);
@ -374,4 +377,3 @@ private:
}; };
rgbf blend(const rgbf& a,const rgbf& b); rgbf blend(const rgbf& a,const rgbf& b);
rgbf blendMax(const rgbf& a,const rgbf& b); rgbf blendMax(const rgbf& a,const rgbf& b);
#endif

@ -1,9 +1,7 @@
//original file from https://github.com/Baughn/Dwarf-Fortress--libgraphics- //original file from https://github.com/Baughn/Dwarf-Fortress--libgraphics-
#ifndef RENDERER_OPENGL_INCLUDED #pragma once
#define RENDERER_OPENGL_INCLUDED
#include "tinythread.h" #include "tinythread.h"
#include "fast_mutex.h"
#include "Core.h" #include "Core.h"
#include <VTableInterpose.h> #include <VTableInterpose.h>
@ -15,6 +13,7 @@
#include "df/graphic.h" #include "df/graphic.h"
#include <math.h> #include <math.h>
#include <cmath> #include <cmath>
#include <mutex>
using df::renderer; using df::renderer;
using df::init; using df::init;
@ -281,7 +280,7 @@ private:
} }
void reinitLightGrid(int w,int h) void reinitLightGrid(int w,int h)
{ {
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
lightGrid.resize(w*h); lightGrid.resize(w*h);
} }
void reinitLightGrid() void reinitLightGrid()
@ -289,7 +288,7 @@ private:
reinitLightGrid(df::global::gps->dimy,df::global::gps->dimx); reinitLightGrid(df::global::gps->dimy,df::global::gps->dimx);
} }
public: public:
tthread::fast_mutex dataMutex; std::mutex dataMutex;
std::vector<rgbf> lightGrid; std::vector<rgbf> lightGrid;
renderer_test(renderer* parent):renderer_wrap(parent) renderer_test(renderer* parent):renderer_wrap(parent)
{ {
@ -297,14 +296,14 @@ public:
} }
virtual void update_tile(int32_t x, int32_t y) { virtual void update_tile(int32_t x, int32_t y) {
renderer_wrap::update_tile(x,y); renderer_wrap::update_tile(x,y);
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
colorizeTile(x,y); colorizeTile(x,y);
//some sort of mutex or sth? //some sort of mutex or sth?
//and then map read //and then map read
}; };
virtual void update_all() { virtual void update_all() {
renderer_wrap::update_all(); renderer_wrap::update_all();
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
for (int x = 0; x < df::global::gps->dimx; x++) for (int x = 0; x < df::global::gps->dimx; x++)
for (int y = 0; y < df::global::gps->dimy; y++) for (int y = 0; y < df::global::gps->dimy; y++)
colorizeTile(x,y); colorizeTile(x,y);
@ -366,7 +365,7 @@ private:
} }
void reinitGrids(int w,int h) void reinitGrids(int w,int h)
{ {
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
foreOffset.resize(w*h); foreOffset.resize(w*h);
foreMult.resize(w*h); foreMult.resize(w*h);
backOffset.resize(w*h); backOffset.resize(w*h);
@ -377,7 +376,7 @@ private:
reinitGrids(df::global::gps->dimy,df::global::gps->dimx); reinitGrids(df::global::gps->dimy,df::global::gps->dimx);
} }
public: public:
tthread::fast_mutex dataMutex; std::mutex dataMutex;
std::vector<rgbf> foreOffset,foreMult; std::vector<rgbf> foreOffset,foreMult;
std::vector<rgbf> backOffset,backMult; std::vector<rgbf> backOffset,backMult;
inline int xyToTile(int x, int y) inline int xyToTile(int x, int y)
@ -390,14 +389,14 @@ public:
} }
virtual void update_tile(int32_t x, int32_t y) { virtual void update_tile(int32_t x, int32_t y) {
renderer_wrap::update_tile(x,y); renderer_wrap::update_tile(x,y);
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
overwriteTile(x,y); overwriteTile(x,y);
//some sort of mutex or sth? //some sort of mutex or sth?
//and then map read //and then map read
}; };
virtual void update_all() { virtual void update_all() {
renderer_wrap::update_all(); renderer_wrap::update_all();
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex); std::lock_guard<std::mutex> guard{dataMutex};
for (int x = 0; x < df::global::gps->dimx; x++) for (int x = 0; x < df::global::gps->dimx; x++)
for (int y = 0; y < df::global::gps->dimy; y++) for (int y = 0; y < df::global::gps->dimy; y++)
overwriteTile(x,y); overwriteTile(x,y);
@ -414,4 +413,3 @@ public:
reinitGrids(w,h); reinitGrids(w,h);
} }
}; };
#endif

@ -1,27 +1,23 @@
#include <vector> #include <mutex>
#include <sstream>
#include <string> #include <string>
#include <vector>
#include <LuaTools.h>
#include <VTableInterpose.h>
#include "Core.h"
#include "Console.h" #include "Console.h"
#include "Core.h"
#include "Export.h" #include "Export.h"
#include "LuaTools.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "VTableInterpose.h"
#include <VTableInterpose.h>
#include "df/renderer.h"
#include "df/enabler.h" #include "df/enabler.h"
#include "df/renderer.h"
#include "df/viewscreen_dungeonmodest.h"
#include "df/viewscreen_dwarfmodest.h"
#include "renderer_opengl.hpp" #include "renderer_opengl.hpp"
#include "renderer_light.hpp" #include "renderer_light.hpp"
#include "df/viewscreen_dwarfmodest.h"
#include "df/viewscreen_dungeonmodest.h"
#include <sstream>
using df::viewscreen_dungeonmodest; using df::viewscreen_dungeonmodest;
using df::viewscreen_dwarfmodest; using df::viewscreen_dwarfmodest;
@ -367,7 +363,7 @@ static command_result rendermax(color_ostream &out, vector <string> & parameters
cur=blue; cur=blue;
renderer_test* r=reinterpret_cast<renderer_test*>(enabler->renderer); renderer_test* r=reinterpret_cast<renderer_test*>(enabler->renderer);
tthread::lock_guard<tthread::fast_mutex> guard(r->dataMutex); std::lock_guard<std::mutex> guard{r->dataMutex};
int h=gps->dimy; int h=gps->dimy;
int w=gps->dimx; int w=gps->dimx;
int cx=w/2; int cx=w/2;

@ -240,6 +240,12 @@ sub render_global_class {
} }
my $rbparent = ($parent ? rb_ucase($parent) : 'MemHack::Compound'); my $rbparent = ($parent ? rb_ucase($parent) : 'MemHack::Compound');
my $ienum;
if (($type->getAttribute('ld:subtype') or '') eq 'df-other-vectors-type')
{
$rbparent = 'MemHack::OtherVectors';
$ienum = rb_ucase($type->getAttribute('index-enum'));
}
push @lines_rb, "class $rbname < $rbparent"; push @lines_rb, "class $rbname < $rbparent";
indent_rb { indent_rb {
my $sz = sizeof($type); my $sz = sizeof($type);
@ -249,6 +255,8 @@ sub render_global_class {
push @lines_rb, "rtti_classname :$rtti_name\n" if $rtti_name; push @lines_rb, "rtti_classname :$rtti_name\n" if $rtti_name;
push @lines_rb, "ienum $ienum\n" if $ienum;
render_struct_fields($type); render_struct_fields($type);
my $vms = $type->findnodes('child::virtual-methods')->[0]; my $vms = $type->findnodes('child::virtual-methods')->[0];

@ -205,6 +205,22 @@ module DFHack
end end
end end
class OtherVectors < Compound
class << self
attr_accessor :_enum
def ienum(enum)
@_enum = enum
end
end
def [](i)
self.send(self.class._enum.sym(i))
end
def []=(i, v)
self.send((self.class._enum.sym(i).to_s + "=").to_sym, v)
end
end
class Enum class Enum
# number -> symbol # number -> symbol
def self.enum def self.enum

@ -1 +1 @@
Subproject commit b9fc28836f34f7ce1be64de94afd90184a341c7d Subproject commit 5b7e7743a1372b929acb2ccb75080e139ac11691