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 *.swp
.vimrc .vimrc
# VSCode files
.vscode
# ctags file # ctags file
tags tags

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

@ -39,6 +39,12 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# Future # 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 # 0.47.04-beta1
## Fixes ## Fixes

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

@ -68,6 +68,8 @@ namespace DFHack
IDTYPE_UNION IDTYPE_UNION
}; };
// pointer flags (bitfield), stored in the count field of struct_field_info
// if mode is POINTER.
enum pointer_identity_flags { enum pointer_identity_flags {
PTRFLAG_IS_ARRAY = 1, PTRFLAG_IS_ARRAY = 1,
PTRFLAG_HAS_BAD_POINTERS = 2, PTRFLAG_HAS_BAD_POINTERS = 2,
@ -164,7 +166,12 @@ namespace DFHack
// Bitfields // Bitfields
struct bitfield_item_info { struct bitfield_item_info {
// the name of the field, or null if the field is unnamed
const char *name; 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; int size;
}; };

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

@ -1,22 +1,24 @@
#include "df/viewscreen_setupdwarfgamest.h" #include "df/viewscreen_setupdwarfgamest.h"
using namespace DFHack;
struct embark_profile_name_hook : df::viewscreen_setupdwarfgamest { struct embark_profile_name_hook : df::viewscreen_setupdwarfgamest {
typedef df::viewscreen_setupdwarfgamest interpose_base; 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; 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); ch = Screen::keyToChar(*it);
if (in_save_profile && ch >= 32 && ch <= 126)
{
profile_name.push_back((char)ch);
} }
else // Intercept all printable characters except space.
{ // If space is intercepted the shift-space abort key will not work.
if (input->count(df::interface_key::LEAVESCREEN)) 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); input->insert(df::interface_key::SETUPGAME_SAVE_PROFILE_ABORT);
}
INTERPOSE_NEXT(feed)(input); INTERPOSE_NEXT(feed)(input);
} }
} }
}; };
IMPLEMENT_VMETHOD_INTERPOSE(embark_profile_name_hook, feed); 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 i = i + 1
end end
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', FAILED = 'failed',
} }
local VALID_MODES = utils.invert{'none', 'fortress'} local VALID_MODES = utils.invert{'none', 'title', 'fortress'}
expect = {} expect = {}
function expect.true_(value, comment) function expect.true_(value, comment)
return not not value, comment, 'expected true' return not not value, comment, 'expected true, got ' .. tostring(value)
end end
function expect.false_(value, comment) 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 end
function expect.eq(a, b, comment) function expect.eq(a, b, comment)
return a == b, comment, ('%s ~= %s'):format(a, b) return a == b, comment, ('%s ~= %s'):format(a, b)
@ -63,12 +69,53 @@ function expect.error(func, ...)
return true return true
end end
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) function delay(frames)
frames = frames or 1 frames = frames or 1
script.sleep(frames, 'frames') script.sleep(frames, 'frames')
end 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) function load_test_config(config_file)
local config = {} local config = {}
if dfhack.filesystem.isfile(config_file) then if dfhack.filesystem.isfile(config_file) then
@ -166,7 +213,7 @@ function load_tests(file, tests)
return false return false
else else
if not VALID_MODES[env.config.mode] then 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 return false
end end
for name, test_func in pairs(env.test) do for name, test_func in pairs(env.test) do
@ -184,6 +231,18 @@ function load_tests(file, tests)
return true return true
end 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) function run_test(test, status, counts)
test.private.checks = 0 test.private.checks = 0
test.private.checks_ok = 0 test.private.checks_ok = 0
@ -217,20 +276,7 @@ function main()
} }
local passed = true local passed = true
print('Looking for title screen...') ensure_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
print('Loading tests') print('Loading tests')
local tests = {} local tests = {}
@ -263,9 +309,11 @@ function main()
table.remove(tests, i) table.remove(tests, i)
end end
end end
sort_tests(tests)
print('Running ' .. #tests .. ' tests') print('Running ' .. #tests .. ' tests')
for _, test in pairs(tests) do for _, test in pairs(tests) do
MODE_NAVIGATE_FNS[test.config.mode]()
local passed = run_test(test, status, counts) local passed = run_test(test, status, counts)
status[test.full_name] = passed and TestStatus.PASSED or TestStatus.FAILED status[test.full_name] = passed and TestStatus.PASSED or TestStatus.FAILED
save_test_status(status) 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