Mtasa-blue: Implement Lua API version

Created on 3 Aug 2020  路  11Comments  路  Source: multitheftauto/mtasa-blue

As briefly discussed in #1459, we should implement a Lua API version which is set via meta.xml.

We always want to ensure backwards-compatibility when making changes to code, however this may prevent us from:

  1. Keeping code clean
  2. Making "beneficial" changes (that would break backwards-compatibility)

An example of this is with CEGUI, where functionality in newer versions may differ from the version we're currently using. By default, we'll ensure everything looks/feels and functions the same as before, however this may prevent new features/changes in CEGUI being used (or at least implemented cleanly).

The server/resource should decide if they care about backwards-compatibility over improved functionality.

Another example may be when "extended" function alternatives have been suggested (#638) - instead of adding a separate function we'd simply allow them to set the API version specifically for this function, e.g:

<api name="setElementData" version="123" />

I haven't really thought about how exactly this will be implemented or configured via meta.xml, so input here would be great.

enhancement

Most helpful comment

Unnoticeable subtle differences in API parameters could cause anguish

But I think this is ~normal when an API changes in a non-backwards compatible way. And my guess is that this might even be the most common scenario. And I'd expect us to still try really hard with backwards compatibility - there are very few scenarios where a good solution demands a new API version.

Rather than avoiding these issues altogether, perhaps we should try really hard to solve/alleviate the challenges associated with having function behaviour change depending on the content of another file.

All 11 comments

Have you thought about having versioning apply for all functions, rather than individual functions?

I'm thinking it would get a bit complicated for both developers and scripters to have to keep track of individual function versioning. It would also be easier to handle documentation-wise, as the user has one version number to remember (and we can show documentation that is valid for a single API, rather than asking the user to figure it out per-function).

I'm also thinking, as a version number, we can just use the MTA version number - something similar (or identical) to whatever value min_mta_version uses.

I agree - that could get messy. I'll try my best to explain how I'm imagining the implementation.

For any proposed changes that could potentially break existing scripts (or change an existing feature massively), we'd place it under the current "new" API version (for instance, v2).

Let's say features X, Y and Z are changed - they'd be put into API v2.

Further down the line, if for some reason feature X is changed massively again, we have the option to increment the API version and, in this case, place it into API v3.

To couple that with your min_mta_version idea, you could then have something like this:

<api version="2" /> <!-- This applies the latest API v2 -->
<api version="2-20616" /> <!-- Only apply API v2 up until version 20616 -->

Does that make sense, or am I talking shite due to lack of knowledge on MTA versioning?

random thought: if you chose API v3, would it cascade changes from lower versions?

This will duplicate min_client_version functionality.

I'm not sure it would. This isn't for required fixes - it's for entire changes / overhauls to features where we'd want the existing implementation to always be available. Surely using min_client_version makes the original version obsolete when transitioning major versions?

If not, someone plz write a guide on MTA versioning 馃槅

If you chose API v3, would it cascade changes from lower versions?

Yeah I'd expect that to be the case. So if your resource was running on API v1 (the default), and you wanted to upgrade to v4, you'd need to read the documentation to upgrade 1 to 2, 2 to 3, and 3 to 4.

And to make it easier, we can provide a tool like this: https://update.angular.io/#9.0:10.0

<api version="2" /> <!-- This applies the latest API v2 -->
<api version="2-20616" /> <!-- Only apply API v2 up until version 20616 -->

I was thinking that, instead of having a separate set of numbers, we can just use the MTA version number, since that will always increment when we make any change that has a new API version. You could think of it as an "opt-in button" for the latest backwards-incompatible changes of the MTA 1.6 API.

This will duplicate min_client_version functionality.

As per #1240 we can't use min_client_version to change how functions behave.

Having function behaviour change depending on the content of another file introduces a dependence subtlety. Code snippets will not be consistent and copy pasting code will not work as expected.

A safer solution would be to have new function names, like setElementData2() or if reusing a function name, have the api switch nearer the actual code.

e.g. if Lua supported namespaces:

apiV2::setElementData("aa",1)
apiV2::setElementData("bb",1)

or

using namespace apiV2
setElementData("aa",1)
setElementData("bb",1)

+1+1+1+1+1 apiV2::setElementData("aa",1) is best way, because can forgot to say what version he use

I'm not a huge fan of adding additional function names or namespaces, as both add additional complexity for users ("do I use setElementData or setElementData2/apiv2::setElementData?") by offering multiple ways to achieve the same effect. This would increase further if another change in the same function is required (e.g. setElementData3). Generally most versioned functions should replace their predecessor entirely with at most a minor code change required (e.g. #1583 changing returns from 3 numbers to a vector, which would need to be unpacked, or teaEncode/Decode dropping trailing zeroes). As a result the old version of a function should no longer be of any use and might as well be removed entirely.

A fixed api version in the meta may break some snippets, but the overall impact should be fairly small and easy to fix as long as you have the source for your scripts and are able to read a wiki entry. Compiled scripts can stay on the old version indefinitely, so those shouldn't be an issue.

In terms of implementation the version meta entry could internally be translated to the corresponding <min_client_version> entries, so that only client versions which at least support api version n can join, making <min_client_version> (and the server equivalent) mostly obsolete (obfuscration changes like noted in #1240 would internally increase <min_client_version>, but not the api version).


@Namespacing: Lua has tables, so apiv2.setElementData would work.

I think we can use library model. Some things like a this:
syncedElementData.setElementData( ... )
pButton = CEGUIv8.Button( x, y, ... )
It will be simple and will not broke backward compatibility.

Some quick points:

  • I think the setElementData2 name is quite ugly.
  • I think, correct me if I'm wrong, the end goal is to be able to break backwards compatibility in the Lua API without actually breaking any old resources.
  • The library model interests me. There's so much we could discuss about the library model that I won't go into detail unless we think some form of library model is the way forward.

@ccw raises a good point. Unnoticeable subtle differences in API parameters could cause anguish (for scripters, scripting support, and even devs via bug reports).

  • e.g. someFunc(true) could do very different things between versions, and people (scripters or devs) might not notice it requires a different version. Time wasted debugging.
  • New forum topics might not include "I'm on API v1.6". (Unless we require posts to be tagged in the scripting section.)
  • Old forum topics would be inaccurate as they are guaranteed to be missing "I'm on v1.5.7". (Unless we auto-tag old ones.)

However, I'd hope new resources always use the latest API version, and support for old versions simply to exist for old resources / resources that have not updated to the latest API version.

Unnoticeable subtle differences in API parameters could cause anguish

But I think this is ~normal when an API changes in a non-backwards compatible way. And my guess is that this might even be the most common scenario. And I'd expect us to still try really hard with backwards compatibility - there are very few scenarios where a good solution demands a new API version.

Rather than avoiding these issues altogether, perhaps we should try really hard to solve/alleviate the challenges associated with having function behaviour change depending on the content of another file.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rk-r picture rk-r  路  4Comments

LosFaul picture LosFaul  路  4Comments

StifflersMom picture StifflersMom  路  4Comments

commanderagu picture commanderagu  路  3Comments

Haxardous picture Haxardous  路  3Comments