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

develop
PatrikLundell 2020-04-08 08:35:58 +02:00
commit 5ce84a76f9
12 changed files with 224 additions and 32 deletions

3
.gitignore vendored

@ -51,6 +51,9 @@ build/CPack*Config.cmake
*.swp
.vimrc
# VSCode files
.vscode
# ctags file
tags

@ -81,6 +81,7 @@ Mason11987 Mason11987
Matt Regul mattregul
Matthew Cline
Matthew Lindner mlindner
Matthew Taylor ymber yutna
Max maxthyme Max^TM
McArcady McArcady
melkor217 melkor217
@ -150,6 +151,7 @@ thefriendlyhacker thefriendlyhacker
TheHologram TheHologram
therahedwig therahedwig
ThiagoLira ThiagoLira
thurin thurin
Tim Walberg twalberg
Timothy Collett danaris
Timur Kelman TymurGubayev

@ -39,6 +39,12 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# Future
## Fixes
- `tweak` embark-profile-name: fixed handling of the native shift+space key
## Lua
- ``pairs()`` now returns available class methods for DF types
# 0.47.04-beta1
## Fixes

@ -1608,8 +1608,8 @@ static void RenderType(lua_State *state, compound_identity *node)
lua_dup(state);
lua_setfield(state, ix_meta, "__index");
// pairs table
lua_newtable(state);
// pairs table - reuse index table
lua_dup(state);
int ptable = base+4;
lua_pushvalue(state, ptable);

@ -68,6 +68,8 @@ namespace DFHack
IDTYPE_UNION
};
// pointer flags (bitfield), stored in the count field of struct_field_info
// if mode is POINTER.
enum pointer_identity_flags {
PTRFLAG_IS_ARRAY = 1,
PTRFLAG_HAS_BAD_POINTERS = 2,
@ -164,7 +166,12 @@ namespace DFHack
// Bitfields
struct bitfield_item_info {
// the name of the field, or null if the field is unnamed
const char *name;
// size is positive for defined fields, zero for bits past the end
// of the field, and negative for padding on multi-bit fields
//
// ex. if bits[2].size is -2, then bits[0].size is at least 3
int size;
};

@ -1 +1 @@
Subproject commit d51a1c4ca36731db62517b699fddd2c011e6bc99
Subproject commit b585e182c404a14130d42bf87a60f94aebbfd1fd

@ -1,22 +1,24 @@
#include "df/viewscreen_setupdwarfgamest.h"
using namespace DFHack;
struct embark_profile_name_hook : df::viewscreen_setupdwarfgamest {
typedef df::viewscreen_setupdwarfgamest interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set<df::interface_key> *input))
{
DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set<df::interface_key> *input)) {
int ch = -1;
for (auto it = input->begin(); ch == -1 && it != input->end(); ++it)
for (auto it = input->begin(); ch == -1 && it != input->end(); ++it) {
ch = Screen::keyToChar(*it);
if (in_save_profile && ch >= 32 && ch <= 126)
{
profile_name.push_back((char)ch);
}
else
{
if (input->count(df::interface_key::LEAVESCREEN))
// Intercept all printable characters except space.
// If space is intercepted the shift-space abort key will not work.
if (in_save_profile && ch >= 33 && ch <= 126) {
profile_name.push_back((char)ch);
} else {
if (input->count(df::interface_key::LEAVESCREEN)) {
input->insert(df::interface_key::SETUPGAME_SAVE_PROFILE_ABORT);
}
INTERPOSE_NEXT(feed)(input);
}
}
};
IMPLEMENT_VMETHOD_INTERPOSE(embark_profile_name_hook, feed);

@ -1 +1 @@
Subproject commit e336520c09dbcd55bb9f7b3ca837d102a9026acf
Subproject commit 8618cd0b0a17935fe07f329b249726cda61f5bdf

@ -13,3 +13,30 @@ function test.OrderedTable()
i = i + 1
end
end
function test.invert()
local t = {}
local i = utils.invert{'a', 4.4, false, true, 5, t}
expect.eq(i.a, 1)
expect.eq(i[4.4], 2)
expect.eq(i[false], 3)
expect.eq(i[true], 4)
expect.eq(i[5], 5)
expect.eq(i[t], 6)
expect.eq(i[700], nil)
expect.eq(i.foo, nil)
expect.eq(i[{}], nil)
end
function test.invert_nil()
local i = utils.invert{'a', nil, 'b'}
expect.eq(i.a, 1)
expect.eq(i[nil], nil)
expect.eq(i.b, 3)
end
function test.invert_overwrite()
local i = utils.invert{'a', 'b', 'a'}
expect.eq(i.b, 2)
expect.eq(i.a, 3)
end

@ -13,14 +13,20 @@ local TestStatus = {
FAILED = 'failed',
}
local VALID_MODES = utils.invert{'none', 'fortress'}
local VALID_MODES = utils.invert{'none', 'title', 'fortress'}
expect = {}
function expect.true_(value, comment)
return not not value, comment, 'expected true'
return not not value, comment, 'expected true, got ' .. tostring(value)
end
function expect.false_(value, comment)
return not value, comment, 'expected false'
return not value, comment, 'expected false, got ' .. tostring(value)
end
function expect.fail(comment)
return false, comment or 'check failed, no reason provided'
end
function expect.nil_(value, comment)
return value == nil, comment, 'expected nil, got ' .. tostring(value)
end
function expect.eq(a, b, comment)
return a == b, comment, ('%s ~= %s'):format(a, b)
@ -63,12 +69,53 @@ function expect.error(func, ...)
return true
end
end
function expect.pairs_contains(table, key, comment)
for k, v in pairs(table) do
if k == key then
return true
end
end
return false, comment, ('could not find key "%s" in table'):format(key)
end
function expect.not_pairs_contains(table, key, comment)
for k, v in pairs(table) do
if k == key then
return false, comment, ('found key "%s" in table'):format(key)
end
end
return true
end
function delay(frames)
frames = frames or 1
script.sleep(frames, 'frames')
end
function ensure_title_screen()
if df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then
return
end
print('Looking for title screen...')
for i = 0, 100 do
local scr = dfhack.gui.getCurViewscreen()
if df.viewscreen_titlest:is_instance(scr) then
print('Found title screen')
break
else
scr:feed_key(df.interface_key.LEAVESCREEN)
delay(10)
end
end
if not df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then
error('Could not find title screen')
end
end
local MODE_NAVIGATE_FNS = {
none = function() end,
title = ensure_title_screen,
}
function load_test_config(config_file)
local config = {}
if dfhack.filesystem.isfile(config_file) then
@ -166,7 +213,7 @@ function load_tests(file, tests)
return false
else
if not VALID_MODES[env.config.mode] then
dfhack.printerr('Invalid config.mode: ' .. env.config.mode)
dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode))
return false
end
for name, test_func in pairs(env.test) do
@ -184,6 +231,18 @@ function load_tests(file, tests)
return true
end
function sort_tests(tests)
-- to make sort stable
local test_index = utils.invert(tests)
table.sort(tests, function(a, b)
if a.config.mode ~= b.config.mode then
return VALID_MODES[a.config.mode] < VALID_MODES[b.config.mode]
else
return test_index[a] < test_index[b]
end
end)
end
function run_test(test, status, counts)
test.private.checks = 0
test.private.checks_ok = 0
@ -217,20 +276,7 @@ function main()
}
local passed = true
print('Looking for title screen...')
for i = 0, 100 do
local scr = dfhack.gui.getCurViewscreen()
if df.viewscreen_titlest:is_instance(scr) then
print('Found title screen')
break
else
scr:feed_key(df.interface_key.LEAVESCREEN)
delay(10)
end
end
if not df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then
qerror('Could not find title screen')
end
ensure_title_screen()
print('Loading tests')
local tests = {}
@ -263,9 +309,11 @@ function main()
table.remove(tests, i)
end
end
sort_tests(tests)
print('Running ' .. #tests .. ' tests')
for _, test in pairs(tests) do
MODE_NAVIGATE_FNS[test.config.mode]()
local passed = run_test(test, status, counts)
status[test.full_name] = passed and TestStatus.PASSED or TestStatus.FAILED
save_test_status(status)

@ -0,0 +1,32 @@
config = {
mode = 'title',
}
local function clean_vec(vec)
while #vec > 0 do
if vec[0] then
expect.true_(vec[0]:delete())
end
vec:erase(0)
end
end
local function with_clean_vec(cls, callback)
local vec = cls.get_vector()
dfhack.call_with_finalizer(1, true, clean_vec, vec, callback, vec)
end
function test.image_set()
-- todo: expand to other types?
with_clean_vec(df.image_set, function(vec)
vec:insert('#', {new = df.image_set, id = 1})
vec:insert('#', {new = df.image_set, id = 2})
vec:insert('#', {new = df.image_set, id = 4})
expect.eq(df.image_set.find(1).id, 1)
expect.eq(df.image_set.find(2).id, 2)
expect.eq(df.image_set.find(4).id, 4)
expect.nil_(df.image_set.find(3))
expect.nil_(df.image_set.find(5))
expect.nil_(df.image_set.find(-1))
end)
end

@ -0,0 +1,65 @@
function test.struct()
expect.eq(df.coord._kind, 'struct-type')
expect.eq(tostring(df.coord), '<type: coord>')
expect.eq(getmetatable(df.coord), 'coord')
expect.pairs_contains(df.coord, 'new')
expect.pairs_contains(df.coord, 'is_instance')
expect.pairs_contains(df.coord, 'sizeof')
end
function test.class()
expect.eq(df.viewscreen._kind, 'class-type')
expect.eq(tostring(df.viewscreen), '<type: viewscreen>')
expect.eq(getmetatable(df.viewscreen), 'viewscreen')
expect.pairs_contains(df.viewscreen, 'new')
expect.pairs_contains(df.viewscreen, 'is_instance')
expect.pairs_contains(df.viewscreen, 'sizeof')
end
function test.enum()
expect.eq(df.interface_key._kind, 'enum-type')
expect.eq(tostring(df.interface_key), '<type: interface_key>')
expect.eq(getmetatable(df.interface_key), 'interface_key')
expect.pairs_contains(df.interface_key, 'new')
expect.pairs_contains(df.interface_key, 'is_instance')
expect.pairs_contains(df.interface_key, 'sizeof')
end
function test.bitfield()
expect.eq(df.item_flags._kind, 'bitfield-type')
expect.eq(tostring(df.item_flags), '<type: item_flags>')
expect.eq(getmetatable(df.item_flags), 'item_flags')
expect.pairs_contains(df.item_flags, 'new')
expect.pairs_contains(df.item_flags, 'is_instance')
expect.pairs_contains(df.item_flags, 'sizeof')
end
function test.global()
expect.eq(df.global._kind, 'global')
expect.eq(tostring(df.global), '<type: global>')
expect.eq(getmetatable(df.global), 'global')
expect.not_pairs_contains(df.global, 'new')
expect.not_pairs_contains(df.global, 'is_instance')
expect.not_pairs_contains(df.global, 'sizeof')
end
function test.unit()
expect.pairs_contains(df.unit, 'new')
expect.pairs_contains(df.unit, 'is_instance')
expect.pairs_contains(df.unit, 'sizeof')
expect.pairs_contains(df.unit, 'find')
expect.pairs_contains(df.unit, 'get_vector')
expect.pairs_contains(df.unit, '_kind')
if df.unit.T_job then
expect.pairs_contains(df.unit, 'T_job')
expect.pairs_contains(df.unit.T_job, 'new')
expect.pairs_contains(df.unit.T_job, 'is_instance')
expect.pairs_contains(df.unit.T_job, 'sizeof')
expect.not_pairs_contains(df.unit.T_job, 'find')
expect.not_pairs_contains(df.unit.T_job, 'get_vector')
expect.pairs_contains(df.unit.T_job, '_kind')
else
expect.fail('unit.T_job not defined; unit has changed')
end
end