Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebased3 fix replay #200

Closed
wants to merge 12 commits into from
Closed

Conversation

vadi2
Copy link
Member

@vadi2 vadi2 commented Oct 5, 2014

No description provided.

… cases

Code that was put in to fix messages with tag "[ ERROR ] - " was not copied
to the other tag types, so those messages were not lined up correctly as
per:

"[<tag>] - <message line 1 ...>
           <message line 2 ...>
           ...
           <message line n ...>"

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
… items

Global items moved from middle of .cpp file to class header, gaining 'm'
for member prefix:
cTelnet Class {private members}:
char loadBuffer[]               ==> mLoadBuffer[]
int loadedBytes                 ==> mLoadedBytes
QDataStream replayStream        ==> mReplayStream
QFile replayFile                ==> mReplayFile

Items renamed to include 'm' for "member" prefix:
bool loadingReplay              ==> mIsReplaying

mudlet class:
Items renamed to include 'mp' for "member pointer" prefix:
QAction * actionSpeedDisplay    ==> mpActionSpeedDisplay
QAction * actionReplayTime      ==> mpActionReplayTime
QLabel * replaySpeedDisplay     ==> mpReplaySpeedDisplay
QLabel * replayTime             ==> mpReplayTimeDisplay
QTimer * replayTimer            ==> mpReplayTimer
QToolBar * replayToolBar        ==> mpReplayToolBar
QAction * actionReplaySpeedUp   ==> mpActionReplaySpeedUp
QAction * actionReplaySpeedDown ==> mpActionReplaySpeedDown

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
The icons style/sizes were not being set and were not modified by changes
made in preferences.

In Qt5 a NULL QTime is invalid and now adding a time to it no longer makes
it valid (this is different from Qt4 where adding a time DID make it
valid).

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
For replays where input occurs less often than once a second the time
display was only updated when each chunk was read with the result that the
time display could be static for long periods.  This commit increments the
display by one second every second divided by the speed factor.  A previous
attempt to do this caused some "jumping/sticking" in the display because
the displayed time was advanced only once a scaled second, which meant the
displayed time did not seem to increase uniformly as it was reset to the
right value when each chunk is processed.  By decreasing the amount the
displayed time was incremented to a scaled tenth of a second the
perturbations is reduced considerably.

As the used time format {"hh:mm:ss"} is the default for the
QTime::toString() method used to generate the text to display on the Replay
Time display widget we do not need to have a const QString constant to hold
the time display format to use as the record of the formatting we want.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
This commit uses negative values of the mudlet class member mReplaySpeed to
indicate speeds that are the reciprocal of the integer number.  It tweaks
the display of the speed to show a fractional value rather than a decimal
one in the limited cases (1/2, 1/4, 1/8) that are coded for.  As the lowest
supported speed is altered by this commit it also seemed reasonable to set
a reasonable upper limit of 128 so that one second of replay corresponds to
just over two minutes of real-time in the original recording.

At the same time the infrastructure to support translation of the widgets
that contain text is implemented for future internationalisation.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
…ing)

Now needed for some work being done on fixing some bugs in the replay
system.  This is not the exact same code that was previously removed as the
change to using QSharedPointer<Host> to access the mHostPool members
instead of the previously used direct Host * pointers.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
Generate and provide messages about both replay starting success and
failure for both main Toolbar and lua script initiated replays from
the same place {QString cTelnet::loadReplay(QString & filename,
bool "called from Main Toolbar")} so that the latter invocation will not
produce messages on the main console for the profile.  Only for the former
case can a message be produced when a replay ends.  A later commit will
provide system events related to replays to user scripts to overcome this
issue.

Remove redundant TConsole::loadRawFile(std::string) as all it does is
convert the file name given in a call from TLuaInterpreter::loadReplay()
into a pathFile relative to the profile's log directory before calling
cTelnet::loadReplay() and that can (and now is) done directly by the
TLuaInterpreter method revised here.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
…hanges

The replay system can only handle one replay at a time, and although a user
script can initiate a replay it previously could not know about the ending
of that replay.  Also if a replay is taking place in one profile, another
one will get informed that the system is busy with a replay but cannot know
without repeatedly trying to start it's own when the system is available.
This commit defines several sysReplayEvents, with additional arguments as
follows:

"myReplayStart" - a replay that this profile has requested, either from a
    script or from the main tool bar has been opened SUCCESSFULLY and is
    now running.  Note that a failure to start the reply will be reported
    back in an error return to a lua script that tries to start one so does
    not need an event.

"otherReplayStart" - a replay has been started in another profile and so
    replays cannot currently be started by this profile.

"myReplayOver" - the replay that this profile had started has finished.

"otherReplayOver" - the replay that another profile had started has
    finished.  The replay system is thus now available to this profile.

"replaySpeedChange", (float)new_replay_rate, (float)old_replay_rate - not
    much use currently but notifies the profile running a replay that the
    replay speed has just been changed, the following arguments are the new
    and the previous rates (x0.125 = 1/8 to x128).  A lua command
    getReplayStatus() will follow in another commit to return a current
    and total replay times so combining this with that data may give useful
    information if a script wants to estimate replay timings.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
Found that during testing with multiple profiles closing the profile that
was running the replay caused a crash - in theory it could also happen when
using a single profile if the timer that cause the next replay chunk to be
loaded occurs during close down.  Cleanest fix is to provide a
cTelnet::abortReplay() member that duplicates the actions that would happen
at the end of the replay normally.  Modifies the mudlet::replayOver(...)
method so that the affected profile gets a "myReplayAborted" rather than
"myReplayOver" "sysReplayEvent" event which is not likely to be much use
at profile close-down but could be of use if the toolbar or lua interpreter
gains a means to stop a replay {change the "disabled" during "replay"
toolbar button to an enabled "stop" one, or when an abortReplay() lua
command is added} in a following commit.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
…by new

Also by using QPointer for the resources allocated with "new" we can avoid
problems with tryinn to "delete" them if they no longer exist.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
Until now the Mudlet replay files had the generic ".dat" file extension and
there was no protection against the user loading a file that is NOT a
replay file.  Given that the file includes embedded values to control the
amount to read from the file using a time sent to a QTimer in another
embedded value this seems unwise.  This commit adds some data to the start
of a replay file that serves to unique identify it (and adds a version code
so that if the format is changed in the future old formats can still be
identified correctly!)  It also changes the extension to ".mreplay" to
stand for Mudlet replay, moving away from a three letter string as an
extension as that restriction went away in operating systems probably way
older than Mudlet ever supported.  Old format replays will still be
acceptable, but the user will have to choose to use those by changing the
file type filter from the file requester dialog that is called when a
replay is requested from the main toolbar button.

The use of "dd-MM-yyyy#hh-mm-ss" as the time format to name the replay file
may look pretty but is unhelpful in sorting as an alphabetical sort of the
directory contents will group by day of month, month and then year etc.
This is OK provided the date-time meta-data is preserved but if such files
are archived or copied that date-time information can be lost and then
picking out files by age can become very difficult if the listing takes
more than one screen-full.  Putting the most significant date-time item
first, as is common in some world regions, makes an alphanumeric sort
produce the same results as a date-time meta-data sort and preserves the
sort order if the latter data is corrupted.

In addition, by structuring some elements in the header in a particular
layout it makes it possible to determine some characteristics about the
file from the command line - this is particularly relevant on *nix
platforms which offer the file(1) command using data parsing routines
configured by magic(5).

The differences now mean instead of receiving the lowest common denominator
of file type information, the generic "data" type:
'$> file ./WoTMUD_Jomin/log/23-02-2014#12-31014.dat
./WoTMUD_Jomin/log/23-02-2014#12-31014.dat: data'

one instead can get:
'$> file ./WoTMUD_Jomin/log/2014-09-12#17-28-11.mreplay
./WoTMUD_Jomin/log/2014-09-12#17-28-11.mreplay: Mudlet replay file, version 2, started: Fri Sep 12 17:28.11 2014(UTC), 15.106(s) long, profile: "WoTMUD_Jomin"'

As it is possible to initiate a replay from with a user Lua script it does
not seem unreasonable to also provide commands to:
* abort a replay
* obtain various bits of status information about such a replay
* control the playback speed in the same way as the toolbar does.

Some existing class members/methods have been modified for clarity or other
reasons:
* TConsole::mReplayFile     ==> TConsole::mRecordFile
* TConsole::mReplayStream   ==> TConsole::mRecordStream
  above two are associated with making a recording not with its playback
* TConsole::mRecordReplay   ==> TConsole::mIsRecording
  to match corresponding cTelnet::mIsReplaying.
* cTelnet::readPipe()       ==> cTelnet::slot_readPipe()
  to emphasise it is a slot method.
* QTime cTelnet::timeOffset ==> QDateTime cTelnet::mRecordLastDateTimeOffset
  instead of measuring the elapsed time directly we now save the point in
  time when the last chunk of data item was recorded, this allows for the
  unlikely but possible case of records of longer than a day or for when
  DST changes - both of which a QTime can not handle.
* mudlet::mpReplayTimer     ==> mpReplayDisplayTimer
  to differentiate it from the new mpReplayChunkTimer, the first is
  associated with updating the time display periodically every
  (second/speed) and the second with loading the next chunk after the
  right time period.
  Both are included in the class header so they can be accessed /
  controlled from outside of the class which is not possible if they are
  declared as class globals as the first had been in the past.
* cTelnet::abortReplay()    ==> cTelnet::abortReplaying()
  to match corresponding TConsole::abortRecording().
* cTelnet::mLoadingReplay   ==> cTelnet::mIsReplaying
  to match corresponding TConsole::mIsRecording.

Also:
mLogFileName, local to TConsole::slot_toggleReplayRecording() MASKS a
variable with the same name declared in the class header, it has been
renamed to recordingPathFile.  Another local variable of the same name in
TConsole::slot_toggleLogging() had the same effect - the local definition
there has now been removed so that that method will use the original member
of the class instance after all.

In TConsole.h the member mpCommandLine has been taken out of the grouping
of public methods and re-positioned further down with the other public
members.  Similarly the cTelnet::postMessage( QString ) method has been
moved out from the public members and up to the bottom of the other public
methods.

When making a recording Mudlet now should detect a failure to write out a
chunk of replay data completely and will abort, try to clean up the end of
the recording if possible, and report an error in the main profile console.

During the loading/playing of replays the data was being loaded into a
static fixed size char array { cTelnet::mLoadBuffer } of 100 Kilo-Bytes!
However as we know the size of each chunk before it is read from the file
it can easily be changed to a QByteArray that can be enlarged as required
if it is not big enough to hold a particular chunk of replay data.  In
a quick test the array only grow to a few thousand bytes and will only
slightly slow things down for each chunk read for which the buffer is
undersized until the maximum size needed is reached.

Although not marked with any licence terms I hereby state that the "magic"
file entry added to the INSTALL file is, for the avoidance of any confusion
to be considered as licensed as "GPLv2+" - if that is not suitable then
please contact me for alternative options:

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
…fine

Not the most elegant way of controlling such debug output, only relevant to
ctelnet.cpp and only changeable at compilation time.  On the other hand it
is better than what was used previously - well, a little bit...!

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
@SlySven
Copy link
Member

SlySven commented Oct 5, 2014

Thanks Vadim 😄

@vadi2
Copy link
Member Author

vadi2 commented Oct 5, 2014

I'd like to review this.

@SlySven
Copy link
Member

SlySven commented Oct 5, 2014

Ah, in E-mail from github:
On 05/10/14 00:57, Jamie Murai (GitHub Staff) wrote:

Hi Stephen,

Sorry for the trouble. We made some changes that are not compatible
with Firefox 24. If you upgrade to Firefox 32, you shouldn't have
any problems.

Let us know if you have any other questions!

Cheers, Jamie

@SlySven SlySven mentioned this pull request Oct 5, 2014
@ahmedcharles
Copy link
Contributor

Two comments:

1, Generally, PR's are easier when they have less changes in them and doing them one commit at a time would save lots of effort with regard to discussions and modifications.
2, Specifically, the second commit changes the names of various variables. I already expressed that I'd prefer that not be done in the previous PR, for multiple reasons:

  1. It's currently done in the same commit as moving variables around, which obscures whether moving them was done correctly or not and makes it needlessly hard to review.
  2. We haven't discussed and don't have concensus on what appropriate naming should be in the code base. I don't want to change the names from what exists today to some intermediate state just to have to change them again in the future to something we all agree on.

// We now use UTC as this may help with replays being shared across the
// world. Also put a trailing 'Z' on end of filename as a
// reminder/explaination of "Why does the time in the filename not match
// my wall-clock time?":
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really think this is a practical concern to be honest and we'd be better off using the local time to create less confusion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's swings and roundabouts to some extent - internally things are more straightforward if we don't have to worry about Wall Clock time issues like, is DST in effect or the corner case of has it/will it change in the two hour window around now? Not using UTC will break recordings in progress during DST changes I believe (it did for the old way but for a different reason).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's pretty unfortunate and not very user-friendly. I expect the time of the replay to be the same one I'm having right now if I just started it. It'll get confusing real fast to try and figure out when which replay was made.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see how to re-jig it, so will use the Wall-clock as you suggest here.

@vadi2
Copy link
Member Author

vadi2 commented Oct 6, 2014

If you make the replay play at the lowest speed, then bring it back to 1x - it doesn't play at 1x. Bringing that up to max x128 doesn't make it play at 1x either even.

stdout mentioned this, not sure if relevant:

cTelnet::_loadReplay(): Reserving more bytes (394 total) for buffer.
cTelnet::_loadReplay(): Reserving more bytes (406 total) for buffer.
cTelnet::_loadReplay(): Reserving more bytes (4976 total) for buffer.

@Chris7
Copy link
Member

Chris7 commented Oct 6, 2014

Our convention has been camelCase for everything.

Sent from my phone.
On Oct 6, 2014 7:41 AM, "Vadim Peretokin" notifications@github.com wrote:

If you make the replay play at the lowest speed, then bring it back to 1x

  • it doesn't play at 1x. Bringing that up to max x128 doesn't make it play
    at 1x either even.

stdout mentioned this, not sure if relevant:

cTelnet::_loadReplay(): Reserving more bytes (394 total) for buffer.
cTelnet::_loadReplay(): Reserving more bytes (406 total) for buffer.
cTelnet::_loadReplay(): Reserving more bytes (4976 total) for buffer.


Reply to this email directly or view it on GitHub
#200 (comment).

@SlySven
Copy link
Member

SlySven commented Oct 6, 2014

Vadim wrote:

If you make the replay play at the lowest speed, then bring it back to 1x - it doesn't play at 1x. Bringing that up to max x128 doesn't make it play at 1x either even.

The speed does not change instantly, only when the next "chunk" is read, is that what you have seen? The original code would only have updated the time display at the time the chunk was read so it may not have been so obvious that changing the speed does not instantly change the playback rate! It might be possible to get around this now as Qt5.2 enables you find out how much time remains on a QTimer but it won't have been straight forward for the original coder and we have only mandated Qt5 I believe.

At this point in time I do not think it is something we should worry about too much but I do have it on my stack - its just a lot further down than some other things. 😉

Chris Vadim wrote:

stdout mentioned this, not sure if relevant:
cTelnet::_loadReplay(): Reserving more bytes (394 total) for buffer.
cTelnet::_loadReplay(): Reserving more bytes (406 total) for buffer.
cTelnet::_loadReplay(): Reserving more bytes (4976 total) for buffer.

That is the QByteArray I changed to use to store the replay "chunk" being read from the file being resized to fit the amount of data being read from the replay file - previously a fixed size 100KByte char array was being used, but I wanted to be able to track just how much was being used and how often it was proving not to be enough - it is the high water mark as it were and will not go down but I cannot really envisage an occasion where it might get anywhere near as many bytes as we had put aside originally. (Also - I mistook the name of the file to be cTelnet.cpp not ctelnet.cpp - is that what you meant about camelCase names?)

@vadi2
Copy link
Member Author

vadi2 commented Oct 7, 2014

Yeah, it sounds like the delay until the next read is what I experienced.

int mReplaySpeed;
QPointer<QTimer> mpReplayDisplayTimer;
QPointer<QTimer> mpReplayChunkTimer;
int mReplayTimeOffset; // How many milliSeconds into this chunk of replay are we?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments are awesome.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫sarcasm Well the purpose of some of the original details wasn't initially clear to me in this area at first either!

msg = tr( "[ ALERT ] - A replay is already in progress for this profile!",
"Do not translate [ ALERT ] it is used to key the color coding of the message" );
else
msg = tr( "1error: a Replay is already in progress in this profile.",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using a tuple so you can return two values? Seems like a better design.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A QPair<QString, QString> sort of thing - then discard the unwanted half of the pair? Guess my 'C' origins are showing, as it wasn't something that crossed my mind but would do the job. 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, not quite the alternative solution as I thought because I also use the second boolean argument which flags what initiated the replay to also set a flag that persists until the replay ends. This is used say whether the replay ending or aborting should produce a message on the Console as well as controlling which type of return QString is generated so would have to be set somehow by the caller. This would still have to be set by the caller so this existing implementation is not so non-optimum after all.

@SlySven SlySven mentioned this pull request Oct 12, 2014
@SlySven
Copy link
Member

SlySven commented Oct 12, 2014

Replaced by #214

@SlySven SlySven closed this Oct 12, 2014
@vadi2
Copy link
Member Author

vadi2 commented Oct 12, 2014

Stop closing and re-opening PRs - that loses all the comments we have and makes traceability hard. You can push to the same branch to update a PR.

@SlySven SlySven deleted the rebased3_fixReplay branch March 26, 2017 21:18
mehulmathur16 pushed a commit to mehulmathur16/Mudlet that referenced this pull request Feb 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants