removing/adding unitdef tags vs callins

removing/adding unitdef tags vs callins

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

Post Reply
Google_Frog
Moderator
Posts: 2448
Joined: 12 Oct 2007, 09:24

removing/adding unitdef tags vs callins

Post by Google_Frog »

Split from viewtopic.php?f=12&t=33573 - SIlentwings

In the previous topic someone said to be wary of adding new unit defs because it makes game creation harder. I think that is completely wrong, I like extra unit defs which can configure behaviour which would otherwise be hardcoded. Game development is not harder as long as the unit defs have reasonable defaults (ideally corresponding to current hardcoded values).
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: miscellaneous aircraft-related improvements

Post by Kloot »

DO ***NOT*** ADD A NEW DEF TAG FOR EVERY LITTLE HIGHLY SPECIFIC BEHAVIOR YOU WANT TO CONTROL

USE THE LuaSynced(Move)Ctrl INTERFACE INSTEAD AND MAKE SUCH UNIT PARAMETERS DYNAMICALLY CONFIGURABLE

TAGS ARE ***ONLY*** MEANT FOR RIGID STATIC TYPE PROPERTIES, THEY LIMIT THE ENGINE'S FLEXIBILITY AND EXTENSIBILITY AND THEIR NUMBER SHOULD BE DECREASED WITH NEW RELEASES, ***NOT*** INCREASED

REPEAT THIS MENTALLY UNTIL IT IS CLEAR: TAGS ARE ***NOT*** VALID SUBSTITUTES FOR HARDCODED CONSTANTS!


User was warned for this post - felony 1. -- FLOZi
(Post slightly cleaned up after threads split - Silentwings)
User avatar
Nemo
Spring 1944 Developer
Posts: 1376
Joined: 30 Jan 2005, 19:44

Re: miscellaneous aircraft-related improvements

Post by Nemo »

As a bonus, things that are exposed/implemented through a LuaSynced interface make for a way better game developer workflow. I have wasted months of time in aggregate waiting for spring to reboot after changing some tag value on a unit where the outcome isn't entirely clear (e.g. the aircraft tags).
abma
Spring Developer
Posts: 3622
Joined: 01 Jun 2009, 00:08

Re: miscellaneous aircraft-related improvements

Post by abma »

Kloot wrote:DO ***NOT*** ADD A NEW DEF TAG FOR EVERY LITTLE HIGHLY SPECIFIC BEHAVIOR YOU WANT TO CONTROL

USE THE LuaSynced(Move)Ctrl INTERFACE INSTEAD AND MAKE SUCH UNIT PARAMETERS DYNAMICALLY CONFIGURABLE

TAGS ARE ***ONLY*** MEANT FOR RIGID STATIC TYPE PROPERTIES, THEY LIMIT THE ENGINE'S FLEXIBILITY AND EXTENSIBILITY AND THEIR NUMBER SHOULD BE DECREASED WITH NEW RELEASES, ***NOT*** INCREASED
this should be wikified.
User avatar
Nemo
Spring 1944 Developer
Posts: 1376
Joined: 30 Jan 2005, 19:44

Re: miscellaneous aircraft-related improvements

Post by Nemo »

And it'd be good to try to get as much information as possible on this in that page, so when people want to implement new interfaces for gamedevs, they can present a reasoned argument based on the pros/cons of implementing it as a pure tag or as a LuaSyncedCtrl bit.

For things that are implemented purely as LuaSyncedCtrl, it seems like it'd be possible to write a defs_pre shim to present the 'tag interface' to gamedevs and shove them in some customparams for a gadget to apply on unit creation.
Google_Frog
Moderator
Posts: 2448
Joined: 12 Oct 2007, 09:24

Re: miscellaneous aircraft-related improvements

Post by Google_Frog »

If I had to pick between tags and whatever it was Kloot was yelling about I would pick whatever it was Kloot was yelling about. Whatever it was Kloot was yelling about gives the gamedev more power than a fixed tag. So if I had to pick one I would not go with the tag.

Tags have benefits beyond power. Tags aid in cleanliness and cross game code compatibility. Every attribute which would reasonably be a tag but is not requires a customparam and part of a gadget to set the desired parameters at unit creation. An experienced game dev who wants to start using a tag will write a gadget and a customparam. This customparam will not have the same name (or even interpretation) as the one picked by other game devs. This especially hurts inexperienced gamedevs because the documentation for tags is much better than inconsistent customparams spread around game repositories.

It can even be non-trivial to implement the tag replacement gadgets. I have had a lot of trouble with Spring.SetUnitMidAndAimPos and currently can only use it for vertical modifications. There seems to be some weird interaction between that tag replacement and the orientation of unit creation.
User avatar
Nemo
Spring 1944 Developer
Posts: 1376
Joined: 30 Jan 2005, 19:44

Re: miscellaneous aircraft-related improvements

Post by Nemo »

Google_Frog wrote: An experienced game dev who wants to start using a tag will write a gadget and a customparam. This customparam will not have the same name (or even interpretation) as the one picked by other game devs.
To clarify, I was talking about putting a Lua-based shim in BaseContent (or whatever), so the tag would look/feel identically to a standard one. FLOZi tells me this is a terrible idea (since you'd have to mutate the UnitDefs table to populate it) and will earn much shouting from jK, so I'll leave this unimplemented, but it seems quite doable.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: miscellaneous aircraft-related improvements

Post by Kloot »

raaar wrote:my priority is to resolve the issues, not go into a screaming contest
Mine is to keep the engine sane, and shouting works.
raaar wrote: When I first made the changes, people told me to make behavior configurable. Then I looked at how to add unitDefs and it seemed easy enough.

attackOverflyDistance's default is probably good enough and airManeuverabilitySpread is a cheap way to spread out aircraft without fancy (and probably computationally expensive) coding.

I'd use the defaults on my game. They should work for other games as well....Those unitDefs could be removed, but do we really gain much from removing them? Why?
As a rule, run-time configurable behavior is better than load-time configurable behavior. This is what you should have been told too, and if you weren't that would be an omission on the part of the reviewer(s).

The concepts controlled by those parameters are not general enough to warrant tags of their own. Adding tags for everything under the sun means you end up with a complex system with lots of dials that can be turned only once and may not always give good results, when what you want is a simple system where the majority of the dials can be turned at any point and do.
raaar wrote: We could use a Lua way to dinamically flag specific units to use custom unitdef trees (with weapondefs, movedefs, etc.) that can be updated and reloaded in-game. But that implies attributes being registered as unitDefs in the first place.
It is precisely because the tag-system and supporting infrastructure is so rigid that swapping such attributes isn't possible in a natural way.
Google_Frog wrote:Tags have benefits beyond power. Tags aid in cleanliness
There are ~150 unneeded Unit- (let alone Weapon- and Feature-)Def tags and they tie into to many scattered bits of old, highly inflexible logic throughout the engine. This is neither clean nor powerful, and for example restricts games to two native resources and one role (transporter, factory, ...) per unit.

Any robust general system has few rigid parts to constrain its range of operation. Therefore, when there is no strong architectural or logical reason for a property to be static, don't add it as such.
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: miscellaneous aircraft-related improvements

Post by jK »

Kloot wrote:As a rule, run-time configurable behavior is better than load-time configurable behavior. This is what you should have been told too, and if you weren't that would be an omission on the part of the reviewer(s).
Wrong. Rules are:
1. Can I remove/merge tags?
2. Can I replace rarely used tags with lua callins?
3. Can I add the new feature as *Defs?
4. Can I add it as run-time var? <---- IT IS THE LAST OPTION

Why is it the last one? Cause run-time var means each instance needs a copy (increasing memfootprint & LinesOfCode, making everything messy). Also it breaks logic, cause code (gadgets, widgets, AIs, ...) want to analyze & filter all *Defs at start. With run-time vars 1. you have to check each instance AND 2. cause it can change at run-time you have to recheck it EVERYTIME.
That's neither KISS nor performance-wise coded!
Defs are needed so code can easily filter out unwanted instances!
Kloot wrote:There are ~150 unneeded Unit- (let alone Weapon- and Feature-)Def tags and they tie into to many scattered bits of old, highly inflexible logic throughout the engine. This is neither clean nor powerful, and for example restricts games to two native resources and one role (transporter, factory, ...) per unit.
Bullsh**
Neither resources nor CAI have anything to do with Defs. The limitations of those are purely in bad object/code designs.
User avatar
Silentwings
Moderator
Posts: 3666
Joined: 25 Oct 2008, 00:23

Re: removing/adding unitdef tags vs callins

Post by Silentwings »

There are ~150 unneeded Unit- (let alone Weapon- and Feature-)Def tags and they tie into to many scattered bits of old, highly inflexible logic throughout the engine.
Without wanting to get involved in the discussion on where to draw the line between needed/unneeded and what to do about it, I completely agree with the sentiment and spent hours trying to untangle the mess of what affects what in the past. Although it is easier these days thanks to the improved wiki.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: removing/adding unitdef tags vs callins

Post by Kloot »

jK wrote:Cause run-time var means each instance needs a copy (increasing memfootprint & LinesOfCode, making everything messy).
Irrelevant: instances already keep copies of many *Def params anyway.

Since you like micro-optimizations so much, maybe you should also consider the cost of dereferencing Def*'s everywhere.
jK wrote:Also it breaks logic, cause code (gadgets, widgets, AIs, ...) want to analyze & filter all *Defs at start.
Control over most tags like canSubmerge is not really going to break any critical filters...
With run-time vars 1. you have to check each instance AND 2. cause it can change at run-time you have to recheck it EVERYTIME. That's neither KISS nor performance-wise coded!
Sorry, not a valid concern: changes can (easily be made to) trigger events so rechecking would not be needed.
jK wrote: Defs are needed so code can easily filter out unwanted instances!
Yes, I'm sure code often wants to filter by UnitDef::wingDrag or some other BS tag.
jK wrote: Neither resources nor CAI have anything to do with Defs. The limitations of those are purely in bad object/code designs.
And that bad code design stems from the UnitDef structure.

When you start with properties like isFactory and isTransport, the natural (bad) design is to write corresponding Factory and Transport classes, and that's exactly what happened.
User avatar
Nemo
Spring 1944 Developer
Posts: 1376
Joined: 30 Jan 2005, 19:44

Re: miscellaneous aircraft-related improvements

Post by Nemo »

abma wrote:this should be wikified.
Like I mentioned on IRC, here's my draft: https://springrts.com/wiki/User:Nemo/Ne ... facesDraft

I cleaned up some of the portions that jK took issue with, like the statement that tags are a primary blocking issue for the engine outgrowing the metal/energy resource model. Suggestions welcome. In a perfect world this could become part of the new developer docs or a simple guideline for reviewing PRs.
User avatar
The Yak
Posts: 344
Joined: 20 May 2012, 05:36

Re: miscellaneous aircraft-related improvements

Post by The Yak »

Kloot wrote:
raaar wrote:my priority is to resolve the issues, not go into a screaming contest
Mine is to keep the engine sane, and shouting works.
Good to know. Next time I have useful information to add to the wiki I'll remember this post and think "Nah, better just post autistic fits of rage on the forums instead".

Is this really how we want things to be done around here?

User was warned for this post: Felony 1 & 4.

-- FLOZi
User avatar
Silentwings
Moderator
Posts: 3666
Joined: 25 Oct 2008, 00:23

Re: removing/adding unitdef tags vs callins

Post by Silentwings »

No, and it was dealt with. The content, however, is part of a useful discussion, so please don't derail this thread with backseat moderation.
raaar
Metal Factions Developer
Posts: 861
Joined: 20 Feb 2010, 12:17

Re: removing/adding unitdef tags vs callins

Post by raaar »

many complex games can be made without changing unitDefs at run time at all.

and there are workarounds like morphing the units.

argument against unitDefs is that they can't be changed at run time..... . . . . . . .

. .. .. ....why can't they be changed at run time?

i find this split between unit properties that can be changed at runtime and others that can't confusing.

what would happen if a peewee were moving and from one frame to the other its unitdef were replaced with the unitdef for a fighter aircraft, or vice versa? Possibly it wouldn't do much because most of the unit properties were already read from the unitDef into a behaviour instance when the unit was created. What if we reload that behavior?

there are surely ways to make the unitDefs dynamic without affecting games who don't use them

maybe:
- by default use the base unitDef that is loaded when the match begins
- add methods to instance dynamic unitdefs that are clones of the base unitdef for a unit name
- add methods to manipulate dynamically created unitDefs's attributes
- add method to change the unitDef of a unit instance from the base unitDef to one of the dynamic ones
- add method to reload unit behavior, to be used whenever significant changes are made to the unitDef (ex: change from ground to air unit)


this way game devs could choose not to use dynamic unitDefs at all, use a single dynamic one for every unit instance (ex: all peewees), and even have multiple dynamic ones in memory to use for specific instances of units (ex: commander, or the peewee that entered the altar of wtf).


this would change from:
- unitdefs (can't be changed at runtime)
- some properties (override the unitdefs and can be changed at runtime)

to:
- unitdefs (can't be changed at runtime)
- dynamic unitdefs (can be changed at runtime and may override the unitdef for each unit instance)
- some properties (override the unitdefs and can be changed at runtime)

the concept could be expanded for movedefs, weapondefs, whateverdefs
Last edited by raaar on 12 Jun 2015, 00:19, edited 2 times in total.
User avatar
Forboding Angel
Evolution RTS Developer
Posts: 14637
Joined: 17 Nov 2005, 02:43

Re: removing/adding unitdef tags vs callins

Post by Forboding Angel »

If I may insert a bit of logic into this, how about we simplify the definition to something like this, as it is what I use as methodology when I code things (yes yes, i don't do lua or C/C++, but it still applies)...

If something con be configurable, it should be. Hardcoded values are bad, especially when they are difficult to overcome via other means.

Ideally values should be end user define-able. The exception to this is when making those values define-able would cause unseemly bloat to the codebase. If the value in question is part of an equation, all of that equations parts should become user define-able with sensible defaults. I understand that it is a lot more work to do things this way, but doing things in this manner make it infinitely scale-able in the long run, and scale-ability is extremely important to longevity.

In addition to scale-ability, it also increases control. The side effects of more control is more complexity. More complexity is not necessarily bad as long as the logic involved is good and the defaults are sensible.

**************

The exception here is that things can be overridden by lua, but just cause you CAN solve a problem that way, does not mean that you SHOULD (I.E. Appropriate). Always do things the right way the first time. That means thinking years down the line and thinking of use case scenarios outside of your scope (I.E. How might someone want to use this in a way that I would not expect?), by thinking through things in this manner, we can have a much larger understanding as a whole and account for more possibilities or future issues.

</2cents>


***
Edit: Dynamic unitdefs would be sex.
hokomoko
Spring Developer
Posts: 592
Joined: 02 Jun 2014, 00:46

Re: removing/adding unitdef tags vs callins

Post by hokomoko »

Nemo wrote:As a bonus, things that are exposed/implemented through a LuaSynced interface make for a way better game developer workflow. I have wasted months of time in aggregate waiting for spring to reboot after changing some tag value on a unit where the outcome isn't entirely clear (e.g. the aircraft tags).
Making life easier for the dev so reloading spring isn't needed for reloading the defs is irrelevant. Even values that shouldn't be changed in regular play, should be changeable by the game dev in runtime (same as /luarules reload), so I'd argue this is a different discussion.

Now for the actual matter:
It's not productive talking about "defs" and whether they're good or not, as some are obviously needed (e.g. weapon type) and there are actually several types of them.

There are many 'relevant values' (I'll use Values with a capital V from now on) who control the behaviour of weapons, units, movetypes etc. in spring. There are several implementations for these including magical constants, defs, defs which are copied and can be changed and so on.

Let's ignore the current implementations though.
We can differ between said Values using the following criteria:
1) When and how often is this Value used? (Loading, Instance initialization, Runtime-rarely, Runtime-often)
2) When will I want to change this Value? (Never, Text, Loading, Instance initialization, Runtime-rarely, Runtime-often)
3) Is this part of a larger logic that can be replaced by lua?

Examples:
  • weapon type
    1. Loading, Init
    2. Text
    3. No
  • aiming arcs
    1. Init, Runtime-often
    2. Text, Instance initialization, Runtime-rarely (currently impossible, but we can think of scenarios that can use that)
    3. No
  • Number of frames between weapon auto-targeting
    1. Runtime-often
    2. Never
    3. Yes
Weapon type fits perfectly into its current role as a def.
Aiming arcs must be defined in text since they're a basic feature that changes often between units. It must be copied into the instance, because it changes in the init (arcs are based on the unit). A lua function to change them in runtime will make some sense.
The number of frames will never be changed. and is often used. It is part of a larger auto targeting logic which can be replaced by a callin.

Applying these for any new or existing Value should give a clue where it belongs.
gajop
Moderator
Posts: 3035
Joined: 05 Aug 2009, 20:42

Re: removing/adding unitdef tags vs callins

Post by gajop »

There are a couple of things to consider:
1. Engine vs Lua specified behavior (originally this thread)
2. Property mutability
3. Def tags vs Lua functions

There's a noticeable difference between 1. and 3. that should be clear which I'll mention in just a bit.

1. In this case, the push should definitely be towards Lua, but we should still striven to have the engine provide a solid functionality (collision handling, pathfinding, physics, and similar), and ways to control that from our game. In this case though, the distinction isn't so much whether you put things in the tags or not, but how much control you have as a user. If a user can just change certain variables of a predefined behavior, that's certainly less robust than being able to specify the movement behavior (movedef) in full - most likely through LuaMoveCtrl.

2. Property mutability is another thing that I find Spring rather lacking. This isn't just an issue when developing games, but it's also a major problem for the Scened. There, I did manage to have per-instance unit property editing, but I really wish I could change unitdefs which would impact all current and future instances of that unitdef, without having to code wrappers myself (at which point, I don't need unitdefs at all). Additionally, many things are immutable that probably shouldn't be, such as unit's size, weapondefs and many others.

3. I think the whole "def" vs "Lua function" debate is rather poorly imagined. The way I see it, defs are properties that are defined as default for all instances of a certain type, where through Lua functions you could set those values to something more specific. This is the way it should be, it's perfectly intuitive as it relies on human generalization and specification, and it should be reflected in the API design. We already have this for engine tags and LuaSyncedCtrl, despite not always being a 1 on 1 mapping, and worse, the naming scheme is different (maxdamage vs GetUnitHealth's 2nd return value). Besides getting those cases fixed, I'd like to see an improvement in the customparams <-> unitparams interface, where units would by get a value of the custom param by default, that could be set to a different value for a specific unit, with both the read and write operations using the same API (e.g. GetUnitValue(name), SetUnitValue(name, value)), and not having to think whether you're reading a customParam or a unitparam unless you're specifically interested in the tag value, for which the API function should look something like GetUnitDefaultValue(name), with the appropriate SetUnitDefaultValue(name, value). The biggest issue here is that isn't clear which things control a certain behavior, and it gets really confusing with collisions when there are just so many different things (unitdefs, movedefs, syncedctrl, movectrl) that have impact over pathing and unit collision.

The big distinction between 1. and 3. is that in 3. you have a pretty similar mapping from def to Lua (such as the collision volumes), while in 1 you don't (using movectrl to control unit movement).
Post Reply

Return to “Engine”