SDK

Learn what data structures you can create with our tool

Game Mechanics

Quest

Reward

Specifies the number of assets to be granted to the user atomically as a single pack. Can be given by the game engine either as a result of crafting, advancing battle pass, etc.

reward = Reward("level_clear_reward")
reward.add(GEMS, 5)
reward.add(GOLD, 1000)
reward.add(item, amount)

"item" can be either:

1. Instance of BaseData subclass created with BaseData.define, and denotes some indistinguishable asset (gold, gems, blueprints etc whatever game design supposes)

2. DataModelTemplate instance

Progression ladder

The progression ladder is an implementation of "upgrade something" game mechanics. To create a progression ladder for DataModel one should call ProgressionLadder constructor.

Its arguments are:

  • Entity - subclass of DataModel. Model to which we should add the ladder

  • IsExperienceBased - we have ladders of two types. When IsExperienceBased is False then to upgrade the entity to the next level you should pay some Cost. Otherwise generated ladder is based on the difference between experience value levels.

  • LevelField - Name of level field in entity. Optional, "Level" by default.

  • ExperienceField - Name of experience field in entity. Optional, "Exp" by default.

  • LadderLevelData - subclass of BaseData. Contains per-level specific static data. During code generation will be augmented with Exp, Reward, and Cost fields.

class CharacterData(BaseData):
  Name: str
  Description: str


class Character(DataModel):
  Exp: int
  Level: int
  Data: DataRef[CharacterData]


class CharacterLadderLevelData(BaseData):
  SomePerLevelIntValue: int
  SomePerLevelStrValue: str


CharacterLadder = ProgressionLadder(
  Entity=Character, 
  IsExperienceBased=True,
  LadderLevelData=CharacterLadderLevelData)


WizardLadder = CharacterLadder.new_ladder('WizardLadder')
exp = 100
step = 100
for lvl in range(1, 10):
  WizardLadder.add_level(Exp=exp, Data=CharacterLadderLevelData(
    id='character_level_{lvl}',
    SomePerLevelIntValue=random.randint(1, 9),
    SomePerLevelStrValue=“some_string_{lvl}“))      
  exp += step
  step += 100

Battlepass

RegularBattlePass = BattlePass(Name='Regular')

REGULAR_BP_STANDARD = RegularBattlePass.define('Standard')
REGULAR_BP_PREMIUM = RegularBattlePass.define('Premium')

for lvl in range(1, 10):
    regular_reward = Reward()
    regular_reward.add(GOLD, 100 * lvl)
    REGULAR_BP_STANDARD.add_level(Exp=100*lvl, Reward=regular_reward)

    premium_reward = Reward()
    premium_reward.add(GEMS, 100 * lvl)
    REGULAR_BP_PREMIUM.add_level(Exp=100*lvl, Reward=premium_reward)

Tournament

Craft rule 🔨

The game engine supports crafting as a first-class primitive. "Crafting" in terms of HyperEdge is exchanging a set of assets of certain types for other assets set.

craft = CraftRule("magic_brewery")
craft.require(MAGIC_POWDER, 1)
craft.require(MAGIC_WOOD_BERRY, 5)
craft.require(GOLD, 10)
craft.product(SMALL_HEALTH_POTION, 1)

Items to be spent are added to require call. Items to be granted add with produce call. Internally CraftRule has Reward and Cost instances and require is Cost.add method call and produce is Reward.add respectively

Cost 💲

Specifies the amount of assets to be spent to buy/craft/burn/etc to perform some action according to game logic

cost = Cost()
cost.add(item, amount)
cost.add(GOLD, 100)

The item can be either:

- Instance of BaseData subclass created with BaseData.define, and denotes some indistinguishable asset (gold, gems, blueprints, etc.)

- DataModelTemplate

Energy

LevelEnergy = EnergySystem(Name='LevelEnergy')

USER_LEVEL_ENERGY = LevelEnergy.define(
    Name='UserLevelEnergy',
    InitialValue=80,
    RegenValue=1,
    RegenRate=1,
    MaxCapacity=100)

Inventory

Auxiliary Models

BaseData

BaseData — represents virtually any static chunk of data in a game from text descriptions to power levels, damage amounts, and experience ladders.

class MagicStoneData(BaseData):
  Name: str
  Power: int
  Mergable: bool
  Element: DataRef[ElementData]
  

FIRE_STONE = MagicStoneData.define(
  Name=“Fire stone“,
  Power=100,
  Mergable=True,
  Element=ELEMENT_FIRE)
WATER_STONE = MagicStoneData.define(
  id=“Water stone“,
  Power=200,
  Mergable=True,
  Element=ELEMENT_WATE

To create instance (*warning*: don“t directly call constructor of BaseData subclasses it will skip all necessary bookkeeping) use define call. All fields except those specified with optional_field should passed to the constructor. Also special parameter id should be passed which should be:

- lowercase

- contain only alphanumeric and underscore

- should start with a letter

Also as a convention, if there's Name field defined it'll be used automatically if id is omitted. Name will be split by space, then all parts will be converted to underscore if they contain CamelCase, then converted to lowercase and joined by underscore

Structures will be generated for this class. DataRef is a special type to reference instances of some other BaseData. In code, it will be represented by type-safe enumeration containing all instances of that enumeration. All data instances are serialized into GameDb table

DataModel

Represents virtually any dynamic data model in a game from heroes, equipments with upgradeable levels, and stats to some per-player scores. As in an example we can use different field types. A set of APIs and structures is generated for DataModel. All models are per-user and belong to her.

class Character(DataModel):
    Level: int
    Exp: int
    Data: DataRef[CharacterData]
    ItemsList: typing.List[Ulid]
    CurrentDialogBubble: str
    IsBusy: bool
var user = await GameContext.GetUserAsync(req.UserId);
var character = user.GetCharacter(req.CharId);
character.CurrentDialogBubble = "I need more experience!";
user.UpdateCharacter(character);

By convention Data is a special field that refers to the model's static data or meta. It is handled in a special way by the code-generation backend. There“s a special class DataModelTemplate which represents all data models initialized with certain BaseData subclass instance.

WIZARD = CharacterData.define(Name=“Wizard“, Power=100)
wizard_template = Character.new_template(WIZARD)

Handler

Handlers are used to express any server-side game logic. Handler class constructor takes 4 parameters:

  • Name - name of the request handler, should be valid C# method name

  • RequestClass - subclass of _BaseModel. C# structure of the same name is generated for this model.

  • ResponseClass - subclass of _BaseModel. C# structure of the same name is generated for this model.

  • Code - valid C# code for handler method body (only function body). It gets req parameter of the type generated for RequestClass parameter and should return an instance of the structure defined by ResponseClass. This parameter is optional during construction of Handler, as it is more convenient to initialize it later.

class SendCharactersToQuestReq(_BaseModel):
    QuestId: int
    Characters: typing.List[Ulid]


class SendCharactersToQuestResp(_BaseModel):
    Success: bool


SendCharactersToQuestHandler = Handler(
    Name='SendCharactersToQuest',
    RequestClass=SendCharactersToQuestReq,
    ResponseClass=SendCharactersToQuestResp)


SendCharactersToQuestHandler.Code = """
var failResp = new SendCharactersToQuestResp { Success = false };
var user = await GameContext.GetUserAsync(GameContext.CurrentUserId);
var questData = GameDb.GetQuestData(req.QuestId);
foreach (var charId in req.Characters)
{
    var char = user.GetCharacter(charId);
    // User logic goes here
}
return new SendCharactersToQuestResp { Success = true };
"""

Storage

Last updated