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 someCost
. 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 forRequestClass
parameter and should return an instance of the structure defined byResponseClass
. This parameter is optional during construction ofHandler
, 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