Skip to content
On this page

v5.0.0 Changes

Written on March 27, 2023

I think it's time to start explaining all of the changes that have happened in V5, and how those changes effect Athena. There is a lot to cover and I actuall may even miss a few changes because there are just that many changes.

I will be going through the CHANGELOG.md file and trying to explain each section and what the reason was behind it.

The first commit for Version 5 was on December 12, 2022, this entire change took almost 3 months to complete.

Breaking Changes

Keep Reading

At first this is going to look like the framework is going backwards, but these major breaking changes tell a larger story.

  • Removed Inventory
  • Removed Equipment
  • Removed Toolbar
  • Removed Storage System
  • Removed Vehicle Keys
  • Removed Holograms
  • Removed Camera Target
  • Removed Item Interfaces

All V4 plugins are not working in V5.

They will likely not be updated, as I have no interest in maintaining 30 plugins anymore. I will focus solely on the framework.

API Imports Changed

This effects all plugins, and all code.

import * as Athena from '@AthenaServer/api';
import * as AthenaClient from '@AthenaClient/api';

Production Upgrade Pathway

WARNING

This only applies to you if you want to maintain player data

If you are not in production I highly recommend just wiping the database and going for the full upgrade to V5.

However, if you are in production and still want to find an upgrade pathway... it will be difficult but doable.

  1. Create a list of all player owned vehicles. Store it somewhere.

    • Create a script that reads the list.

    • Use the Athena.vehicle.add pathway to re-create vehicles.

  2. Create a basic list of the items that were stored in each players inventory. You want dbName and quantity.

    • Wipe the items collection

    • Wipe the inventory, equipment, and toolbar of all players.

    • Convert all items to BaseItems in the Athena.systems.inventory.factory functions.

    • Turn off weight checks in Athena.systems.inventory.config

    • Use the Athena.player.inventory.add function to add by dbName, and quantity.

  3. Storages

    • Anything that has a storage should be given to the original owner. Create a list of who owns what, and add it to the user.

    • Wipe the entire storages collection.

  4. permissionLevel

    • Permission Level is no longer a thing. We now use an array of permissions which contains a list of string values.

    • The two permissions that come with Athena are admin and moderator. Almost everything requires admin rights by default.

  5. Ares Service

    • The original Ares service is dead. The Discord plugin was updated to already use the new system.

Interactions

All interactions now use SHIFT + E by default.

This is to prevent collisions with default in-game controls.

Default Systems

Default Systems are a new section of the systems folder under src/core/systems.

Inside you will find a few general systems that can easily be disabled by following this API Pathway: Athena.systems.defaults.X.

You should disable these default systems by creating your own plugin, and invoking the disable function.

Here are a few default systems that come with Athena now.

  • ammo

    • An item called 'ammo-box' is added.
    • The ammo box can be used on a weapon to add ammo.
    • Weapons track some ammo; albeit not a complete system yet.
    • Can be disabled
  • clothingCrafting

    • Take two clothing items and combine them.
    • Then take the single clothing item and combine it with more items.
    • The items that are combined are essentially 'sewn' together.
    • Can be disabled
  • death

    • A very simple death system.
    • It just respawns a player after 5 seconds.
    • Can be disabled
  • displayId

    • Shows your ID in the top-right of the screen
    • Can be disabled
  • hospitalBlips

    • Adds all hopsital locations to the map
    • Can be disabled
  • inventorySync

    • Whenever inventory or equipment is updated, it synchronizes it to the client.
    • Can be disabled
  • time

    • Time progresses based on server time.
    • Whatever time it is where the server is located is what time it is in-game.
    • Can be disabled
  • toolbar

    • Handles invoking item functionality when press 1-4
    • Can be disabled
  • vehiclesDespawnOnDestroy

    • When a vehicle is destroyed, it is removed from the world after 60s
    • Can be disabled
  • vehiclesDespawnOnLeave

    • When a character leaves the server, so does all their vehicles.
    • Can be disabled
  • vehiclesSpawnOnJoin

    • When a character joins the server, so does all their vehicles.
    • Can be disabled
  • weaponItems

    • All weapons have a name and item created to represent them.
    • They can be spawned through the add item functionality.
    • These items are automatically added to the database.
    • Can be disabled
  • weather

    • Weather rotates throug a specific weather pattern for the whole map.
    • The weather pattern can be changed through a function.
    • Can be disabled

Inventory Rewrite

Why?

The old inventory was one of the more legacy things that existed in Athena. It had been around forever, and it was impossible to change without changing the core functionality. Explaining how it all worked was a mystery in itself.

How?

The new inventory system has two levels of API. One is the newbie programmer API which is very easy to use, it's meant for adding / removing items and maybe sometimes checking if the user has an item.

Key Notes

  • Athena.player.inventory functions all save automatically.
  • Items should not be modified directly.
  • New lower level inventory functions are input and output based. Meaning if you feed it an array, you will get an array back. Nothing is changed for a player until it is set through the Athena.document.character API.
  • Always do your inventory updates all at once, never delay inventory changes.

Player API Examples

ts
const didAdd = await Athena.player.inventory.add(somePlayer, { dbName: 'burger', quantity: 1, data: {} });

const didSubtract = await Athena.player.inventory.sub(somePlayer, { dbName: 'burger', quantity: 1 });

const didRemove = await Athena.player.inventory.remove(somePlayer, someSlot);


const itemClone = await Athena.player.inventory.getAt(somePlayer, someSlot);

const hasEnough = Athena.player.inventory.has(somePlayer, 'burger', 5);

Item Differences

StoredItem vs BaseItem vs Item

  • BaseItem

    • A single instance of general item information.
    • Usually contains generic information to establish what the item does.
    • This can include item effects.
    • The behavior of the item can be generated here as well.
  • StoredItem

    • The smallest version of an inventory item.
    • Often stored in the player document, or other storage interfaces.
    • This is the type you will come across frequently.
    • Can contain unique data specific to that item instance only.
  • Item

    • Distributed to the client at runtime with all item information when they open their inventory.
    • You will almost never create this one.
    • This is a combination of both BaseItem and StoredItem
    • The 'data' from the BaseItem is assigned to the StoredItem

tldr - Base Item is the factory template. Stored item is the minted item.

You can also use custom data on all of these interfaces

ts
const item = StoredItemEx<{ valueInData: string }> = {
  ...
  data: {
    valueInData: 'hi!'
  }
}

const item = BaseItemEx<{ valueInData: string }> = {
  ...
  data: {
    valueInData: 'hi!'
  }
}

State Rewrite

Why?

If you used Athena.systems.state before it was the way to update player data. It was clunky and sometimes a really dumb solution to a harder problem I was dealing with which is Prototyping.

You can read more about the why in this other blog post.

How?

The important thing about this API replacement is that it can now be found under Athena.document.character and it is named in this way because we are modifying MongoDB documents that belong to a specific character, vehicle, or account.

WARNING

If you modify the data from Athena.document.x.get it will not be synchronized. It will not update. You MUST use the set or setBulk functionality to push the update to the player.

Key Notes

  • Player Joins
  • They Authenticate
  • They are assigned an Account, and the Account Data is cached in memory for this session.
  • They select a Character
  • The are assigned a Character, and the Character Data is cached in memory for this session.
  • They vehicles are created
  • The vehicles are assigned an OwnedVehicle document, and the Vehicle Data is cached in memory.

All of this data is now easily accessible, and we use a write cache first, and output database changes after method.

This means that when we update character, vehicle, or account data it is pushed to the in-memory cache, and the output to the Database as soon as possible. This keeps everything fluid while the rest of the server moves along.

Examples

ts
await Athena.document.character.set(somePlayer, 'cash', 25);
await Athena.document.character.setBulk(somePlayer, { cash: 25, bank: 100 });

// Custom Interface Support
interface CharacterExtension {
    newValue: string
}

let data = Athena.document.character.get<CharacterExtension>(somePlayer);

if (!data.newValue) {
    await Athena.document.character.set<CharacterExtension>(somePlayer, 'newValue', 25);
    data = Athena.document.character.get<CharacterExtension>(somePlayer);
}

Attachables Update

Attachables use the new alt.Object API which fixed some issues with removing the objects.

Object Controller Update

The Object API was rewritten to use the new alt.Object API which fixed issues with removing objects.

Also performance should be much better.

Currency

Currencies now support custom types, so you can create a new currency automatically by using the given functionality.

ts
Athena.player.currency.add<'bitcoin' | 'ethereum'>(somePlayer, 'ethereum', 5)

Chat / Messenger System

Chat was replaced with a new messaging system.

The messaging system allows you to easily intercept all messages from a player when they are chatting.

The original chat input was replaced with RMLUI which makes chat input very fast.

All of this is done through the core-chat plugin.

If your language is more complex (I have no idea how to word this, Chinese, Japenese, etc.) then the input though RMLUI may not support your typing, consider replacing the RMLUI chat input with a CEF based one to fix the input.

It still supports these other languages, but you'll have to write your own chat input. The rest can be recycled though.

Here's an example on server-side on how to re-route a message from a player.

ts
import * as alt from 'alt-server';
import * as Athena from '@AthenaServer/api';

function handleMessage(player: alt.Player, msg: string) {
    const data = Athena.document.character.get(player);
    if (typeof data === 'undefined') {
        return;
    }

    const closestPlayers = Athena.getters.players.inRange(player.pos, CHAT_CONFIG.settings.range);
    Athena.systems.messenger.messaging.sendToPlayers(closestPlayers, `${data.name}: ${msg}`);
}

export function init() {
    Athena.systems.messenger.messaging.addCallback(handleMessage);
}

Here's an example on client-side on how to send a message or command.

ts
import * as AthenaClient from '@AthenaClient/api';

// Goes up to the server as if the client were the one to type it.
AthenaClient.systems.messenger.send('Hello World!');

Permission System

Permission Level is no longer a thing. We now use an array of permissions which contains a list of string values.

The two permissions that come with Athena are admin and moderator. Almost everything requires admin rights by default.

Permissions can be validated with a few different functions.

ts
Athena.systems.permission.has<'custom-perm'>('character', somePlayer, 'custom-perm');
Athena.systems.permission.hasOne<'custom-perm1' | 'custom-perm2'>('account', somePlayer, ['admin', 'custom-perm1']);
Athena.systems.permission.hasAll('character', somePlayer, ['admin', 'moderator']);

Permissions can be added / removed easily as well.

ts
type CustomPerms = 'perm1' | 'perm2' | 'perm3'

await Athena.systems.permission.add('character', somePlayer, 'admin')
await Athena.systems.permission.add<CustomPerms>('character', somePlayer, 'perm1');
await Athena.systems.permission.remove<CustomPerms>('character', somePlayer, 'perm2');

Athena.get

I had to replace this with getters because of TypeScript limitations.

Anyway, you can find all the relevant APIs for getting various player info, ids, etc. under this pathway.

Vue Dev Menu

When you open http://localhost:3000 in the browser while using dev mode you had to constantly close the panel to browse pages.

I've changed the dev menu to allow you to hide the panel from showing, or simply Hide on Refresh which lets you focus on what you are working on.

Additional instructions are there on how to bring the panel back before hiding it.

Inventory

The inventory UI was moved out of the core system.

It now exists as its own plugin which you can make a copy of, and make all of your appearance changes.

The thing is a monster, and it was really difficult to move it over to a plugin.

That being said, it's much more robust and offers tons of new functionality and even a context menu.

Item Factory

When you want to create an item, you create a base item.

Use the upsertAsync function to pass that item to the database so 'copies' of that item can be made when specifying a matching dbName and version to a player to add that item.

When you want to add an item to a player, you use the manager or the Athena.player.inventory API.

Item Manager

The entire item system was reworked to work in a very specific way.

This item manager is considered the advanced portion of inventory management. If you want an easy to use function use Athena.player.inventory.x or Athena.player.toolbar.x.

Fundamentals

  • The item manager saves nothing.
  • The item manager does not auto-synchronize anything.
  • The item manager does update data automatically for a player.
  • Almost everything can return undefined that means that the data could not be set, or modified. When the data is returned correctly you get the modified data.

You still need to set that data through Athena.document.x.set or Athena.document.x.setBulk.

Here's an example of actually adding an item to a user through the advanced API that is this manager.

Code Example
ts
async function add(player: alt.Player, dbName: string, quantity: number): Promise<boolean> {
    const data = document.character.get(player);
    if (typeof data === 'undefined') {
        return false;
    }

    const baseItem = Athena.systems.inventory.factory.getBaseItem(dbName);
    if (typeof baseItem === 'undefined') {
        return false;
    }

    if (typeof data.inventory === 'undefined') {
        data.inventory = [];
    }

    const newInventoryData = Athena.systems.inventory.manager.add({ dbName, quantity, data: {} }, data.inventory, 'inventory');
    if (typeof newInventoryData === 'undefined') {
        return false;
    }

    if (Athena.systems.inventory.weight.isWeightExceeded([newInventoryData, data.toolbar])) {
        return false;
    }

    await document.character.set(player, 'inventory', newInventoryData);
    return true;
}


// This needs to be wrapped in an async function
const didAdd = await add(somePlayer, 'burger', 5);

Item Effects

Item effects are now handled a bit differently.

Items are not automatically removed when an effect is invoked.

Instead it's up to you to decide what to do with an item after it is used.

Code Example
ts
Athena.systems.inventory.effects.add(
    'edible',
    async (player: alt.Player, slot: number, type: 'inventory' | 'toolbar') => {
        const propertyName = String(type);
        const data = Athena.document.character.get(player);
        if (typeof data === 'undefined' || typeof data[propertyName] === 'undefined') {
            return;
        }

        // This is an item reference; do not modify it directly.
        const item = Athena.systems.inventory.slot.getAt<{ health: number }>(slot, data[propertyName]);
        if (typeof item === 'undefined') {
            return;
        }

        const index = data[propertyName].findIndex((x) => x.slot === slot);
        if (index <= -1) {
            // Item was not found with matching slot
            return;
        }

        // Instead you can directly apply data changes...
        Athena.systems.inventory.manager.setData<{ health: number }>(item, { health: item.data.health + 5 });

        const didRemove = await Athena.player.inventory.sub(player, { dbName: item.dbName, quantity: 1 });
        if (!didRemove) {
            Athena.player.emit.notification(player, `Could not eat ${item.dbName}`);
            return;
        }

        Athena.player.safe.addHealth(player, item.data.health);
        Athena.player.emit.notification(player, `You ate 1 ${item.dbName}`);
    },
);

Item Crafting

Item crafting is something new but it allows you to simply combine two items by left-clicking one item in the inventory, and trying to combine it with the other.

If a recipe exists, it will combine it.

Adding new recipes is even easier.

ts
Athena.systems.inventory.crafting.addRecipe({
  combo: ['burger', 'tomato'],
  quantities: [1, 1],
  uid: 'burger-with-tomato',
  result: { dbName: 'burger-with-tomato', quantity: 1 },
});

Item Weapons

Weapons have their given data; but you can also modify a weapon to add weapon component information to it.

It must be stored under the data section of the item though.

ts
const someWeaponInSlot = 5;

Athena.systems.inventory.weapon.addComponent(somePlayer, 'inventory', someWeaponInSlot, 'COMPONENT_AT_PI_FLSH');

Clothing

We used to have an array called equipment but this is completely gone now. Instead you can now equip items directly inside of your inventory.

This means that when you right-click and select use in the context menu clothing is given an equipped status.

This equipped status is also available for other items as well.

By default the order in which your clothing is applied is from top to bottom, meaning that if something is in the very last slot of your inventory it is equipped last.

I've also created various interfaces / functions to help build clothing items quickly.

Here are some of those functions...

ts
Athena.systems.inventory.clothing.outfitFromDlc

// Use this one for clothing systems
// You just apply all the relative values on a player...
// Then you get the constructed StoredItem back.
const storeableItem = Athena.systems.inventory.clothing.outfitFromPlayer

Uniforms

These override clothes. They are applied over clothing.

They function like normal clothing, but are a uniform.

ts
Athena.systems.inventory.clothing.setUniform
Athena.systems.inventory.clothing.clearUniform

Skins

Default Ped Skins, Animals, etc. are available through these APIs now as well.

ts
Athena.systems.inventory.clothing.setSkin
Athena.systems.inventory.clothing.clearSkin

Hotkey Registry

All hotkey systems were removed and moved into a single standard hotkey registration systep. This hotkey registration allows for rebinding hotkeys, as long as you register it through this system.

There is a ton of functionality built into this hotkey system now.

  • Do something while pressed
  • Do something on press down
  • Do something on press up
  • Bypass Menu Restrictions
  • Disable One
  • Enable One
  • Spam Prevention
  • Delay Key Down Function (Hold for X ms)
  • Allow for specific page only

Here's a simple hotkey example for client-side.

ts
const THE_LETTER_C = 67;

AthenaClient.systems.hotkeys.add({
    key: THE_LETTER_C,
    description: 'Do Something',
    identifier: 'my-unique-key-identifier',
    keyDown: () => {
      console.log('Did it!')
    },
    keyUp: () => {
      console.log('Did it!')
    },
    whilePressed: ()  => {
      console.log('This is going to log A LOT')
    },
    modifier: 'shift'
});

Admin Commands

Added a lot of new commands, but these are the admin ones.

account or character is the type you are adding a permission to.

/addperm [account or character] [ingame-id] [permission] - Add permission to an account

/removeperm [account or character] [ingame-id] [permission] - Remove permission from an account

/getperms [account or character] [ingame-id] - Returns the current list of permissions for given type

Player API Changes

Athena.player.x got a lot of changes in general. Lots of new pathways and such but here are a few that are worth mentioning.

Athena.player.appearance.setHair
Athena.player.appearance.setFacialHair
Athena.player.appearance.setEyebrows
Athena.player.appearance.setEyeColor
Athena.player.appearance.setModel

Notification System

Much like the messenger system, you can intercept the notifications on client-side and write overrides for it. This means you can write your own notification system instead of using the default GTA:V one.

Is that everything?

I do not know, but the CHANGELOG tells a larger story of this update.

There are tons of new functions, and useful things that were added to this changelog but still plenty missing from this post. This really just highlights some more significant changes to the Framework.

https://github.com/Stuyk/altv-athena/blob/alpha/5.0.0/CHANGELOG.md

Created by Stuyk | Est. 2020