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

Using object types outside of current list #9

Open
noble-ux opened this issue Aug 21, 2020 · 3 comments
Open

Using object types outside of current list #9

noble-ux opened this issue Aug 21, 2020 · 3 comments

Comments

@noble-ux
Copy link

noble-ux commented Aug 21, 2020

From my understanding the compiler checks objects in the script to a predefined list to grab it's tag location.

Is there any way for users to add on to this list or place other types of items that are not already predefined such as street_cone or even ff_plat_2x1_flat?

If not I wouldn't getting a list together of some objects and their tags if I could provide those to be added.

@noble-ux noble-ux changed the title Adding additional object types Using object types outside of current list Aug 21, 2020
@DavidJCobb
Copy link
Owner

DavidJCobb commented Aug 29, 2020

Apologies for the delayed reply.

The list of objects available to Megalo is defined in the motl tag on each *.map file. Compiled scripts refer to entries in that list by their numeric index within the list, notably not by the actual list item names. ReachVariantTool therefore has a hardcoded list that maps names (and in some cases, extra information like descriptions) to these numeric indices. Notably, it does not open *.map files and so does not care what names are used in the motl tag (in fact, for several list items I chose to use different names because they were more intuitive).

As such:

  • If you want to make more objects available to Megalo, you must edit the motl tag in the underlying *.map file.

  • If you want to use these modded objects in ReachVariantTool, you will have to use the name that ReachVariantTool expects you to use. For example, you can change the unused motl entry for "Firebomb Grenade" to spawn traffic cones instead, and you could even change the name within the motl tag, but you would still need to write firebomb_grenade in ReachVariantTool to refer to traffic cones. (You could, however, put this at the top of your script: alias traffic_cone = firebomb_grenade; then you can use traffic_cone directly. You can also use the numeric index directly, but unfortunately, the documentation doesn't list those at present.)

It must also be noted that while it may be possible to extend the motl list with new entries at its end, ReachVariantTool will reject numbers that are past the "official" list end. This is because invalid values will crash the game.

@DavidJCobb
Copy link
Owner

DavidJCobb commented Aug 29, 2020

Addendum: I could in theory add a feature to allow people to override or replace the object type names for the compiler, but that would have to be opt-in on a per-script basis (rather than a program-wide setting) for the following reasons:

  • Changes to motl that work for one script may break another script, if a script uses an object type name that has been changed.

  • Object type names are, internally, "imported names." Script types are allowed to "import" named values into the global scope. These values have to be always-accessible so that you can create aliases of them. This means that changing the object type name list could break a script by causing one of that script's existing alias names to conflict with the object type name.

We could set up OpcodeArgValueObjectType to be able to hold a pointer to a DetailedEnum to use as an override for the built-in one, and then have some kind of facility whereby you can define an object type list in a text file and we can load that into a DetailedEnum on request. (Perhaps it's time to add #pragmas to the compiler?) We're somewhat fortunate in this regard in that OpcodeArgTypeinfo::imported_names is a struct which holds a DetailedEnum pointer: we can overwrite that if need be. (Actually, in that case, it'd be better for the logic for ObjectArgValueObjectType to just refer to the imported_names enum member directly.)

If I add this feature, I would need to validate names in the new list to enforce the usual rules against shadowing built-ins and keywords, with the additional caveat that I have to let you shadow built-ins that belong to OpcodeArgValueObjectType because you're replacing its list of built-ins in the first place.

Ideal syntax, then, would probably be something like this with some syntax for the object names:

pragma replace_imported_names(_object_type):
   imports/my_cool_map_objects.txt
end

Alternatively, we could allow this either inline in a script or in a secondary file:

pragma replace_imported_names(_object_type):
   object_0
   object_1
   object_2
   -- ...
end

And then we could allow imports of secondary files with another pragma (using paths relative to the application directory):

pragma import(imports/my_cool_map_objects.txt)

The overall syntax for pragma directives, then, would be:

pragma name -- no arguments or body
pragma name(arguments) -- no body
pragma name:
   -- body
end
pragma name(arguments):
   -- body
end

@DavidJCobb
Copy link
Owner

DavidJCobb commented Aug 29, 2020

Additional considerations:

  • There would still be no way to redefine the object type list in contexts other than script compilation, e.g. the Required Object Types editor for gametype data.

  • Any types modified with the pragmas described above would need to be reset after a compile operation is complete (or after it fails, is canceled, etc.). This requires the compiler to remember the original enums they used. (Maybe easier to just give OpcodeArgTypeinfo a second imported_names struct for overrides.)

  • If a script redefines a type's imported names multiple times, we need to ensure that we still restore the built-in name list properly after compiling.

  • The implementation described above would only allow the redefining of enums, not flags or other imported names. For the object type list, this isn't a problem, but the syntax and names chosen above imply broader functionality.

  • For object types, we need to make sure that a user-supplied enum does not contain more than 32767 imported names, as we use an int16_t to hold the value. Other types may have different maximum counts.

  • A syntax for overriding specific elements, rather than the whole list, will probably be more generally useful when dealing with object types, as might a syntax for extending the existing list. Mimicking the enum syntax might work (i.e. name = value) with the caveat that you have to be able to use old values' names e.g. "traffic_cone = firebomb_grenade" (so, the old names have to be "in scope" for the purposes of the override).

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

No branches or pull requests

2 participants