Git Product home page Git Product logo

phalanx's Introduction

phalanx

Project Phalanx

This is a project to create an alternative roster editor that uses BattleScribe-format datafiles.

Our main communication channel beside Issues, PRs and Discussions on GitHub is the #project-phalanx channel on BSData Discord server. BSData Discord link

Please see Wiki for more information.

Technical description

The following stack of app layers is currently (at least partially) implemented:

  • DTO to (de)serialize XML content into typed objects (WarHub.ArmouryModel.Source.*Core types). This layer is a tree where children don't have a reference to their parent.
  • SourceNode layer, lazy-initialized immutable wrappers for DTOs (WarHub.ArmouryModel.Source.*Node types). This layer is a tree where children have a reference to their parent.
  • Symbol layer, immutable object graph. Internal implementation of upper ISymbol layer, which builds an actual object graph, by resolving references (e.g. link targetId is resolved to an actual symbol for the target entry) - this operation is called binding. This layer also generates diagnostics (e.g. bad links, invalid enum values, etc).
  • ISymbol layer is an interface view of the Symbol layer, creating a fully bound object graph.
  • Compilation is a container for a set of data roots (gamesystem, catalogues, rosters), in which a binding happends.
  • RosterEditor and RosterState (from EditorServices namespace) is a heavily WIP layer that manages actual editing of roster, via IRosterOperations which encapsulate roster edit actions.

Development

You need one of the following setups:

  • Visual Studio 2022 (latest) - open the Phalanx.sln with it.
  • VSCode and .NET 7 SDK (latest) - open the repository folder in it.

The main app to run is in src/Phalanx.App - select this project as startup project in Visual Studio. VSCode has a defined debug configuration.

TODO

  • test default group entry binding - how it works in BattleScribe (allowed selections), does it work same in Phalanx
  • consider removing "deeper" types than IResourceDefinition/IResourceEntry/IContainerEntry
    • simpler usage
    • requires moving their "custom" properties somewhere: "ContentFields" collection of custom name-value wrappers, maybe strongly typed?
  • symbol layer:
    • symbolinfo that might be an error
    • implementation for: constraints, logic (conditions, modifiers)
    • usage/references (UseSiteInfo?)
  • add default subselections:
    • for entries with constraints min > 0 (constraints need symbols?)
    • entry groups
    • should that be in a separate "RosterEditor" module?
  • implement Logic symbols
  • semantic model that retrieves symbols/symbol info from SourceNodes
  • use ObjectPool for performance
  • Analyzer-like API/plugin support
  • print nicer diagnostics + usable location
  • support for speculative semantic model (simulation)
  • more declaration diagnostics
  • diagnostic fixers

Symbols

The symbols are the basis of semantic model object graph.

Symbol notes

  • ISymbol is the root type.
  • Links (BS EntryLink/InfoLink/CategoryLink) are represented as the symbol type that the link points to, its IsReference is true and ReferencedEntry points to the link target.

Symbol list

ISymbol is the top-level symbol interface. All symbols are an ISymbol

  • IGamesystemNamespaceSymbol - root symbol, contains all loaded data.

  • IModuleSymbol - data module root, most often one file is one module.

    • ICatalogueSymbol - contains data: definitions, entries.
    • IRosterSymbol
  • ICatalogueReferenceSymbol - references other catalogues from a catalogue.

  • IResourceDefinitionSymbol - defines a resource type: publication, cost, profile, characteristic.

    • IPublicationSymbol - special resource definition with additional details, like publisher.
  • IEntrySymbol // contains effects

    • IResourceEntrySymbol (can be a group, or group link)
      • ICharacteristicSymbol
      • ICostSymbol
      • IProfileSymbol (can be a link)
      • IRuleSymbol (can be a link)
    • IContainerEntrySymbol // contains constraints, resources
      • ICategoryEntry (can be a link)
      • IForceEntry
      • ISelectionEntryContainerSymbol // contains other SelectionEntry-like stuff
        • ISelectionEntrySymbol (can be a link)
        • ISelectionEntryGroupSymbol (can be a link)
  • ILogicSymbol

    • IConstraintSymbol // constraint, contains query
    • IEffectSymbol // modifier/modifier group/repeat, contains query and condition
    • IConditionSymbol // condition/condition group, contains query
    • IQuerySymbol // condition/constaint/repeat "query" part
  • IRosterCostSymbol // both value and limit (if set)

  • IEntryInstanceSymbol // has SourceEntry

    • IResourceSymbol
      • IRosterProfileSymbol
      • IRosterRuleSymbol
    • IContainerEntryInstanceSymbol // has custom name, notes
      • ICategorySymbol
      • ISelectionContainerSymbol // has selections
        • IForceSymbol
        • ISelectionSymbol

Implementation notes

BattleScribe has some unnatural or unexpected, or just unobvious behavior. Here we try to gather such cases:

  • Editing a roster results in Categories having new IDs, even if they/selections didn't change.

phalanx's People

Contributors

amis92 avatar arlo47 avatar carlheiberg avatar cloverfox avatar dependabot[bot] avatar jlueck6 avatar nstephenh avatar skuerzo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

phalanx's Issues

UI wireframe mockup POC thing

  • mobile first
  • hardcoded data if that even
  • 3 views:
    • roster metadata (name, points) - separate or not?
    • root selection list ("main" view)
    • selection edit view ("recursive" one)

Implement Logic in Symbol layer

ILogicSymbol is a parent type of the following:

  • IConditionSymbol (BS Condition/ConditionGroup)
  • IConstraintSymbol (BS Constraint)
  • IEffectSymbol (BS Modifier/ModifierGroup/Repeat)
  • IQuerySymbol (BS Modifier/Constraint/Condition's Query+FilterBy+Condition common abstraction)
  • IQuerySymbol and IEffectSymbol bindings of the field/scope/filter(child) IDs.

I've settled on a tiny simplification - modifier(group) and repeat are an Effect, condition(group) is Condition, and Query is a common part of querying in constraint, condition and repeat:

  • IEffectSymbol is either a modifier, modifier group or a repeat BS element unified into a single interface. May contain a Condition, and a RepetitionQuery. Entries contains Effects (modifiers/modifier groups) and an Effect can contain other Effects (repeats), as well as ChildEffects (in modifier group).
  • IConditionSymbol is either a condition or condition group BS element. Contains Query. Effects can contain up to a single Condition, and Conditions can have Child conditions that are evaluated using and/or operator.
  • IConstraintSymbol is a constraint BS element. Contains Query, but signifies a boundary/limit. Entries contain Constraints.
  • IQuerySymbol - is an abstraction over querying in conditions, constraints and repeats. It defines a Value (field) that is counted, a Scope in which elements are counted, and a Filter which takes only specific elements to count. Then the results are processed - if query defines a ComparisonOperator, the query result is compared with ReferenceValue - otherwise the numeric sum of values is returned.

Documenting Querying in BattleScribe

We need to document queries: what are legal combinations, how do they work, what are the results.

BS Nodes

The elements in BattleScribe that use queries are: condition, constraint, repeat.

These elements appear as children in other BattleScribe elements:

  • condition can be child of: modifier, modifierGroup, conditionGroup.
  • repeat can be child of: modifier, modifierGroup.
  • constraint can be child of: selectionEntry, selectionEntryGroup, entryLink, forceEntry, categoryLink in forceEntry, categoryEntry.

It's important to list all elements that can contain modifiers, since then they can also contain conditions and repeats within those modifiers. modifier can be child of:

  • all those that can have constraint (see list above)
  • profile, rule, infoGroup, infoLink.

Query components

The elements of a query are:

  • field - what is the counted value.
  • scope - where (in what subtree) are the values counted.
  • childId aka Filter By - which of the candidate entries/values do we actually process.
  • value - reference value that the query result is compared with.
  • comparison - condition and constraint uses it to compare the result with a reference value.
  • additional options: shared, value-is-percentage, include-child-selections, include-child-forces, round-up.

Known options

Field

Allowed values for a field in a Query:

  • selections - count the selections.
  • forces - count the forces.
  • specific Cost - sum cost values of the given Cost Type, looking at elements returned by the query.
  • specific Cost Limit - use roster limit of the given Cost Type (scope has to be Roster, filter is unused).

Special cases:

  • forces field allows only the following scope values: force, roster, specific force entry.
  • Cost Limit field allows only scope=roster. The field is then formatted like limit::{type-id} where {type-id} is the ID of the Cost Type.

Scope

Scope can be one of:

  • self - restricted
  • parent
  • ancestor - restricted
  • primary-category - restricted
  • force
  • roster
  • primary-catalogue
  • specific selection, category, or force entry

Special cases:

  • self is not allowed in constraints.
  • ancestor and primary-category are only allowed with comparison of (not)instance-of.
  • specific entries allowed:
    • any Category Entry
    • any Force Entry (including nested ones)
    • any Selection Entry that is ancestor of the querying constraint/modifier

Filter

Filter can be one of:

  • any (Anything) - noop.
  • unit/model/upgrade (Unit/Model/Upgrade) - all elements with specified EntryKind (type) are returned.
  • specific selection, category, or force entry

When filter has specified value:

  • any (anything) - all elements in the scope are returned.
  • EntryType (unit/model/upgrade) - all elements in the scope with specified EntryKind (type) are returned.
  • a Category Entry - all elements in the scope with specified category linked are returned.
  • a Force Entry - all elements in the scope that are instance of that entry.
  • any Selection Entry - all elements in the scope that are instance of that entry.

Special cases:

  • childId/filter in constraint is disabled. It is implicitly the constraint's parent entry.
  • complete reference of what is allowed when: #45 (comment)

Value

  • in repeat used to divide query result into "buckets", and for each such bucket there are N repetitions of the modifier applied (N is repeats value in BS XML).
  • repeat requires a positive value.
  • in constraint used to compare using comparison operator.
  • in condition used to compare using comparison operator. If it's a instance-of kind of operator, the value is unused.

Generally, negative values work as expected. The exception here is a -1 value for a type=max constraint - in that case, it is interpreted as "infinity" or "no limit". Further modifications of the value (e.g. by Modifiers) are calculated as normal, e.g. when a constraint of -1 is modifed to increase value by 1, now the maximum is 0 so the selections are not allowed. Any other negative value (e.g. -2) is treated normally (no special behavior).

Comparison

  • repeat has none.
  • condition has all numeric comparison operators and two special ones (instance-of):
    • (not-)equal to
    • greater/less than (or equal)
    • (not-)instance of.
  • constraint has min (greater than or equal) and max (less than or equal).

Special cases:

  • when scope is ancestor or primary-category, comparison must be (not)instance-of, thus those scopes are not available for constraint and repeat.
  • (not-)instance-of value of comparison is a special case in condition queries: there's no field defined, scope defines the checked entry, and childId/filter defines the type/entry the scope should be "instance of". When filter is:
    • any (anything) - it's a noop, always satisfied.
    • EntryType (unit/model/upgrade) - the scope should have that type.
    • a Category Entry - the scope should have that category linked.
    • a Force Entry - the scope should be instance of that entry.
    • any Selection Entry - the scope should be instance of that entry.

Options

shared - the query should sum up all instances of childId/filter in scope, disregarding the selection path. BS author explainer. โ“ When is this option allowed in Data Editor UI?

value-is-percentage - the value should be interpreted as percentage, and is limited to the range [0; 100].

include-child-selections - the scope includes selection subtrees (recursive/all descendants).

include-child-forces - the scope includes force subtrees (recursive/all descendants).

round-up - used in repeat calculations, rounds the division of result by value up, instead of down as is by default.

Loose notes

  • constraint has comparison defined differently: it has type of min or max - those are equivalent to greater than or equal and less than or equal values of type in condition.
  • value can be negative for constraint and condition. Details: #45 (comment)
  • repeat has no comparison (type), but instead declares a number of repetitions per multiplications of reference value in query result ((result / value) * repeats).
  • constraint of max value has an interesting quirk. When an entry has a constraint of type=min scope=parent value=0, the entry is hidden in Roster Editor, as it's not allowed to be selected. As expected, using a Modifier to Set that constraint's value to -1 makes this entry selectable (unlimited) and it's correctly shown in Roster Editor. However, when using a Modifier to Decrease the value by 1 (making it 0 - 1 = -1 - unlimited), the Roster Editor does not show the entry (incorrectly?), as that entry is unlimited due to the new value of max constraint.

โ“ What are other unobvious interactions?

UI framework selection hackathon

The idea here is to organize a "hackathon" where, given sample data set and (maybe?) a mocked API for Data Engine, a person creates a prototype UI in their framework of choice.

Then we compare entrant's "submissions" and select the winning framework, based on several factors of which an important one should be the availability of people interested in driving the implementation.

Data Browser

Currently there is no way to browse battlescribe data in a human readable format.

Amis and I were discussing this, and we decided this would be a good project, and be something that will excite users. It will also help us discover bugs in our loading code.

Alternatives you've considered
We talked about updating godmode, but decided this makes more sense as a part of Phalanx. Godmode is old and uses an old version of WHAM, and some needed parts of WHAM may be in the phalanx project.

Implement Symbol layer for Roster

Parts:

  • Symbols:
    • RosterSymbol
    • RosterCostSymbol
    • ForceSymbol
    • SelectionSymbol
    • RosterRuleSymbol (currently used RuleSymbol doesn't reference original Rule entry, needs ID resolution like Selection)
    • RosterProfileSymbol (currently used ProfileSymbol doesn't reference original Profile entry, needs ID resolution like Selection)
    • RosterCharacteristicSymbol (for reasons like for profile)?
  • Symbol binding:
    • CostType for RosterCostSymbol
    • ForceEntry for ForceSymbol
    • Category for special (No Category) value

Roster browser (roster list, select/click to edit etc)

Create a screen for displaying rosters, and selecting one to load and 'edit' on the Roster Edit.

  • For a first pass, loading a file from the server-side is fine; file management can be left to another task for now
  • List a handful of rosters from local files (again, punt on file management for now unless you want to tackle that at the same time)
  • Let user click a ListItem or control on it to load the roster into RosterEdit

For later:

  • Use files/folders loaded by the user - for mobile... can Razor be deployed so it has a local app folder that's automatically uploaded?
  • (file management in general is probably a separate, larger issue than this one)
  • Delete a roster from Roster Select view

Selection Edit: first pass

Let user select an item from the root Roster edit screen, and open a Selection Edit screen.
For now, Symbols and etc aren't in place for editing, so this will be a view-only screen.
Although editing isn't possible yet, adding the UI to edit ints, dropdowns, etc, could still be created.
Selection Edit should allow a Selection to be ...selected, if it has subselections, and show those subselections (ie, the SelectionEdit should have some recursion to it)

Implement data acquisition

Enable browsing BSData Gallery and downloading files from there.

For MVP here, we're aiming at:

  • downloading the Gallery JSON index: bsdata.catpkg-gallery.json form https://github.com/BSData/gallery/releases/tag/index-v1
  • showing a game system (repository) selection UI for a new roster - keep ability to select Sample Dataset
  • try to match the gamesystem ID with Gallery JSON's item (repository) when opening a roster.

BSData Gallery is a nuget.org/npm.org like Registry/Gallery that indexes gamesystems. It provides a static index asset.

Datafiles are available from GitHub data repositories via GitHub release assets. Sadly, those assets do not have CORS headers set, so that downloading them in a browser won't work.

Solutions I can see:

  1. Make Gallery "cache" the actual assets in a branch published to GitHub Pages. Content published there is CORS-enabled and can be freely downloaded in a browser.
  2. Create and use our own CORS-proxy. One thing I've researched is a Cloudflare-cors-proxy, using Cloudflare Workers.

Show some sort of loading indicator

Ideally we should add some sort of "loading" icon to the UI as it often hangs when doing computationally intensive tasks. Godmode also had this issue.

Create a settings section (cost limits, name etc) Roster Edit

Currently, Game Options show up as a Selection (since, they are one).

Either use the 'Options' tab stubbed out in the sample roster edit or determine a new way to open and edit the Roster's Game Options.

  • Save game options changes to RosterState
  • Editing + saving the roster name (and updating Roster Edit with it)
  • Editing + saving Notes for the roster
  • Reflect Game Options in the Roster Edit screen (e.g. 50 / 100 points)

Data management UI

Adding UI for managing data sets (game systems, catalogues etc).

Browsing Gallery/Appspot content and selecting which items to download,
and showing which are currently installed locally.

The backing code is supposed to be done in #25

Features:

  • Show a list of repositories from a Catpkg Gallery (see #25)
  • Elements (repositories) can be selected to be locally loaded (downloaded into the browser memory)
  • Elements should show some details like name, date, version
  • Elements should show a message/icon that an updated version is available (compared to locally downloaded)

A repository can have different states:

  • listed as "available to load"
  • listed as "loaded locally" and then:
    • it can have an "update available"
    • or it can be "up to date"

Data and editor behavior specification

The general objective is to create a dataset (gamesystem + catalogues + rosters) that has a very strictly defined desired behavior (mostly in terms of roster editor behavior). Those expectations (desired behaviors) should be described as well.

I'd imagine it working like that:
A "scenario package" consists of a game system, a catalogue, a roster and a scenario (free-form/markdown). The scenario describes steps taken in a roster editor and expected changes/behavior (e.g. warnings, options being hidden) to be observed. The package could also include reference rosters that a user should get following the scenario steps.

The dataset (game system and catalogues) could be shared across all scenarios and include all necessary permutations of data to be checked in scenarios.

It's essentially a spec for BattleScribe as is, and we will be able to further enhance it in future as we make changes, making sure to keep a back-compat should we desire to do so.

It's a giant project overall (the spec, in full), but I think starting with a basic "sample dataset" should be quite straightforward.

Binding links to nested entries

Describe the bug

Currently, the Binder fails to bind references (links) to nodes (entries) which are not directly in a Shared list.

It seems BattleScribe has no problems resolving links to nested nodes, at least for profiles/rules. Further verification required as to what scopes and nodes are allowed. BS however doesn't offer such nested nodes in UI to select from.

Expected behavior

Bind like BattleScribe does. Consider setting this behavior as a feature, to possibly deprecate it in future or warn on usages.

Export roster feature

Saving the roster as a .ros or .rosz file for interoperability with BattleScribe.

From UI we should have a "save" button in a Roster Edit view, which will download the file in the browser.

Roster Management UI

Roster list view (user rosters) which you can select from, and open for editing.

As a stretch goal, an import roster button with file drop area or file picker would be cool.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.