BugFix: Fix original coding errors creating data in TArea::exits member#219
BugFix: Fix original coding errors creating data in TArea::exits member#219SlySven merged 4 commits intoMudlet:developmentfrom
Conversation
|
Any one have any objections to merging this? |
|
Sorry, I have not reviewed this yet! I would like to when I can. |
|
This is so verbose....can you simply say if it's a bug fix and if it Sent from my phone.
|
|
Yes - it fixes the specific bug - but theoretically anyone relying on the data involved (which I don't think there can be) should run auditAreas() to fix it up on existing maps. I apologise if I seem to go on a bit in commit comments but that does seem to be the place to leave anything that a change-log or other reviewing process might need. |
|
I have to agree, this information is useful to know. On Wed, Nov 12, 2014 at 10:24 AM, Stephen Lyons notifications@github.com
|
|
It is still weird is best I can describe it. At first I loaded the map (get it here) and only got this result for area 44:
Which is a valid area exit room, but there are more than that. Then I did a pathfind, and the result changed to:
Which includes non-area exits like 11841. The actual list is:
Which is generated by this Lua-side function: Also what does |
|
This doesn't fix getAreaExits() but does fix auditAreas(), so +1. |
|
Since this is a broken function, let's make the output better. A table with exit rooms as keys and the room they go to as value? |
|
Well since I've got a better idea about Lua tables now (thanks to that gitter hint) I'll tack something on, but I think directions will be the keys. Of course it can be the case that one exit room has multiple exits in different directions to either the same or different rooms. Though since Mudlet doesn't have separate "name" and "command" items for Special Exits c.f. TinTin++ where an exit has something you type to use it - which for "normal" exits is just something like "e" or "ne" but could also be say what we have as a "special" exit "jump out" which is separate from the "command" that is sent to the MUD server - the key could become a long lua script... |
|
One room can go to several different areas though, which complicates it. Just an indexed list of the room id's or a key-value list with the room id and room name will be enough. |
|
For possible future work on chunked path-finding, a key-value pair of from->to is better. I implemented as such, though this pull is needed for it to work as well, along with a map version increase. |
|
From a room to a room? But a room can have several exits leading to other |
|
Is there anything else that we want to bring in with a map file format increment?
|
|
Nothing else, since this commit needs to go into 3.0 and 3.0 is frozen for new features - we're just trying to fix all the new issues introduced and get it released. |
|
@SlySven Just a version # increase to 17 and rerun initAreasForOldMaps if version < 17 (look at the code in TMap::init) |
|
Yeah, that initAreasForOldMaps() (run by TMap::init() for map file formats less than 15 IIRC) runs the same bit of code needed as the lua auditAreas() does - the downside of incrementing the map file version being that shared/crowd sourced maps then become unusable to anyone not using the beta at this point in time. Whereas implementing the code in this PR so far and advising users to use "lua auditAreas()" once on existing maps (and subsequently each time they use their map on the Mudlet application built on this or later code if it has been touched by an earlier Mudlet application instance) may be less disruptive at this point in the release process. I'd prefer to combine the auto map data fixup with the next other change that forces a map version increment unless you really,really want it done with such an increment now Chris ❓ |
|
I have no idea how the crowd sourced maps work. How are they updated? If someone does the lua auditAreas(), then uploads that map, it would be the same problem, correct? |
|
If you increment the version number, you increment the Mudlet version dependency. This means that if the person doing the mapping upgrades to a new Mudlet, nobody else on the old Mudlet can use the map. So ideally, this happens fewest times possible because it's a pita for everyone involved because of the abscence of forward compatibility. Just run the map fix thing automatically, no need to actually change the map format until the 'magic numbers' come in, yeah? Which we can bundle with something else since very, very few people are actually going to be making use of that feature. |
|
Sounds good @vadi2 . If they are adding a new feature, they can do the run. Here's another idea then as well -- how about a mudlet version/map version fetcher for lua so scripts can run any migration code that is needed. To make it easier we can even bundle it in LuaGlobal (or whatever) so there aren't 15 different migration scripts. @SlySven Do you want to change the mapping to: or you can merge this and I'll change that code with getAreaExits fix. |
|
Do you mean QMap > or something else, you keep mentioning it and it seems something is getting cut off. |
|
The issue is forward compatibility, old Mudlet can't load the a binary map from a newer Mudlet - not sure Lua scripts can do much here. |
|
yeah, it's the markup. |
|
Well we can't change the exits variable without a version increase, since the new map will be storing the information differently and importing the old map will throw an error. We can address this by a new variable, or a version increase. I don't like having cruft hanging around, but for backwards compatibility I suppose a new variable is the only way. |
|
To clear up any potential confusion - Any newer Mudlet can load any older map version (and then it saves it in the current map format) So the practical effect is that we can change the map version format, just not very often, because upgrading Mudlet isn't that seamless (as say the self-updating Chrome). As soon as the person doing the map upgrades (after holding out appropriately long and missing out on the new features) upgrades, everyone else on the older versions has to. |
|
I'm going to merge this in then because I like what's been done for the exit mapping and the actual code is cleaner. But I'm going to make new versions of mudlet empty the exits table since it's useless overhead (but still there/saved for compatibility) with a warning in the code of why there's a dead variable hanging around. We can revisit it at a later Mudlet. A good lesson in how wise it is to put data structures that are wrong/may change in the map file. |
|
Didn't @SlySven mention this has an issue of only allowing 1 special exit between two rooms? |
|
It does. If @SlySven doesn't mind, I'll pull this locally and submit a new PR with the faulty exits being removed and a new exit mapping being created. |
|
@Chris7 This latest commit should sort things out - it provides an additional TArea Class method to massage the area exit data to the wanted QMap<(int)fromRomId, QPair<(QString)direction, (int)toRoomId> > and uses it when TLuaInterpreter::getAreaExits() is called with a second optional boolean argument set to true. I think this will render #225 redundant. 😄 I anticipate that this will/can be revisited when/if we restructure the TRoom::other member to use the exit direction as the key instead of the toRoomId. It also renames those areaExits finding methods to something in English! |
src/TMap.cpp
Outdated
There was a problem hiding this comment.
Does this show up in the errors view or the main view?
There was a problem hiding this comment.
Ah, the main console (as part of the map loading), using the same system as the one that report the Lua modules loaded directly from C++ code and not via LuaGlobal.lua - partly because if the profile is being auto-loaded the messages could be lost otherwise and the user will want to fix the problems ones (and might want to know about the one-time conversion that is taking place for the non-problem one...)
Just noted that I've messed up the qApp->tr() should be qApp->translate() - it'll compile as is but the arguments will be wrong as they are used here - just going to amend last commit.
There was a problem hiding this comment.
I don't think the common user wants to know about this internal map file data stuff. At most it should go into the errors view where the technical one would look.
|
How do you think I should best present the directions in the detailed output for that lua function? 😕 |
|
Same way as http://wiki.mudlet.org/w/Manual:Mapper_Functions#getRoomExits does, without the translation stuff as it has. |
|
Can I make the defensive point that just because a string is marked as being a candidate for translation that it does not have to be translated, we are perfectly at liberty to leave the "translated" version to be the same as the source when Qt Linguist is used - or indeed the person doing it could produce two translations to ship: one with the lua API using the US English form and one completely rendered in their mother tongue - it may be that we recommend the former but a section of users might wish to go all the way (possibly at their own effort) with the latter. This, I would imagine, could be a selling point for some countries (somehow I keep thinking of France for some reason, of course they'd be wanting the cardinal compass points to be n,e,s,o !) For the moment I see that we'd get what you describe if I took the hyphens out of the diagonals... |
|
I don't think APIs in other languages are an idea that took off. Microsoft has translated APIs with Excel formula names I know, and as far as I can see that just makes coding harder for everyone involved. The other issue is adding this stuff doesn't guarantee that's what we'll end up with once we decide to take it seriously. So why have half of the stuff translatable in various different forms only for us to decide on something and have to go through and fix everything? Makes more sense to put it off until we're ready to tackle it, form a strategy and apply it. |
…ember
The specification for this member is:
QMultiMap<int, QPair<int, int> > exits
and it is a record of the rooms that are on border on the TArea instance.
The outer QMultiMap key is the room id of the in_area room, and the value
pair is: first=out_of_area room id
second=direction code
The original direction codes were defined at the start of the TArea.cpp
class file but there did not appear to be any logic to the values used:
N=12, NE=1, E=3, SE=4, S=6, SW=7, W=9, NW=10, UP=13, DOWN=14, IN=15,
OUT=16, OTHER=17. Other than a lua function getAreaExits(areaId) which was
supposed to return just a list of unique keys via a TArea::getAreaExits()
method - i.e. a list of rooms in the given area which were exits to another
area, no other use was made of this data. I propose to replace this list
of values with the better known list stored in the TRoom class header file
but as that does not currently have a value for "other" {a.k.a. Special}
exits I had added a new define: #DEFINE DIR_OTHER with the value 13.
The data IS stored in the map file but is not changed except by calls to:
* (void)TArea::ausgaengeBestimmen() called from:
(void)TRoomDB::initAreasForOldMaps()
* (void)TArea::fast_ausgaengeBestimmen(int id) called from:
(bool)TMap::setExit(int from, int to, int dir)
(void)TRoom::setArea(int _areaID)
(void)TRoom::setSpecialExit(int to, const QString & cmd)
(void)TRoom::removeAllSpecialExitsToRoom(int _id)
(void)dlgRoomExits::save()
* (void)TArea::removeRoom(int room) called from:
(void)TRoom::setArea(int _areaID)
(bool)TRoomDB::__removeRoom(int id)
The bugs are that the code in both "ausgaengeBestimmen" methods (with
and without the "fast_" prefix) used the FROM room Id as the first member
of the value pair rather than the TO (a.k.a. exit) room Id for Normal
exits and use the room ID of the TO (a.k.a. exit) room Id as the key for
Special exits (i.e. stores a room that is NOT in the relevant area as a
room IN the area that is an exit from THAT area!) Additionally, even if
the code was correct the existing flawed data would not be corrected when
the map is loaded by running TArea::ausgaengeBestimmen() again because that
is only called at the end of TRoomDB::initAreasForOldMaps() which was
called only for old pre-version 15 map file formats (and we are currently
on 16 - though I have plans in pipeline for something that would require an
increment on that). To further stir the faulty data up previous faulty
code that introduced problems when moving a room from one area to another
may also have contributed to errors with the TArea::exits data.
However:
tl;dr;
running the lua command "auditAreas()" runs TRoomDB::initAreasForOldMaps()
which will fix-up existing maps after this commit has been committed...!
This fixes ["getAreaExits is broken (bug 1380822)"](http://bugs.launchpad.net/mudlet/+bug/1380822) 8-)
Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
|
Humm, this has become a series of four commits but it would make things clearer if I squashed the last three together IMO. As I understand it that would make the git history cleaner when it gets merged but can be confusing if anyone looks through this PR. @vadi2 Are you OK with the state now before I squash the last two commits into the second one? |
b99584d to
5889dee
Compare
|
Yep, go ahead! |
5889dee to
a88c716
Compare
|
OK - should be just the two commits ready for someone to merge now. 👍 {Also kills off need for #225 I believe!} |
src/TLuaInterpreter.cpp
Outdated
There was a problem hiding this comment.
What is the point of the message and the 1/0?
There was a problem hiding this comment.
Additional (ignorable) translated response message - and a numeric return code so international script writers don't have to parse each and every language it gets changed into to know the outcome. Returning just a nil if there is no data does not distinguish between bad input values (note the message and -1 result for that) and no output for valid input (0); neither of these throws a Lua error as the invalid input (wrong type) does; which is what I thought we wanted - only throw errors for "code design" errors not for run-time issues...
There was a problem hiding this comment.
Only return the table and that's it - no need for the message because this is for scripting, not the UI. If the input value is bad, then you return nil + the error message (and that is the only time you return a message). We follow the same convention as Lua's standard stuff does.
The message bit isn't really followed though so most functions return nil, which is a problem in case of multiple error messages.
In the case of this function:
- bad input value would be nil + error message
- no output for valid input would be an empty table
- output would just be the table, no status codes or success messages
There was a problem hiding this comment.
Right, let me reiterate how I see this so I have it clear:
- If the user's script supplies incorrect types of arguments that cannot be coerced(?) into the wanted one, throw a lua_error() which aborts things and passes a message back to the user about the first argument that is not right - that message should begin with the name of the function that encountered the problem, without "()" but followed by a ':'. This message IMHO ought to be translated via a Qt tr().toUtf8().constData() wrapper when we go multi-lingual as it will help to inform the user in their own language what the problem is. Not furnishing enough mandatory arguments should now be caught by the current standard type checking tests {with lua_pushstring( L, tr(": bad argument #N (..., got %1).arg( luaL_typename, N).toUtf8().constData() ) } type messages as the automatically generated nil values that the missed out arguments get will trip the type checks.
- If the user's script supplies the correct type of arguments, but one or more values is outside of the acceptable range of values the first return value is a nil and a second value, a message about the problem value should be returned. Like the message in the previous case, in my option, that message should, in the future, be subject to translation into the user's language of choice as it is intended to inform them of the problem rather than be parsed for meaning by other scripts.
- If the user's script supplies the correct type of arguments, and all values are inside of the acceptable range of values but there is no data to return for that particular set of values then an empty table "{}" or string "" should be returned. We should avoid returning nil in this situation...
- For the normal case the expected data should be returned, without further strings attached 😜 - I'm not entirely convinced of this, unless it is essential that the additional message provision for wrong value arguments must be nil when things are 🆗, as a script writer I'd welcome positive outcome messages when debugging stuff unless they get in the way by decreasing the Signal-to-Noise ratio of debugging message.
In the case where a function does produce a multi-value return in the event of a bad argument value should all of those values get set to nil then the extra error message gets tagged on? I was going to quote my getMudletVersion() when supplied with a single (literal) string of "table" as an argument - which produces a multi-value return but that would be a bad example because it only does a multi-value return if the (incorrectly chosen) string "table" is supplied so this situation does not apply.
Discuss ❓
If I can get a good grip on this I would consider writing it up for the wiki / sticky it in the development forum 😁
There was a problem hiding this comment.
- yes, no further strings attached - it makes the functions simpler to work with and hasn't been necessary. I also don't know of an API that would so verbosely describe what it gives you.
- I don't know what value are you referring to.
There was a problem hiding this comment.
I don't know what value are you referring to.
I was thinking of a (hypothetical) case where the normal output was, say, a 3 value multi-return rather than a table, e.g. perhaps an alternative room coordinate function that might be used thus:
lua x,y,z = getRoomCoordinates( 123 ) echo( "The room is at ("..x..","..y..","..z..")\n" )
If room 123 did not exist, following the nil return plus extra message suggestion should the return be:
nil, nil, nil, "getRoomCoordinates: Warning - bad argument #1 value (Room number 123 does not-exist)."
This is only a contrived example to explain my query. 😉
There was a problem hiding this comment.
Just nil and the message then. It's not possible for a room coordinate to be nil, so when checking for success you'd just be checking the first return value.
This should go up on the wiki as the Lua API design philosophy for developers.
…rrect
Rename:
(void)TArea::fast_ausgaengeBestimmen(int)
==> TArea::determineAreaExitsOfRoom
(void)TArea::ausgaengeBestimmen(int) ==> TArea::determineAreaExits
(const)(QList<int>)TArea::getAreaExits() const
==> TArea::getAreaExitRoomIds()
Add new method to return area exit data in new, wanted format:
(const)(QMultiMap<int, QPair<QString, int> >) getAreaExitRoomData() const
In preparation to revising internal storage representation of area exit
data moved the: (QMultiMap<int, QPair<int, int> >)(TArea *)->exits member
from public to private area of class. To permit save and load the
following have had to be made friends of the TArea class:
(bool)TMap::serialize( QDataStream & ) and (bool)TMap::restore( QString )
Revise (void)TMap::init(Host *) to run (TArea *)->determineAreaExits() on
current and all previous map file format versions, will not be needed on
future version as the code to manage the areaExits data is now functional.
Previous code would have done this only for versions prior to 14 files
(current is 16) or if the lua function auditAreas() was manually run. In
passing also modified code that "fixed-up" "old style" map labels so that
it is no longer run on current version files and pushes any messages that
that creates into the main profile console instead of using standard C++
cout calls which we deprecate now.
All code blocks that have been touched by this series of commits have been
re-formatted to current styles.
Update copyrights on all files touched that have not already been marked as
having been edited by myself.
Revised TLuaInterpreter::getAreaExits(...) to take a second optional
Boolean that if present and true cause it to return data about the area
exit directions and the destination rooms, if false or omitted, returns
only the rooms in the area that have exits out of it, reproducing the
previous implementation. In either case the result is a table if there
are area exits (or a nil for an isolate area without exits); two additional
values are returned an informative, translatable, text message and an
integer status code that reflects the same information.
When moving a series of rooms to a different area via the 2D mapper's GUI
the recalculations for the area extremes {by TArea::calcSpan()} and the
out of area exits {by TArea::determineAreaExits()} can now be deferred
until the last room has been moved by passing a third true (boolean)
argument to TMap::setRoomArea(...) which defaults to false for other single
room at a time usages. Though that method keeps a local copy of the areas
that have been modified and thus need updating, should the last room NOT
be processed (null TRooo pointer for room Id) a publicly accessible
"mIsDirty" flag is also used so that recovery code can identify and clean
up those affected areas otherwise. It is possible that this flag may be
useful in other situations, such as when moving or adding multiple rooms
WITHIN an area.
*** This commit has been rebased so it's history might not be the same as
someone else's copy of it ***
Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
|
Been tweaking again, to get the lua returns inline with the suggestions given for error/fault/no output cases. Bottom line:
If there are no objections I'd like to get this one into development branch. Note: I've raise the point on Gitter that we are ambiguous about duplication of area names - some parts demand unique area names others permit them without hesitation. I have another Pull Request ready to put out that addresses this consistently (prohibits duplicates, fixes existing maps by applying numeric suffixes to duplicates, and applying a generic name to unnamed areas {with a suffix if more than one} - it advises user with what is happening and why and offers them the information of the specific area names before and after that are being affected) and it will only hit the user once per map file. I've thought about this a little and I feel that allowing two areas to have an identical name does not make sense from a semantic point of view and whilst it might surprise a user who falls foul of this issue if they are referring to areas by name as some of the Lua functions permit they are gonna have bigger problems than existing names changing in a comprehensible manner.
The |
src/TLuaInterpreter.cpp
Outdated
|
Looks good to me otherwise. |
…andard Due to unawareness of standards I have deviated from them in producing multiple return values upon success as well as failure. Whilst I feel that a second return value being a translatable status string and a third being an integer encoding of the same might have some merit, particularly in a fully internationalised and localised version of Mudlet in the future; no decision has been made over precisely how I18n and L10n will be handled so using them is a little premature and only confuses things for the moment. The current methodology is: * For bad argument TYPE situations: to throw a lua_error and provide a error message using a fairly uniform construction, I provide these via Qt's translation system to permit that part of the Lua API to be translated with the C++ parts of the application's framework. * For bad argument VALUE situations best practice is for a lua function to provide a primary nil return value but to also provide a secondary value as a string message describing the (first) argument value error. A lua error is NOT thrown but unless the user catches the error message by providing a second variable to contain the second return value they may not find out what is wrong. Again I choose to provide a translatable message for this. * For good arguments case that are satisfactory but produce no data, an empty table, an empty string or a signal number value is an appropriate primary return value. For example for either type of table that the lua getAreaExits((int) areaId, <(bool) provide Full data> ) function now returns, an empty table will be returned for an area which is isolated and has no exits. A secondary return value is NOT expected in this situation as far as I can tell, though I believe one could be useful... * For good arguments values for functions that provide data then the data is returned as the primary and only return value. * For good arguments values for functions that do not return data then success should be indicated by a single true Boolean return value. Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
BugFix: Fix original coding errors creating data in TArea::exits member
|
This needs to be merged into release_30 because it fixes getAreaExits(), a function introduced in 3.0 but was broken. |
|
OK, so I should make a local branch of release30 and check that I can merge the same series of commits in on my system then put up a PR against that branch, yes? |
|
Yeah Sent from my phone
|
|
@Chris7 Done, awaiting merge by a suitably authorised person 😉 |
The specification for this member is:
and it is a record of the rooms that are on border on the TArea instance.
The outer QMultiMap key is the room id of the in_area room, and the value
pair is:
The original direction codes were defined at the start of the TArea.cpp
class file but there did not appear to be any logic to the values used:
N=12, NE=1, E=3, SE=4, S=6, SW=7, W=9, NW=10, UP=13, DOWN=14, IN=15,
OUT=16, OTHER=17. Other than a lua function getAreaExits(areaId) which was
supposed to return just a list of unique keys via a TArea::getAreaExits()
method - i.e. a list of rooms in the given area which were exits to another
area, no other use was made of this data. I propose to replace this list
of values with the better known list stored in the TRoom class header file
but as that does not currently have a value for "other" {a.k.a. Special}
exits I had added a new define: #DEFINE DIR_OTHER with the value 13.
The data IS stored in the map file but is not changed except by calls to:
The bugs are that the code in both "ausgaengeBestimmen" methods (with
and without the "fast_" prefix) used the FROM room Id as the first member
of the value pair rather than the TO (a.k.a. exit) room Id for Normal
exits and use the room ID of the TO (a.k.a. exit) room Id as the key for
Special exits (i.e. stores a room that is NOT in the relevant area as a
room IN the area that is an exit from THAT area!) Additionally, even if
the code was correct the existing flawed data would not be corrected when
the map is loaded by running TArea::ausgaengeBestimmen() again because that
is only called at the end of TRoomDB::initAreasForOldMaps() which was
called only for old pre-version 15 map file formats (and we are currently
on 16 - though I have plans in pipeline for something that would require an
increment on that). To further stir the faulty data up previous faulty
code that introduced problems when moving a room from one area to another
may also have contributed to errors with the TArea::exits data.
However:
tl;dr;
running the lua command "auditAreas()" runs TRoomDB::initAreasForOldMaps()
which will fix-up existing maps after this commit has been committed...!
This fixes "getAreaExits is broken (bug 1380822)" 8-)
Signed-off-by: Stephen Lyons slysven@virginmedia.com