Atavism Blog

Atavism Blog

Here you will find Blog posts about atavism

  • Home
    Home This is where you can find all the blog posts throughout the site.
  • Categories
    Categories Displays a list of categories from this blog.
  • Tags
    Tags Displays a list of tags that have been used in the blog.
  • Bloggers
    Bloggers Search for your favorite blogger from this site.
  • Team Blogs
    Team Blogs Find your favorite team blogs here.
  • Login
    Login Login form
Recent blog posts

As developers look to get more serious about their game development we thought it would be a good idea to run another round of tests to get an idea of how well the Atavism Server performs when put under different loads. These numbers don’t just show how well the Atavism Server runs, but helps give you an idea of how much you can put in your game and how many resources your servers will need.

This first round of tests covers the basics of an empty server, static mobs, moving mobs and small groups of players. The information from the tests is given below with some analysis and recommendations at the bottom.

Notes:

  • CPU Usage (Ghz), Memory (GB) and Bandwidth In/Out (KBps) are recorded for each test
  • The world used was a 4km by 4km square. Mobs were randomly spawned within that area.
  • NavMesh is not used for these tests. Later tests will include this.

 

Test 1: Empty Server over 3 weeks

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.054

1.04

0

0

1 week

0.056

1.56

0

0

2 weeks

0.052

1.92

0

0

3 weeks

0.054

2.44

0

0

 

Analysis:

The basic Atavism Server looks to be very stable now, being able to run for long periods of time without issue. You will notice the Memory use does increase by a very small amount over time but the amount is minimal and it is good practice to run maintenance weekly which will reset it.

 

Test 2: Static Mobs, 1 template

a)      100 Mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.053

1.08

0

0

30 minutes

0.053

1.08

0

0

 

b)      500 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.054

1.09

0

0

30 minutes

0.054

1.09

0

0

 

c)       1000 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.076

1.98

0

0

30 minutes

0.076

2.03

0

0

 

d)      5000 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.088

2.98

0

0

30 minutes

0.088

2.98

0

0

 

e)      20000 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.208

4.26

0

0

30 minutes

0.208

4.26

0

0

 

                Analysis:

As expected, static mobs have minimal effect on the server. Using the numbers above we see each mob using about 0.2 – 0.3MB of memory each. There appeared to be no change over time for the static mobs.

 

Test 3: Roaming Mobs (10 metre radius), 1 template

a)      100 Mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

0.306

1.99

0

0

30 minutes

0.309

2.00

0

0

 

b)      500 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

1.02

2.26

0

0

30 minutes

1.15

2.26

0

0

 

c)       1000 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

2.44

3.04

0

0

30 minutes

2.46

3.05

0

0

 

d)      5000 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

5.01

7.89

0

0

30 minutes

5.18

7.97

0

0

 

e)      20000 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

Startup

20+

10+

0

0

30 minutes

20+

10+

0

0

 

                Analysis:

The server starts doing a lot more work when mobs are moving, which is expected. The server hit its limits on the 20000 mobs that were moving which will be due to the Quad Tree system being overworked having to constantly move the mobs between nodes as they are too close together having 20000 in a 4km by 4km area.

 

Test 4: Players in game with non-roaming mobs chasing them after being aggravated.

a)      100 mobs, 5 players, 10 mobs chasing

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

5 minutes

1.90

1.90

8

18

30 minutes

2.07

2.07

13

28

 

b)      500 mobs, 10 players, 50 mobs chasing

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

5 minutes

3.28

3.70

17

36

30 minutes

4.77

5.01

17

36

 

c)       1000 mobs, 20 players, 100 mobs

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

5 minutes

9.01

6.99

23

70

30 minutes

9.97

7.24

24

81

 

d)      5000 mobs, 25 players, 1000 mobs chasing

Time Lapsed

CPU Usage

Memory

Bandwidth In

Bandwidth Out

5 minutes

15.26

10.99

21

100

30 minutes

20+

11.03

26

122

 

                Analysis:

There’s good news and bad news here. The good news is that the bandwidth seems very much within reasonable levels. The bad news is causing mobs to aggro and chase players around seems to have a bit more of a hit on the server. The additional good news though is with this information the aggro system can be looked at and improvements made to bring it back into line (before the next release).

 

Conclusion:

Overall it’s very good news for the Atavism Server’s performance. From the tests so far there is one area that needs to be looked at and it is an area that is easily changed without effecting much else of the code. We will always be looking to improve these numbers as well, and there are a few plans in place to add additional optimisations to improve performance of mobs on the server.

With this information you need to think about your game and how many mobs and players you want to have and how powerful your servers will need to be. The one thing to keep in mind is to be smart about your mob placement and how many you have in your world.

Keep an eye out for more information about tests including more player performance testing and resource nodes.

 

 

 

 

                                                                                                                

Hits: 1028

Posted by on in Uncategorized
AGIS Combat Traces

Most up-to-date version: AGIS Combat Traces (Google Drive)

Contents: AutoAttackTrace AbilityTrace EffectTrace CoordEffectTrace StatTrace EquipTrace

Hello everyone!

I'm fairly new to Atavism and, like many of you, am developing an MMO starting from scratch. This document started as my attempt to understand how auto-attack works but has evolved somewhat into a decent reference for the combat system. It is not complete, but it covers the basics. I define a trace as a logical chain of events in the code from start to finish. The traces involve files along the chain from player to server to database so they may refer to Java or CSharp files and include Unity, Server, and AGIS code references (AGIS requires a Veteran License). Keep in mind that many of the function references are not written verbatim from the code and are sometimes altered to make it easier to remember what certain variables represent. For example, an ability’s caster is referred to as ‘caster’, ‘obj’, ‘attacker’, and ‘source’ in different areas of the code and I simply wrote ‘attacker’ every time to keep it easy to remember. Sometimes I’ve directly copied comments from the code when they are descriptive. Furthermore, the language is often short-hand and not in complete sentences because I was moving fast. I encourage other developers to expand upon this and other plugin systems so that we can have basic references for everything.

Credits: to the Atavism Online team (Jacques and Andrew) for building the system and providing me permission to post this.

Version: Atavism 2.1.1 (will update if there are major changes, see Google Drive link at the top for most up-to-date version)

Note: This document is too long to fit into a blog entry so you'll only find part of it here and the rest on Google Drive.

AutoAttack Trace

This trace aims to document what happens from the moment a player clicks on a mob to the moment that mob’s hp is decremented. The journey through the code is a long one, but it is due to the level of sophistication of the intervening code that provides many contingencies for failure, result possibilities, and innumerable opportunities for customization.

Cursor.cs

  • Mouseover object click on ‘attackable’ object

  • NetworkAPI sendAttackMessage with object ID (Oid), attacktype (strike), attackstatus (true)

  • Message client “sent strike attack for” Oid (number displayed is not damage amount, it is object id

NetworkAPI.cs

  • SendAttackMesssage (Oid, attackType, attackStatus)

  • AutoAttackMessage sent via Client.Instance.NetworkHelper.SendMessage

CombatPlugin.java

  • AutoAttackHook intercepts msg

  • Obtain attacker id and target id and attackstatus

  • Load CombatInfo for both

  • Lock player and target CombatInfo objects and only unlock when attack is over

  • if status is false or obj dead or no target or target dead, stopAutoAttack() and set COMBAT_TAG_OWNER to next aggressive mob, else obj.setAutoAttack(targetOid)

CombatInfo.java

  • obj.setAutoAttack(targetOid), lock first and unlock when done

  • if newtarget is same as oldtarget, return (we are already attacking)

  • if not, we need to start a new attack, so setCombatState (true) and if not scheduled, schedule the auto attack with schedule(getAttackDelay() which checks attack_speed) as the update interval for CombatInfo object run() method

  • remove the old attacker from our list and if we have a null new target, we want to turn off combat by setCombatState(false), but if we do have a new attacker we want to addAttacker(target, getOwnerOid()) to the list

  • setCombatState sets COMBAT_PROP_COMBATSTATE, and broadcasts message that we are in combat and that weapons are unsheathed.

CombatPlugin.java

  • addAttacker (OID target, OID attacker)

  • lock combatplugin to do this

  • Add player’s OID as one of the attackers to this mob’s attacker hash map or create a new attacker map if it is null

  • make sure this target is tagOwner (current target?)

CombatInfo.java

  • run() method for both attacker and target is scheduled according to their attack_speed (getAttackDelay())

  • Lock the CombatInfo object for attacker and target

  • Get the attack ability id from COMBAT_PROP_AUTOATTACK_ABILITY and continue if successful

  • if target is null or the entity it points to is null, stop scheduling

  • Otherwise CombatPlugin.resolveAutoAttack(this CombatInfo) for both attacker and target and schedule next run() method with getAttackDelay()

CombatPlugin.java

  • resolveAutoAttack(this CombatInfo)

  • Get CombatInfo objects from attacker and target

  • if target is null or attack ability not valid, return

  • Some temp AI code here but the running code does the following: if the attacker isn’t the player (isUser(), COMBAT_PROP_USERFLAG false) then set the maxHealth, curHealth to health-max and health stats and healthPercent calculated as float, but these numbers aren’t used for anything locally currently.

  • Get AgisAbility object ability from abilityID

  • More temp AI code here: If the abilityID is no longer the autoattack (currently not possible), the previous AI code wants the mob to cast a spell, so a message is sent to the client that the mob begins casting the ability name.

  • Duel code: if both attacker and target are players get duelIDs for both and if they are in the same duel, then setDuelID on the autoattack ability (which does nothing as of now ?)

  • AgisAbility.startAbility(ability, info, target, null) finally executes the autoattack for attacker and target (as earlier, delay is based on attack_speed) --> See AbilityTrace

 

Ability Trace

Abilities can range from auto attack to heals to sophisticated high level damage spells and may even be general enough to be completely unrelated to combat if creativity is used.

AgisAbility.java

  • startAbility(AgisAbility ability, CombatInfo source, CombatInfo target, AgisItem item, Point loc)

  • For this ability, generateState(source, target, item, loc) which returns AgisAbilityState obj (see AgisAbilityState constructor for details--if the ability is TargetType.SELF it sets the target to the source=attacker and a message hook is setup in case the attacker is moving so the ability can be interrupted) and updateState() called

AgisAbilityState.java

  • updateState ()

  • source (attacker) and target are already defined from the generateState earlier, so this first locks the attacker and the target and all potentialTargets which may change throughout the course of the ability

  • ActivationState state is INIT by default, enum defined in AgisAbility. Ability can be in INIT, ACTIVATING, CHANNELING, ACTIVATED, COMPLETED, CANCELLED, INTERRUPTED, or FAILED states

  • Depending on state, switch will perform the correct type of update

  • For all updates, a series of checks is performed on the ability to determine whether to go forward. if the checks succeed, AbilityResult.SUCCESS is returned and if they fail, a different AbilityResult is returned and AgisAbility.interruptAbility is called with the result, which resets the states (if fails during init runs init coordinated effects of ability? --> See CoordEffectTrace ) and sends a message.

AgisAbility.java

  • checkAbility(source, target, state)

  • The checks for INIT are if the attacker is ready (not performing another action), if the target type makes sense depending on the ability target type, if the target species makes sense depending on the ability type, if the ability only works on specifically named targets and that target is selected (allows object interaction ?), if the player/target is alive, or if the target should be dead (resurrection), if the target is within range for starting the ability (too close or too far), and finally if the ability has any effect requirements that are active like just having dealt a crit, having last attack dodged, having used a certain ability within the past 5 seconds, etc (works by storing all effects player gets into a list and then listing what numeric effect values an ability requires to activate--can be >1effect required).

  • The checks for other states (including INIT) are if the attacker has/knows the ability, if the ability is a passive ability that shouldn’t be activated, if the attacker requires a tool or reagent in their inventory and if they have it, if the attacker has enough ‘costProp’ (the property required by the ability, usually mana) or vigor (which is like rage in that some abilities add vigor and some need vigor) to use the ability, if the target is within range for continuing the ability (too close or too far), and finally if they are in the correct combat stance (not fully coded).

(CombatMeleeAbility.java)

  • For CombatMeleeAbility, which is the default player auto attack ability, it extends AgisAbility, so retains the same properties as AgisAbility and adds the following: checkAbility does the default checks and then sendAbilityFailMessage with result if failure. Otherwise, checkPosition (not coded yet), then checkEquip to see which weapon type is required and if it is equipped.

  • If ACTIVATING, reset params to default, call changeCoordinatedEffect(“success”) to reset the result parameters (which may become block/partial resist later).

  • The next piece of code is confusing in regards to player vs target, especially the in-line comments. Checks target’s defenses: sets defensiveType to ‘dodged’ (default) and weapType to target’s weaponType (possible error--shouldn’t this be the weapon of the attacker?). Checks if target has a parry effect for this weapon type and if so, does the target also have the skillType required. If so, set defensiveType to ‘parried’.

  • hitChance = CombatHelper.CalcPhysicalHitChance(attacker, target, skillType)

CombatHelper.java

  • CalcPhysicalHitChance(attacker, target, skillType)

  • dexterity taken from CombatPlugin.PHYSICAL_ACCURACY_STAT, targetPerception = 20 (arbitrary, temp?), targetLevel taken, attacker skillLevel set to attacker level * 10 if attacker doesn’t have skill (arbitrary?), and to attacker’s skill if he has it.

  • hitChance = Math.atan((dexterity * skillLevel) - ((targetPerception * targetLevel)/1400) * 0.3) + 0.7

  • This calculation is arbitrary and there is a ‘New Formula’ above it commented out.

(CombatMeleeAbility.java)

  • Next get a random value [0,1] and hitRoll = rand * 100

  • If the rand > 0.95, the ability has missed. Set attackerResult in params to missed = 3, changeCoordinatedEffect(“missed”), get casterResultEffect and targetResultEffect for the miss, which are effects that are later applied to both parties in the event of the miss.

  • If the rand > hitChance, the ability was dodged or parried if the target defensiveType was set to parried earlier. Set attackerResult in params to dodged = 5, changeCoordinatedEffect(“dodged”), get caster/target result effects, similar for parry.

  • There are some other commented-out possibilities including blockChance, critChance

  • Else, the ability has hit successfully and attackerResult = 1. Even if the ability didn’t hit, AbilityResult.SUCCESS is set to continue updating the ability state.

AgisAbilityState.java

  • In updateState(), If AbilityResult.SUCCESS

  • If INIT, setCurrentAction for attacker to AgisAbilityState.INIT, then move to nextState(), run coordinated effects for this state using effect.invoke(getSourceOid(), getTargetOid(), location, this) -->See CoordEffectTrace and then another switch statement controls the new state

  • If ACTIVATING, which is next state, check the activation time and if there is an animation for it, run that (and also check the castingAffinity and send that to the attacker as well ?), then send the casting started message, set the duration of the activating state (getActivationTime()), and then schedule the run() function of AgisAbilityState to execute once that time has elapsed, which simply calls updateState() again to check the state and advance it. This then calls ability.completeActivation.

AgisAbility.java

  • completeActivation(state)

  • Gets attacker, target CombatInfo objs

  • Checks if reagents are required and if consumeReagents is active before removing reagents from inventory via AgisInventoryClient.removeGenericItem(OID, itemID, removeStack?, numToRemove)

  • Checks for a costProp (like mana) and subtracts from that property using CombatInfo.statModifyBaseValue(costProp, -activationCost), does similar with vigor stat except adds or removes (vigor is like building rage with abilities), then sendStatusUpdate() which is not coded.

  • Checks for effects that must be consumed by attacker and target (required effects or debuffs) and removes them with AgisEffect.removeEffect(EffectState existingState).

  • If attacker is player, send message to client that ability was used

  • Activate cooldowns in CooldownMap with Cooldown.activateCooldowns(cooldown collection, CombatInfo obj, quickness value = 100)

  • Smoo only? decrementWeaponUses message broadcasted ?

(CombatMeleeAbility.java)

  • For CombatMeleeAbility, it retains the same properties from completeActivation and adds the following: also setCombatState(true) on the target, (if AREA_ENEMY =AoE ability gets a list of attackable targets in radius with getAoETargets(attacker’s CombatInfo)).

  • For every activation effect, put attackerResult, skillType, hitRoll into params. Get the target of this effect, and next condition checks all AoE targets and finally calls AgisEffect.applyEffect(activationEffect(i), attacker, target, params), (-->See EffectTrace) to all targets. If not AoE, checks if the target is attacker (self) and then applies the effect with the function above before clearing the params.

  • Last, the casterResultEffect and targetResultEffect are applied (-->See EffectTrace) in the same way.

AgisAbilityState.java

  • Next it moves to nextState() which is CHANNELLING or ACTIVATED or (COMPLETED if not persistent) depending on ability and coordinated effects are run for that state -->See CoordEffectTrace.

  • If CHANNELLING, duration of the CHANNELLING state is set to the number of pulses * pulse time and it is scheduled to run again after one pulse time. ability.pulseChannelling(this) is called (which subtracts from costProp the cost per channel pulse) and nextPulse is incremented and scheduled to run after pulse time and updateState() returns so it can repeat until the number of pulses is up before moving to nextState() which is ACTIVATED or COMPLETED depending on ability persistence. For CombatMeleeAbility, AgisEffect.applyEffect(channelEffect, attacker, target) is called, -->See EffectTrace

  • If ACTIVATED, the current action is set to null since the attacker is no longer busy activating/channeling, the ability is added to active abilities via addActiveAbility(this) and update is scheduled for ActivePulseTime.

  • After return pulseActivated(this) is called (which subtracts from costProp the cost for an activePulse) and nextPulse incremented. Then the function schedules for ActivePulseTime and returns indefinitely without progressing to the next state (is this return intentional?). The only way for it to move to completed is for the state to be changed to COMPLETED elsewhere. For CombatMeleeAbility, AgisEffect.applyEffect(activeEffect, attacker, target) is called, -->See EffectTrace

  • If COMPLETED, setCurrentAction to null since we are no longer busy, terminate the casting animation and castingAffinity (?)

  • Finally unlockAll because the ability is finished

...Continued at AGIS Combat Traces (Google Drive)

 

Hits: 5328

Posted by on in Uncategorized
Dialogues

To create a more lively and interactive world you want NPC’s that have something to say to players when they click on them. This can range from a friendly chat message such as “Hi, welcome to the town, it is always nice to meet new travellers” to story based dialogues that can have response options.

Atavism provides support for these features through the Dialogue System. Developers can create single or chained dialogues using the Atavism Editor and assign these to NPCs with the in-game spawn tool. The steps to create Dialogues are detailed below along with possible ideas/plans for the future.

 

Creating a Simple Chat Dialogue

Simple Chat Dialogues are used for a simple greeting that does not present any response options. Chat Dialogues can be used in conjunction with other NPC Interaction options such as Merchant and Quest Giver. When the player clicks on the NPC it will display the chat dialogue at the top with any other interaction options listed below.

To create the Dialogue click on the Dialogue Plugin in the Atavism Editor. Give the dialogue a name (used to help find it later) and leave the Opening Dialogue and Repeatable boxes ticked (opening dialogue means it comes up as soon as you talk to the NPC, repeatable means it can show up numerous times).

Change the prereq settings as desired. If any are set, the dialogue will only come up if the player matches the requirement. A common setting will be to set a faction and stance so the NPC will only talk to players who it is friendly with.

The final step is to write in the dialogue text. Click save and your dialogue is ready to be added to an NPC.

 

Creating a Chained Dialogue with Options

Chained dialogues allow multiple blocks of text to be shown to a player using buttons to progress to the next dialogue. Each dialogue can have up to three actions or choices which can cause the next dialogue to show up (based on their choice).

Note: If an NPC is given a dialogue with actions/choices along with other interaction options (such as quests) the dialogue will not come up straight away, but the title of the dialogue will be shown as a button the player can click on.

Creating the chained dialogue starts off the same as a standard dialogue (instructions above). Once the dialogue has been saved it will appear with some Actions at the bottom. Adding the next dialogue in the chain is achieved by filling in the text for the action (the response the player can choose) and clicking on Create Dialogue.

You will be back to the Create a New Dialogue window, but with two differences: there is a Go Back to Previous Dialogue button, and Opening Dialogue has been unchecked. When you save this new dialogue, the Atavism Editor will automatically link this new dialogue up to the previous one.

With the second dialogue saved, the Go back button can be clicked to return to the first dialogue and more actions can be added by clicking Add Action. Further chained dialogues can also be added to the second dialogue by repeating the same process from the second dialogue, allowing the creation of the complex tree of chained dialogues if wanted.

 

Adding a Dialogue to an NPC

To add a Dialogue (or multiple) to an NPC, log in game with an admin account and bring up the spawner tool (type /spawner in the chat box). Either bring up the UI to spawn a new mob, or select and existing mob and click on the Dialogues button in the UI. From here you can select which dialogues to give the spawn.

Once happy with your selection, close the Add Dialogues window and click Spawn/Save. Your NPC will instantly offer the dialogue to players who click on it.

Note: For chained dialogues, you only need to add the first dialogue in the chain (the one with Opening Dialogue ticked).

 

Final Notes

You may notice that the Action Type drop down has two more options: Quest and Ability. These aren’t supported yet, but the plan is to allow the starting of a Quest or the performing of an ability at the end of a dialogue chain. Possible ideas for the ability use would be teleporting the player somewhere or giving them a buff when they click on the option provided by the NPC. A lot of potential to come. This will open up a lot of potential for NPC interaction.

 

Hits: 2616
0
Creating and Accessing Properties Part II

In Part I we covered creating and adding properties to our characters and mobs. It’s all good having properties on them, but to be of any use we need to access them. This second part covers accessing properties both in-game and at the Character Selection scene along with setting up listeners for when properties change.

 

Accessing/Reading Character Properties at the Selection Scene

Properties can be easily accessed for any character in the selection screen by adding the property key (name) to the end of the CharacterEntry object, such as:

string gender = (string)characterSelected ["gender"];

Where characterSelected is the CharacterEntry object for the currently selected object. The property value will need to be converted to the variable type wanted (such as string or int). Be careful when adding new property getting code here as if the character doesn’t have the property it will error out the Character Selection scene.

Note: The example above or similar can be found in the LoginUI.cs or CharacterSelectionCreation.cs (UMA) files, generally in the DrawCharacterSelectUI() or equivalent.

 

Accessing/Reading Character or Mob Properties in game

Getting player and mob properties in game is done by getting the ObjectNode or AtavismNode for the player/mob and calling GetProperty(“property_name”) on it. For example, in the MobController3D class:

bool dead = (bool)GetComponent<AtavismNode>().GetProperty("deadstate");

The slightly tricky part is getting the ObjectNode/AtavismNode, as depending on the situation there are different ways.

Getting the ObjectNode for the local player is done using:

ClientAPI.GetPlayerObject()  - See PlayerPortrait.cs

 Getting the ObjectNode for the current target for the local player is done using:

ClientAPI.GetTargetObject() - See TargetPortrait.cs

 To get the ObjectNode for any other mob or player you can get it by using:

ClientAPI.GetObjectNode(long oid) – if you have the OID for it

 Or you can get the AtavismNode if you have the gameObject to work with:

gameObject.GetComponent<AtavismNode> () - see Cursor.cs Update() function.

 

It may be a bit confusing at first (especially if you are not a programmer), but if you look through the files mentioned above it should give you a better idea.

 

Creating Property Change Handlers

Property Change Handlers are used to run updates/changes when a property has been changed (such as the health of the player has gone down and the health bar needs to change to reflect that). A listener generally wants set up in either the Start() function of a class, or in the ObjectNodeReady() function when the script is going to be attached to a mob (such as the MobController3D).

Similar to the getting of properties, the registering of a change handler requires either the ObjectNode or AtavismNode and is done in the following format:

ClientAPI.GetPlayerObject().RegisterPropertyChangeHandler(“health”, HealthHandler);

The first parameter is the property to listen for, and the second is the name of the function to run when the stat has changed. The function must match this setup:

public void FunctionName(object sender, PropertyChangeEventArgs args) {
  // Do whatever you want in here
}

 

For the health example for above the HealthHandler function looks like:

public void HealthHandler(object sender, PropertyChangeEventArgs args) {
    health = (int)ClientAPI.GetPlayerObject().GetProperty(“health”);
}

All these few lines of code do (combined with the RegisterPropertyChangeHandler above) is listen for when the health property changes, then set the local health (for the health bar) to whatever the value is the player has now.

 

Title Property Tutorial

Ok so we have now covered how to set a property and get a property, it's now time to try put in a new example in full: a Title property that is displayed before a player’s name (such as a Mr, Mrs, Dr, Warlord, Grand Marshall).

Note: this tutorial is designed for the basic demo project. If you are using UMA or NGUI with your project you may need to edit some other files instead.

Step 1) Editing the Character Creation Code to add the property

Open up the LoginUI.cs file and near the top just under:

List<CharacterEntry> characterEntries;

add a new list for the potential Titles and a string for the chosen title:

public List<string> titles;
string chosenTitle = “”;

 We will then add some code in DrawCharacterCreateUI () to draw buttons for each title option. I have put this just before line 239 - GUILayout.Label("Name:");

GUILayout.Label("Chosen Title: " + chosenTitle);
foreach (string title in titles) {
            if (GUILayout.Button(title)) {
                        chosenTitle = title;
            }
}

 And just below: properties.Add("gender", gender); (at line 255) add:

properties.Add("title", chosenTitle);

 

Step 2) Adding a list of titles to your game.

Load up the Login scene and click on the Main Camera object in the scene. You should now see a new Titles property listed in the Login UI component on it. Here you can specify which titles you would like players to choose. I have attached an image showing how it should look (along with my selection of titles).

b2ap3_thumbnail_TitlesList.PNG

 

Step 3) First Test

With a selection of titles added, you should now play your game and try create a new character. You should see a list of buttons that match your titles and you can click one to set it for your character.

 

Step 4) Altering the display of character names

Now that we can give our characters a title property it's time to get that property in game. For this tutorial I'm going to modify the MobController3D.cs file which draws the names above the heads of characters/mobs.

Open up the MobController3D.cs file and add the following line somewhere in the UI Fields region (lines 111-119 - #region UI Fields):

string title = "";

This is to store the value of the title. Next we will update the OnGUI() function to display the title before the name. Look for these lines:

if (!isPlayer)
            GUI.Label (rect, gameObject.name);

 And modify the second line so it says:

GUI.Label (rect, title + " " + gameObject.name);

You may want to comment out the first line so you can see the title above your character as it will make testing much easier.

Note: Commenting is done by adding // before the line of code.

I also found out that the line up about 5 lines above that says:

Vector2 size = GUI.skin.GetStyle (styleName).CalcSize (new GUIContent (gameObject.name));

needs to be changed to:

Vector2 size = GUI.skin.GetStyle (styleName).CalcSize (new GUIContent (title + " " + gameObject.name));

otherwise it doesn't have enough space to draw the title and name.

 

Step 5) Creating the Property Change Handler

The last step before final testing is to add a property change handler for the title property.

I created a new function called HandleTitle which looks like:

public void HandleTitle (object sender, PropertyChangeEventArgs args)
{
           title = (string)Client.Instance.WorldManager.GetObjectNode(oid).GetProperty("title");
}

 

It can go anywhere in the file, I added it after HandleCombatState().

The final line of code is to set up the registration of the property change handler. Find your way to the ObjectNodeReady() function and just after the line:

GetComponent<AtavismNode>().RegisterObjectPropertyChangeHandler("combatstate", HandleCombatState);

add:

GetComponent<AtavismNode>().RegisterObjectPropertyChangeHandler("title", HandleTitle);

 

Note: the line before may look slightly different, it is changing in update 2.2.

 

Step 6) Final Test

Finally, log in with your new character that has a title and see what their name looks like! Here is how mine turned out:

 b2ap3_thumbnail_WarlordSoomy.PNG

 

Extension activity:

Try get the Title to show up with the player name in the Player Portrait by editing the PlayerPortrait.cs.

 

Hits: 3071
0
Creating and Accessing Properties Part I

Every player character and mob in Atavism uses properties to keep track of appearance, combat and other game progression information. Properties are generally given to the player/mob on creation and accessed and updated as events happen in the game.

Properties can only be created and updated by the server (to prevent synchronisation issues and cheating), and are sent down to the client as the player comes within range of another player or mob.  The client (Unity) can listen for property changes and/or grab a property value from a player/mob and use it to display information in various ways (such as numbers/text in the user interface or the visual appearance of the player).

In Part I of this two part blog how to create properties for your players and mobs is explained below. Part II next week will cover how to access that data in Unity and set up listeners. Part II will also be accompanied by a tutorial to add a Title property to your characters which will be displayed beside their name.

 

Creating Properties for Players

Player properties can be added in different ways depending on the property type. Stat properties for combat (such as health, strength etc.) are added using the Stat plugin in the Atavism Editor (see more here: <insert page>). Other properties, such as appearance or general game progression properties, can be added either in the Character Creation scripts in Unity, or in the Character Template in the AGIS code on the server.

Adding Properties in Unity

Adding properties to the character creation in Unity is done by adding in a new entry to the properties map that is sent to the NetworkHelper.CreateCharacter() function. In the standard Atavism setup this is located in the LoginUI.cs file, in the DrawCharacterCreateUI() function, and in the UMA setup it is in the CharacterSelectionCreation.cs file, in the CreateCharacter() function.

Any new properties added in to via the Unity method need to have “custom:” at the start so the server knows not to confuse it with the standard properties. For example, an age property to be given to player characters upon creation:

properties.Add ("custom:age", 27);

Note: An example of a few properties are provided in the LoginUI file, commented out among the rest of the property setting code in the character creation.

Adding Properties in AGIS

Adding properties in the AGIS code is done by modifying the CharacterTemplate.java file found in the objects package. New properties need to be added to the template for a character which is setup in the createCharacter() function. Adding the properties in the AGIS code comes with the added complexity of deciding which Namespace the property should be added to (Namespaces relate to different areas of the server such as combat, inventory, world). Properties relating to combat should be added to the CombatClient.NAMESPACE, inventory related ones to InventoryClient.NAMESPACE, and most others to the WorldManagerClient.NAMESPACE. Other Namespaces exist, but I won’t go into detail here about what it all means as it is another topic in itself.

Note: All custom properties from Unity are added to the WorldManagerClient.NAMESPACE.

As an example, if I wanted to add the age property directly on the server rather than through Unity, I could add:

player.put(WorldManagerClient.NAMESPACE, "age", 27);

 

Creating Properties for Mobs

New Properties for mobs can only be done in the AGIS code, by editing the loadMobTemplates() function in the MobDatabase.java file located in the database package. Mobs use the same template system as the CharacterTemplate setup listed above. For example, mobs could be given an age property as well by adding:

tmpl.put(WorldManagerClient.NAMESPACE, "age ", 27);

to the loadMobTemplates function.

 

Final Notes

It is important to note that any new properties will only exist for newly created characters. You can always wipe all existing characters in your game by re-sourcing the install.sql file if needed.

All properties of your character, or of the player/mob you have targeted can be viewed by typing /props into the chat box when in game. It is a good idea to try this after creating a new property to make sure it is coming up as expected.

 

 

 

 

 

Tagged in: atavism MMO properties
Hits: 3549
0

Posted by on in Uncategorized
Vitality Stats

For all those who have wanted hunger, warmth and other survival stats in their games, Atavism now provides a new type of stat known as Vitality Stats. These stats allow a change in the value over time (known as a shift) with actions that can be set upon reaching the minimum or maximum value (such as the player/mob dying).

For example, a hunger stat can be set with a max of 100, and a min of 0. The stat can be set to increase by 2 every 6 seconds, with death occurring when hunger reaches 100. If the player doesn’t eat some food (or have some effect applied) that decreases their hunger, they will die in 300 seconds (5 minutes).

There are 3 steps in setting up a Vitality stat: Creating the max stat, creating the vitality stat, and setting the stat on the character template.

Creating the Max Stat

A max-stat needs to be set up to control the maximum value of the vitality stat. Open the Stat plugin in the Atavism Editor and create a new stat with type Base Stat. I generally put the word “max” in the max-stat name to help identify it. Leave Stat Function as none and ignore the Mob Values.

Example max stat:

b2ap3_thumbnail_Blog6-MaxStat.png

Creating the Vitality Stat

The vitality stat setup involves setting the shift data (how much the stat changes by itself over time), the requirements for the shift to occur, and what happens when the min/max values are reached.

To create a vitality stat, open the stat plugin in the Atavism Editor and set its type to Vitality Stat. Set the minimum value you want (generally 0) and set the Max Stat to the stat created in the step above. If the stat should only effect players then tick the Player Only check box (most Vitality stats will be player only, otherwise you will have random mobs and NPC's dying). Set the Shift value to how much the stat will change each update, and if the stat can be reversed (such as breath going back up when you are out of water) then set the Reverse Value. Now set the Shift Interval to how often (in seconds) you want the stat to update.

Note: Reverse mode is not functional yet and will be included in the next update.

Set the On Min Hit and/or On Max Hit to what should happen when the stat reaches either its minimum or maximum. By default the only option at the moment is death. The system is designed for more options to be added in the future.

The last part for the Vitality Stat setup is the requirements. Requirements can be set so stats only update when certain states are true for the player, such as the player being alive, or not in combat. The current version provides only these two options with support for new requirements to be added in. If the stat update is to run all the time, add no requirements. Click Save Data and the only task left is setting up the stat for your character templates.

Example vitality stat:

b2ap3_thumbnail_Blog6-VitalityStat.png

Explanation: The hunger stat goes up by 2 every 10 seconds and when it reaches the max value (which is 100) they will die.

 

Setting the Stat on the Character Template

The stat now needs to be set on each character template that has been created in the Player Character Setup plugin.

Open the Player Character Setup Plugin and for each template scroll down to the new stats and set their values. Be careful when setting the base value for the vitality stat on the character as it can result in instant death (and character creation issues) if it triggers the onMin or onMax events (for example, if the onMax action is death and the starting value for the vitality stat is equal to the max value).

Example stat values on my character template:

b2ap3_thumbnail_Blog6-CharacterStats.png

 

Other ideas

From here you may want to offer ways for players to prevent their death from a vitality stat such as adding items that can be consumed that decrease the stat, or giving them abilities they can activate. These ideas can be achieved using Stat Effects that modify the value of the vitality stat.

As Atavism development continues the plan is to add many new states and onMin/onMax actions to provide better gameplay. One example is warmth that can be increased while near certain objects (fires) and decreases when outside and based on the weather. Any adventurous programmers should be able to achieve results like this already using the base that has been programmed in.

Hits: 2296
0

Posted by on in Uncategorized
Working with movement speed

To Setting and managing the movement speed of players and mobs is an important part of game design,and a highly requested feature by developers. As of release 2.1.1 Atavism users can now easily set and work with movement speeds i their games. Working with movement speed is simple in Atavism, base movement speeds can be set for players and mobs through the Atavism Editor tool, and effects can be created to modify speed through abilities and items. These are covered below.

Setting Base Movement Speed

As of the current release (2.1.1) all mobs share the same movement speed, and player characters can ahve thier speed set by character/race template.

To set mob movement speed go into the Stats plugin in the Atavism Editor, click the Edit button and choose the movement_speed stat. If no stat with that name is listed, you can create it and give it the exact name: movement_speed. The Base Value is the speed the mobs will run at. By default a speed of 7 is suggested.

To set player movement speed go into the Player Character Setup plugin and you will find the movement speed stat listed. As stats are defined for each class/race combination you can have different speeds for different races or classes. Once again, a speed of 7 is the recommended default value. Note that any changes made here will only take effect for new characters, not per-existing ones.

Note: For those interested in Mob Controller development in Unity, the runSpeed variable from the AtavismMobController abstract class is updated from the server and should be used for showing correct movement of players and mobs.

Creating Speed altering effects

We now have the base movement speed for our mobs and players, but what about creating a speed boost or slow effect/ability. To achieve this , Stat Effects are used. To create a speed boost effect go into the Effects plugin and set the Effect Type to Stat. Set Stat 1 to movement speed and give it a value. Make sure the duration is set to greater than 0 or the effect will be removed straight away. In the example below I have created an Effect called Speed Boost which increases the movement speed by 25% and lasts for 10 seconds.

The same idea can be used for Slow Down Effects by using a negative value for the Modification value.

Creating Speed altering Equipment

The other way to alter the speed of a player/mob is to apply a movement speed stat modification to a piece of armor or a weapon. For example, a pair of boots could be given a speed boost of 2 so when equipped the player starts running faster. To achieve this, go into the Items Plugin and select the item you want to add a speed modifier to. At the bottom section, titled Item Effects, click Add Item Effect Type to Stat. Choose the movement speed stat and give it a non-zero value.

As shown, working with movement speed in Atavism is now very easy. To finish up, a handy tip is to make an ability or pair of boots that increases movement speed for any test characters to make traveling around a bit less tedious while testing.

Hits: 2447
0

Posted by on in Uncategorized
Creating a Damage over Time Effect

This week I’m going to explain how to create a Damage over Time effect (DoT) along with setting up the ability, the skill and giving it to players. For any who aren’t familiar with the term, DoTs are used for bleed, poison, burn or curse (or other) style abilities where the target continues to take damage for a period of time.

For this blog I am going to create an ability called Lacerate which causes a DoT called Bleed. The ability will be part of the Knife Style skill. There are 4 parts to cover: Creating the Skill, creating the Effect, creating the Ability and giving the Skill to a player.

Creating the Skill

Open the Skills plugin in the Atavism Online Editor and create a new Skill called Knife Style. Make sure Automatically Learn is checked and hit Save Data. The rest of the settings don't matter for this example.

Creating the Effect

Open the Effects plugin in the Atavism Online editor. I have set the properties as below:

Name: Bleed

Effect Type: Damage (as this effect will be dealing damage).

Damage Effect Type: Physical Dot (Bleed effects generally use physical stats for their damage calculations. By default the physical stats are strength (physical power) and dexterity (physical accuracy)).

Damage Property: health (the target will be losing health from this effect).

Damage Type: I have chosen slash, but it could be any.

Damage amount: 30 (this is the full amount that will be dealt by the DoT before other modifiers).

Damage modifier: 1 (leaving this as default)

Transfer Rate: 0 (I don’t want the caster getting any health from this)

Bonus Damage Effect: None (I’ll cover this at the end of the Blog)

Bonus Damage Amount: 0 (if there is no bonus damage effect, there’s no need to set an amount)

Is Buff: False (buffs are for positive effects, damage effects are negative)

Is Passive: False (this effect is activated by an ability)

Skill Type: Knife Style (the skill I setup in the first step)

Skill Mod: 1 (Add 1 damage for every level the caster has of the Knife Style skill)

Stack Limit: 3 (The caster can stack the ability 3 times on the target allowing it to deal up to 3 times the damage).

Allow Multiple: True (multiple casters can all put this effect on the target at the same time)

Duration: 15 (the effect stays on the target for 15 seconds)

Num Pulses: 5 (the damage from the effect will be applied 5 times)

Effect Particle: None

Tooltip: You are bleeding! You will lose health every few seconds. (if the UI is setup to display effects on the player, this message will show up when they have this effect).

The main settings to look at here are Damage Amount, Duration and Num Pulses. The Damage amount is split up by the number of pulses. In this example the 30 damage is split between 5 pulses resulting in 6 damage per pulse. There are 5 pulses over 15 seconds, so each pulse happens 3 seconds apart, the first one occurring after 3 seconds.

Once the settings are as wanted, hit Save Data. With the effect created, an Ability now needs to be setup to apply the effect.

Creating the Ability

Open the Abilities plugin and set the properties as specified below (anything not mentioned can be left as default):

Name: Lacerate

Ability Type: CombatMeleeAbility

Skill: Knife Style (the Skill made for this example – this skill can be increased by using this ability)

Target Type: Enemy (can only be used on enemy targets)

Cooldown Type: LACERATE (I made a custom cooldown so this ability can only be used every 5 seconds)

Duration: 5

Act Target1: target (we want the effect applied to the target of the ability)

Act Effect1: Bleed (the effect made in the step above)

The Ability now needs to be added to the Knife Style skill. Open the Skills Plugin again and click on the Edit button and choose the Knife Style Skill. Under the Skill Abilities section set Ability 1 to the Lacerate ability created in the step above. Make sure Level is still set to 0 and click Save.

Giving the skill to a Player

Open the Player Character Setup plugin and go into Edit mode. Choose the template you want to edit and head down to Starting Skills. Click the Add Skill button and choose the Knife Style skill. This will give the skill to any new characters made that match the Race/Class combination for this template.

Give the server a restart and everything is ready to go. Make a new character and they will have a new Lacerate ability in their action bar. Now it's just a matter of finding an enemy to attack and trying the ability out on them. You should see them take some damage every few seconds after using the ability.

Images have been added below to show how my Effect and Abilities screens looked when I was finished.

Effect:

Ability:

 

 

Hits: 4407
0

Posted by on in Uncategorized

With the release of v2.1.1 developers will be able to connect their Atavism server account authentication to external systems such as a website or database. This will allow you to manage or control who has access to your game without making changes to the atavism master database. It also means those with a group of followers who have accounts on a website can use their website accounts to log into the game. The only challenge is it requires a bit of setup on the remote system to allow Atavism to get the data it needs.

The atavism server has built in support to send a request to a php page and get a response back to verify an account. The rest of this blog post is going to cover how to set that php page up to talk to your website database and how to get atavism to talk to your php page.

Note: There is also a skeleton file to work with direct remote database connections which will be completed later (but any keen programmers can modify it easily if they have access to the AGIS code – see RemoteDatabaseAccountConnector.java in the util package).

Setting up the PHP Page:

The Atavism server sends two parameters to the php page: 'user' and 'password'. You need to use the POST function to get the properies. i.e:

$user = $_POST["user"];

$password = $_POST["password"];

From here your php page will do whatever it needs to verify the username and password.

It then must echo either a “Success” or a fail message which the Atavism server will pickup. For example, I have a password check that echoes Success when the passwords match, otherwise Fail:

if ($password === $passnya) {

    echo "Success";

} else {

    echo "Fail";

}

That is pretty much all you need to get the php side going. The hard part is creating the logic to verify the account details. To help you setup your php page, an example php script is given on the wiki page: http://atavismonline.com/wiki/doku.php?id=remote_php_connector

 Getting the Atavism server to communicate with your PHP page:

A remote connector can be set in the auth_server.py file in the server files/bin folder. The following 3 lines need to be added or edited (which already exist in the file and just need the # symbol removed):

connector = RemotePhpAccountConnector()

connector.setUrl("http://www.yourdomain.com/verifyAccount.php")

ms.setRemoteConnector(connector)

Replace the url specified with the address of the php file you have uploaded and you are ready to go.

Note: To use other connectors, substitute in the different class name and the set functions.

 We will be adding this to the wiki as well. That's if for this week. Next week's blog won't be quite so technical, so don't worry if this is all a bit confusing.

Hits: 1859
0

Posted by on in Uncategorized
Fixes, UMA, AtVoxel and NGUI

Our main focus for the next few months is the server side pathfinding and player movement handling, but we will be doing small updates every so often to fix those pesky bugs and to fix up some minor features. The past couple weeks I have been spending a bit of time with our testers to get all our additional plugins up-to date with our latest release (2.1) and to fix up a couple things. This means you can look forward to seeing an incremental update of Atavism (version 2.1.1) along with AtVoxel 2.1 and the latest NGUI-Atavism scripts next weekend.

So what fixes or improvements can you expect?

Atavism itself has seen the WorldBuilding UI and client-side scripting split into two files allowing for easier integration with AtVoxel and any other UI customisations that others may wish to use. The player input and mob controller scripts have been modified slightly which have resulted in a Click-to-Move input controller that works properly (allowing Diablo-style control).

On the server side the remote-account connection system has been improved to make it much easier to connect external websites, databases or other systems to Atavism to control user accounts. Next weeks blog will cover this in detail, explaining how you can set up Atavism login to connect to your website. Quests will also get another fix so pre-reqs now work.

The UMA-Atavism package has had 3 fixes added in: pants for Male characters now work, unequipping a belt now removes the model from the character and the alt-tab (or minimise) bug has been fixed so the textures are applied again to all UMA characters when going back into your game. The update is already up and ready for you to grab.

AtVoxel has been upgraded to work with the new Claim/World Building system in Atavism and as a result now has a proper UI which can be used without any customisation. This means AtVoxel can now be adeed to your project and used right away rather than having to make other changes (or deal with ugly debug UI).

Finally, the NGUI package is being updated to contain scripts for all the new features added in 2.1 (such as Merchants). One of our key testers has been working to create a demo scene/project which will be released a little later to help users get NGUI working with Atavism.

It's looking to be a good weekend of releases next week with something for everyone. Keep an eye on the forums for the announcement of the releases.

Tagged in: Tech Blog 2
Hits: 2750

Intel

Unity

S5 Box

Sign On