This is a documentation for Board Game Arena: play board games online !

BGA Studio Migration Guide: Difference between revisions

From Board Game Arena
Jump to navigation Jump to search
(initial commit)
 
 
(16 intermediate revisions by one other user not shown)
Line 1: Line 1:
under construction
This page is only for people who started long time ago and now need to re-write older projects into more modern versions.
This page is only for people who started long time ago and now need to re-write older projects into more modern versions.
Also if you trying to fix older game you may have to look here.
Also if you trying to fix older game you may have to look here.


==Overview==
See announcement here https://studio.boardgamearena.com/forum/viewtopic.php?f=12&t=45248
See announcement here https://studio.boardgamearena.com/forum/viewtopic.php?f=12&t=45248


📌 This symbol: direct information about migration
== Structural changes==


'''''gameoptions.inc.php''''' => gameoptions.json, gamepreferences.json


Previously, options and preferences were specified in a single gameoptions.inc.php file.


📌 This symbol: information about migration, if you want to migrate an old game to the most recent ways
Now options and preferences are 2 json files, follow Migration steps on this page  https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Migration


== Structural changes ==
See [[#User preferences]] and [[#Game options]] for API changes.


''gameoptions.inc.php'' => gameoptions.json, gamepreferences.json
When building the game with this file you will see deprecation warning: The file gameoptions.inc.php is deprecated. click "Reload game options configuration" to generate the JSON content you can then put on a gameoptions.json and gamepreferences.json file. Then you can safely delete the gameoptions.inc.php file.


Previously, options and preferences were specified in a single gameoptions.inc.php file.
'''''<gamename>.game.php''''' => modules/php/Game.php
Now options and preferences are 2 json files, follow Migration steps on this page  https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Migration
 
Move and refactor, see section [[BGA Studio Migration Guide#Namespaced game class|Namespaced game class]]
 
'''<gamename>.action.php => remove'''
 
See section [[BGA Studio Migration Guide#Autowire game actions|Autowire game actions]]
 
'''''<gamename>.view.php, <gamename>_<gamename>.tpl''''' => remove
 
See section [[BGA Studio Migration Guide#Removal of view and template|Removal of view and template]]
 
'''gameinfos.inc.php'''
 
File still there. Deprecated keys '''designer''', '''artist''', '''year''', '''presentation''', '''tags''', '''complexity''', '''strategy''', '''luck''', '''diplomacy''', '''is_beta''' are no longer in use. Please remove these keys and use the Game Metadata Manager instead.
 
'''''material.inc.php''''' => optional
 
See section [[#Material]]


''<gamename>.game.php'' => modules/php/Game.php
'''''states.inc.php''''' => modules/php/States


''<gamename>.view.php, <gamename>_<gamename>.tpl'' => /dev/null
See section [[#States]]


''material.inc.php'' => optional
'''stats.inc.php''' => stats.json


''states.inc.php'' => modules/php/States
Deprecation warning: The file stats.inc.php is deprecated. click "Reload statistics configuration" to generate the JSON content you can then put on a stats.json file. Then you can safely delete the stats.inc.php file.


== PHP migration ==
'''<gamename>.js'''


Oct 2025: The migration was made from PHP7.4 to PHP8.4 new syntax and functions.
File still there but massive API changes, see bottom sections
Things to watch: ...


== User preferences ==
==IDE Support==
A new _ide_helper.php file is now provided in every project dir, allowing IDE to provide syntax error highlighting for the framework functions. This file is regularly updated to match the latest framework updates.


Access to user preferences and listener: https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#User_preferences
Same with bga-framework.d.ts for those using TypeScript.


📌 If you had a custom function called setupPreferences() reading the <select> values, you can now use onGameUserPreferenceChanged instead.
📌 Sync the files from the FTP dir to your local copy to benefit from it. Most of the IDE like Visual Studio Code should handle _ide_helper.php if you already followed https://en.doc.boardgamearena.com/Setting_up_BGA_Development_environment_using_VSCode


If you had a copy of the user preferences on a DB table, it's not needed anymore.
==Game configuration ==


== Game options ==
===User preferences===


New function to access the table options without needing the old global way: $this->tableOptions->get(int $optionId): int


https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Game_Options
Access to user preferences and listener: https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#User_preferences


📌 It was before done with either $this->getGameStateValue or $this->gamestate->table_globals
📌  
*If you had a custom function called <code>setupPreferences()</code> reading the <select> values, you can now use <code>onGameUserPreferenceChanged</code> instead.
*If you had a copy of the user preferences on a DB table, it's not needed anymore. Remove all support of writing to this table. Replace access to this table with
        $pref = $this->userPreferences->get($playerId, $prefCode) ?? $defaultValue;
*If you used $this->player_preferences - replace the use with use of proper API


This new object can also return the Real-time/Turn-based information: https://en.doc.boardgamearena.com/Main_ ... exion_time
====Instant cssPref on user preferences====
A reload is not needed anymore to apply cssPref on a user preference change.


Legacy
📌 Remove forceReload: true if it was only set to update the cssPref. The player will appreciate to not reload the whole page!


New object to access the legacy functions, removing the need to manually decode the JSON result when getting the values.
===Game options===


https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Legacy_games_API
New functions to access the table options (game options) without hassle


📌 Use $this->legacy->actionname instead of $this->actionnameLegacy and remove JSON decoding on getters
https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Game_Options


Globals of any type
📌
*Remove declaration of game options  from "<code>initGameStateLabels</code>"
* Instead of using <code>$this->getGameStateValue</code> or <code>$this->gamestate->table_globals</code> use
$this->tableOptions->get(int $optionId)


New functions to handle any type variables instead of numerical values only
This new object can also return the Real-time/Turn-based setting: https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Reflexion_time


https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Use_globals
==Server parts (php, sql, etc)==


Simplify front->back calls


Introduce bgaPerformAction to replace ajaxcall and checkAction combination, with a simpler syntax:


https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Actions
===PHP migration===


📌 Replace combination of checkAction/ajaxcall by bgaPerformAction. Beware of the options (3rd param) if it was an ajaxcall without checkAction.
Oct 2025: The migration was made from PHP7.4 to PHP8.4 new syntax and functions.


Autowire game actions
New projects are generated using the strict mode


Simplify the action calls by removing the use of the action.php file
📌


https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Actions_%28autowired%29
*Replace all <code>self::</code> to <code>$this-></code>  - The new project template has been updated to remove this bad practice (that may be unsupported in a future PHP version)


📌 Autowired actions needs to start with "act", so it's risky to change them (if you change all actions names in the states.php, game, action and JS file, Real-time players will call the old name until they refresh. So, it needs to be done in two steps with duplicates on back side, or to be deployed when there is no Realt-time table running.
*Add <code>declare(strict_types=1);</code> to all .php files and fix compiler warnings (if you use IDE it will detect it before upload).


When migration is done, the action.php file can be deleted.
===Namespaced game class===
Game class from '''''<gamename>.game.php''''' are now namespaced (and moved to modules/php/Game.php) and can autoload other classes of the same namespace


Namespaced game class
[[Main game logic: Game.php#Creating other classes]]


Game classes are now namespaced (and moved to modules/php/Game.php) and can autoload other classes of the same namespace
📌 The class file should be moved to modules/php/Game.php and adopted


https://en.doc.boardgamearena.com/Main_ ... er_classes
(In examples below YourGameName is NOT verbatim its your game name)


📌 The class file should be moved to modules/php/Game.php and start with this adapted part:
* Move YourGameName.game.php to modules/php (create this dir if does not exists)
Code: Select all
* Rename to Game.php
* Find the place below the copyright and add


namespace Bga\Games\YourGameName;
      declare(strict_types=1);
      namespace Bga\Games\YourGameName;


class Game extends \Bga\GameFramework\Table
* Remove
All references to non-namespaced classes in this file should be defined on top of the file with "use", for example "use \BgaUserException;" as it is this non-namespaced exception is used in the zombieTurn function.
  require_once APP_GAMEMODULE_PATH . "module/table/table.game.php";


All includes with relative path will need to be updated too
* Find you class declaration change YouGameName to Game (verbatim) and change extends


IDE Helper & bga-framework.d.ts
  class Game extends \Bga\GameFramework\Table


A new _ide_helper.php file is now provided in every project dir, allowing IDE to provide syntax error highlighting for the framework functions. This file is regularly updated to match the latest framework updates.
* All references to non-namespaced classes in this file should be defined on top of the file with "use", for example "use \BgaUserException;" as it is this non-namespaced exception is used in the zombieTurn function.


Same with bga-framework.d.ts for those using TypeScript.
* All includes with relative path will need to be updated too.


📌 Sync the files from the FTP dir to your local copy to benefit from it. Most of the IDE like Visual Studio Code should handle _ide_helper.php if you already followed https://en.doc.boardgamearena.com/Setting_up_BGA_Development_environment_using_VSCode
* The material.inc.php to have be moved and included directly (see below)


Strict mode set in new project template
Multiple functions of "Table" base class are now deprecated, see how to migrate in corresponding section


New projects are generated using the strict mode activated (for typings). The examples in the doc have been updated to handle old framework function returning bad typings, for example (int) $this->getActivePlayerId();
* notifyAllPlayers
*notifyPlayer
* mysql_fetch_assoc
** Deprecation warning:  mysql_fetch_assoc function detected. It is deprecated, and may be removed someday. Please replace it by standard framework DB functions!
*Table (class access without namespace)
*isMutiactiveState (misspelled version)
*...


📌 Make sure the typings are correct on the Game.php file, a global check of the game is recommended
===Material===
Material file '''material.inc.php''' is now optional. You can define all your material directly in php class. If you still like to keep it, and using namespaced Game.php you have to move it to subfolder and include directly [[Game material description: material.inc.php#Move it to modules/php]]


📌 A global replace should work on the Game.php files
=== Autowire game actions===
Simplify the action calls by removing  '''<gamename>.action.php'''  file


Access template elements
https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Actions_%28autowired%29


New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()
📌 Autowired actions needs to start with "act", so it's risky to change them (if you change all actions names in the states.php, game, action and JS file, Real-time players will call the old name until they refresh. So, it needs to be done in two steps with duplicates on back side, or to be deployed when there is no Realt-time table running.


https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_stuff_to_player%27s_panel
When migration is done, the action.php file can be deleted.


📌 Code like dojo.place(html, player_board_${player.id}); would be replaced by this.getGameAreaElement().insertAdjacentHTML('beforeend', html);
Deprecation warning: Actions detected on .action.php file. You can now use [[Main game logic: Game.php#Actions (autowired)|Auto-wired actions]] to avoid pass-through functions in .action.php file. If you transform your project to use only auto-wired actions, you can then delete the .action.php file.


Optional files: action/view/template/material
=== Notifications===
Functions notifyAllPlayers and notifyPlayer from main game.php are deprecated


Action/view/template/material files are now optional and are not generated anymore on a new project. The new project templates demonstrate how to work without them.
📌 Replace <code>$this->notifyAllPlayers</code> with <code>$this->notify->all</code>
and Replace <code>$this->notifyPlayer</code> with <code>$this->notify->player</code>


📌 See Autowiring to delete the action file.
====Notification Decorators====
The template should be built on the JS side to remove the view/template files, so it can be complicated for old projects using them intensively. It would look like this:
New notify function that handles decorators, reducing the duplicate code on notification args.
Code: Select all


this.getGameAreaElement().insertAdjacentHTML('beforeend', `
https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Notification_decorators
  <span>${_('My translated text')}</span><div id="player-tables"></div>
`);
Easier notification setup


Notifications can now be automatically scanned and called without needing to register them one by one. They'll handle Promises, so they end synchronously when the Promise resolves.
====Notification args consistency====
Previously, when you sent an arg that was transformed by format_string_recursive or bgaFormatText, the args object was mutated and you got the transformed value in the notif_ handler.


https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Notifications
The solution was to send the values in 2 different names like this:


A wait function has been added to return a Promise when a delay is passed (compatible with fast-replay mode)
[
  'roundNumber' => $roundNumber, // number, to update the round counter
  'round_number' => $roundNumber, // number that will be transformed to string by bgaFormatText, when shown in bold in the logs
]
📌 Do not duplicate the value, as the notif_ handler will now get unmutated args


A new utility function has been added to support Promises for old Dojo animations
===Deprecated getGameName===
The getGameName() function is now useless in the Game PHP file and can be deleted


https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animation_Callbacks
📌 Delete the getGameName function in the Game PHP file.


📌 Dojo.subscribe calls in setupNotifications must be removed if bgaSetupPromiseNotifications is used. Notif_ function should be async and return a Promise, make sure they wait for the expected amount of time if the sync setup was using a numerical duration
Deprecation warning: getGameName function detected. It is deprecated. You can delete it, it is not used anymore


If you used Dojo animation, make them Promise compatible with "await this.bgaPlayDojoAnimation(dojoAnim);"
=== Deprecated APP_* Classes ===
Deprecation warning:


Status bar manipulation
Reference to old APP_* class detected.


Function to change the title from the JS
We recommend you to use composition instead of extend:
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Title_bar


📌 Replace direct title div manipulation with this.statusBar.setTitle(title: string, args?: object), and benefit from replacement of ${actplayer}/${you}/... (see example in the link above).
Pass `private Game $game` in the constructor of your object that need to access Table functions


This also includes a new function to create action buttons, that are more screen-reader compatible than the previous version. The new button parameters also allow you to set a confirm popin or an autoclick for confirmation buttons
If it's too complicated, at least replace APP_Object/APP_GameClass by APP_DbObject as APP_Object/APP_GameClass may be removed soon and don't contain anything more than APP_DbObject.


📌 Replace this.addActionButton by this.statusBar.addActionButton. Notice the parameters have changed, so they need to be adapted too! Remove manual setActionTimer or manual confirm with the new parameters.
Don't hesitate to ask for help in the Dev Discord or in the Dev forum if you don't know how to do it!
class Tokens extends APP_GameClass { 
becomes:
class Tokens extends \APP_DbObject {


Notification decorators
=== Deprecated translation functions ===


New notify function that handles decorators, reducing the duplicate code on notification args.
On php side translation story is simplified


https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Notification_decorators
* totranslate function is not longer needed and can be replaced with clienttranslate
* $this->_() - can also be replaced with clienttranslate when use for non parameterized exceptions strings like


📌 Replace notifyAllPlayers by notify->all and notifyPlayer by notify->player
  throw new \BgaUserException(clienttranslate('You must choose 3 cards'));


Forbid access to global BGA variables and direct DB access on action/view files
See [[Translations]]


A new getCurrentPlayerId() function has been added to those action/view classes for easier migration
=== Deprecated getNew ===
Function getNew that was only used to create new deck object is now deprecated, use $this->deckFactory->createDeck('') instead


📌 Replace $g_user->get_id() by $this-> getCurrentPlayerId()[
=== Stats ===


Replace DB calls by $this->game->myFunctionCallingTheDB()
The stats function such as initStat, setStat and getStat are also deprecated in favor of access via the objects <code>$this->tableStats and $this->playerStats</code>
See https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php#Game_statistics


Instant cssPref on user preferences
===Legacy===
New object to access the legacy functions, removing the need to manually decode the JSON result when getting the values.


A reload is not needed anymore to apply cssPref on a user preference change.
[[Main game logic: Game.php#Legacy games API|https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Legacy_games_API]]


📌 Remove forceReload: true if it was only set to update the cssPref. The player will appreciate to not reload the whole page!
📌 Use $this->legacy->actionname instead of $this->actionnameLegacy and remove JSON decoding on getters


Dojo usage
===Any Globals===
New database table and API to handle any type variables instead of numerical values only


Dojo usage has been reduced to minimum in the new project template and the doc, as native JS is now able to do almost the same things, with better performance and more knowledge for newcomers of the native (vanilla) JS.
https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Use_globals


📌 Replace dojo by vanilla JS where possible
📌 If you had custom tables just for that you can drop them and use standard table


Skip a state
=== Server Counters ===
2 new counter classes have been added to easily handle the various counters your game might have. You also have 2 prebuilt counters: playerScore and playerScoreAux, to handle the scoring values, so you don't need to update manually the DB when setting the scores.


When you skip a state on PHP side (directly move to another state on the "st" function), the JS is still notified that the skipped state is activated, then it activates the next state just after, but you may see the skipped state buttons being created then deleted.
https://en.doc.boardgamearena.com/PlayerCounter_and_TableCounter


You can set up the _no_notify flag so that the JS notification of this skipped state is not sent, and from the JS side it considers the state was never loaded. For example, if you have a confirm step and a user preference allows to disable it, the user doesn't need to see the Confirm buttons showing then removed just after.
📌 Replace setting player_score/player_score_aux using db queries with use of $this->playerScore and $this->playerScoreAux. Remove the notifications, or part of notifications, updating the scoreCtrl counter (if you had some custom notification you may still need them).
===Updated Zombie Mode documentation and recommendations===
We now recommend making the zombie player playing randomly, instead of passing as a default. A new "Zombie Mode level" field has been added to the Game Metadata Manager, to indicated the Zombie Mode you implemented in your game.


https://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#Flag_to_indicate_a_skipped_state
https://en.doc.boardgamearena.com/Zombie_Mode


📌 Add _no_notify in the args when a state is skipped


Sound loading


New functions load/play have been added for the sounds:
===View and template files: deprecated===
'''''<gamename>.view.php, <gamename>_<gamename>.tpl''''' are now optional and are not generated anymore on a new project. The new project templates demonstrate how to work without them.


https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Sounds
📌 The DOM should be built on the JS side to remove the view/template files, so it can be complicated for old projects using them intensively. It would look like this:
this.getGameAreaElement().insertAdjacentHTML('beforeend', `
  <nowiki><span>${_('My translated text')}</span></nowiki><nowiki><div id="player-tables"></div></nowiki>
`);
 


📌 Replace template loading of sounds and global function playSound
See more in [[#Access template elements]]


Useless getGameName function on Game PHP file
====Forbid access to global BGA variables and direct DB access on action/view files====
If you did not remove action and view files, you cannot longer use some stuff in them, such $g_user global and db access functions.


The getGameName function is now useless in the Game PHP file and can be deleted
A new getCurrentPlayerId() function has been added to those action/view classes for easier migration


📌 Delete the getGameName function in the Game PHP file.
📌 Replace $g_user->get_id() by $this-> getCurrentPlayerId()


GameStateBuilder
Replace DB calls by $this->game->DbQuery() (and such...)


This new class helps you build the state machine, allowing auto-completion, and avoid typo errors on state types. Complete example: 📌 https://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php
===States===
There is now a way to describe each game state in a State class, that will handle all logic and description of the state. It helps splitting the code into multiple files, instead of one big Game.php file.


States 1 and 99, that must not be changed, are now optional.
https://en.doc.boardgamearena.com/State_classes:_State_directory


📌 Replace the array definition by GameStateBuilder use. You can remove the declaration of states 1 and 99.
📌 Create a State class for each state of the game (except 1 and 99 if they are still described in states.inc.php), move the state definition in it, and adapt the "st", "arg", "actXXX" and "zombie" functions in the class. When all classes are migrated, you can remove the states.inc.php file in the FTP folder.


Note: it's only useful if you don't migrate to State classes described later on.
==== If still using states.php====
The new class GameStateBuilder helps you build the state machine, allowing auto-completion, and avoid typo errors on state types. Complete example: 📌 https://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php


bgaFormatText
States 1 and 99, that must not be changed, are now optional.


This function, if defined, will allow you to insert HTML in the logs without overriding format_string_recursive. Example: 📌https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Define_this.bgaFormatText%28%29_method
📌 Replace the array definition by GameStateBuilder use. You can remove the declaration of states 1 and 99.


📌 Replace the override of format_string_recursive by bgaFormatText (the last line will change)
Note: it's only useful if you don't migrate to State classes described above


Future support of dark mode
==Client parts (js, html, css) ==


BGA doesn't support dark mode yet. To have some games compatible when we do, we added a theme data tag you can use as described here:
===Deprecated ajaxcall ===
Introduced function bgaPerformAction to replace ajaxcall and checkAction combination, with a simpler syntax:


https://en.doc.boardgamearena.com/Game_interface_stylesheet:_yourgamename.css#Support_of_the_Dark_mode
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Actions


Framework function for automata player panel
Deprecation warning: The <code>ajaxcall</code>  function is deprecated, check [[/en.doc.boardgamearena.com/Game interface logic: yourgamename.js#Actions|the]] <code>bgaPerformAction</code> [[/en.doc.boardgamearena.com/Game interface logic: yourgamename.js#Actions|function]].


A new framework function to add a player panel for your game automatas https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_a_player_panel_for_an_automata
📌 Replace combination of checkAction/ajaxcall by bgaPerformAction. Beware of the options (3rd param) if it was an ajaxcall without checkAction.
===Access to DOM elements ===
New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()


📌 Replace manually created automata player panel with this new function
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_stuff_to_player%27s_panel


New JS libraries
📌 Code like dojo.place(html, player_board_${player.id}); would be replaced by this.getGameAreaElement().insertAdjacentHTML('beforeend', html);
===Notification setup===
Notifications can now be automatically scanned and called without needing to register them one by one. They'll handle Promises, so they end synchronously when the Promise resolves.


We will provide new libraries to help you design your games, especially for components that you will find on numerous games. The first available libraries are:
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Notifications


[bga-animations https://en.doc.boardgamearena.com/BgaAnimations]  : a JS component to make animations, compatible with scaled or rotated containers.
A wait function has been added to return a Promise when a delay is passed (compatible with fast-replay mode)


bga-cards : a JS component to handle cards.
A new utility function has been added to support Promises for old Dojo animations


bga-dice : a JS component to handle dice.
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animation_Callbacks


bga-autofit : a JS component to make text fit on a fixed size div.
📌 Dojo.subscribe calls in setupNotifications must be removed if bgaSetupPromiseNotifications is used. Notif_ function should be async and return a Promise, make sure they wait for the expected amount of time if the sync setup was using a numerical duration


bga-score-sheet : a JS component to help you display an animated score sheet at the end of the game.
If you used Dojo animation, make them Promise compatible with "await this.bgaPlayDojoAnimation(dojoAnim);"


📌 Try them, and hopefully use them instead of the very old components! Each lib has a demo in the beginning of the wiki page to show what it can do.
===Status bar manipulation===
Function to change the title from the JS
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Title_bar


Notification args consistency
📌 Replace direct title div manipulation with this.statusBar.setTitle(title: string, args?: object), and benefit from replacement of ${actplayer}/${you}/... (see example in the link above).


Previously, when you sent an arg that was transformed by format_string_recursive or bgaFormatText, the args object was mutated and you got the transformed value in the notif_ handler.
This also includes a new function to create action buttons, that are more screen-reader compatible than the previous version. The new button parameters also allow you to set a confirm popin or an autoclick for confirmation buttons


The solution was to send the values in 2 different names like this:
📌 Replace this.addActionButton by this.statusBar.addActionButton. Notice the parameters have changed, so they need to be adapted too! Remove manual setActionTimer or manual confirm with the new parameters.
Code: Select all


[
===Dojo usage===
  'roundNumber' => $roundNumber, // number, to update the round counter
Dojo usage has been reduced to minimum in the new project template and the doc, as native JS is now able to do almost the same things, with better performance and more knowledge for newcomers of the native (vanilla) JS.
  'round_number' => $roundNumber, // number that will be transformed to string by bgaFormatText, when shown in bold in the logs
]
📌 Do not duplicate the value, as the notif_ handler will now get unmutated args


Updated Zombie Mode documentation and recommendations
📌 Replace dojo by vanilla JS where possible
{| class="wikitable"
! colspan="undefined" |Dojo API
! colspan="undefined" |Category
! colspan="undefined" |Description
! colspan="undefined" |Vanilla JS Replacement
|-
| colspan="undefined" |<code>dojo.byId("id")</code>
| colspan="undefined" |DOM Selection
| colspan="undefined" |Selects a single DOM element by its ID.
| colspan="undefined" |<code>document.getElementById("id")</code>
|-
| colspan="undefined" |<code>dojo.query("selector")</code>
| colspan="undefined" |DOM Selection
| colspan="undefined" |Selects a collection of DOM elements using CSS selectors.
| colspan="undefined" |<code>document.querySelectorAll("selector")</code> or <code>document.querySelector("selector")</code>
|-
| colspan="undefined" |<code>dojo.connect(node, "onclick", fn)</code>
| colspan="undefined" |Event Handling
| colspan="undefined" |Connects an event handler to a DOM element.
| colspan="undefined" |<code>node.addEventListener("click", fn)</code>
|-
| colspan="undefined" |<code>dojo.disconnect(handle)</code>
| colspan="undefined" |Event Handling
| colspan="undefined" |Removes an event handler created with <code>dojo.connect</code>.
| colspan="undefined" |<code>handle.remove()</code> for event listeners, or <code>node.removeEventListener("click", fn)</code>
|-
| colspan="undefined" |<code>dojo.place(node, parent, "last")</code>
| colspan="undefined" |DOM Manipulation
| colspan="undefined" |Places a DOM node inside a parent node at a specific position.
| colspan="undefined" |<code>parent.appendChild(node)</code>
|-
| colspan="undefined" |<code>dojo.create("tag", props, parent)</code>
| colspan="undefined" |DOM Manipulation
| colspan="undefined" |Creates a new DOM element with optional properties.
| colspan="undefined" |<code>document.createElement("tag")</code>, then set properties and use <code>parent.appendChild()</code>
|-
| colspan="undefined" |<code>dojo.style(node, "color", "red")</code>
| colspan="undefined" |Styling
| colspan="undefined" |Sets an inline CSS property on a DOM node.
| colspan="undefined" |<code>node.style.color = "red"</code>
|-
| colspan="undefined" |<code>dojo.hasClass(node, "className")</code>
| colspan="undefined" |Styling
| colspan="undefined" |Checks if a DOM node has a specific CSS class.
| colspan="undefined" |<code>node.classList.contains("className")</code>
|-
| colspan="undefined" |<code>dojo.addClass(node, "className")</code>
| colspan="undefined" |Styling
| colspan="undefined" |Adds a CSS class to a DOM node.
| colspan="undefined" |<code>node.classList.add("className")</code>
|-
| colspan="undefined" |<code>dojo.removeClass(node, "className")</code>
| colspan="undefined" |Styling
| colspan="undefined" |Removes a CSS class from a DOM node.
| colspan="undefined" |<code>node.classList.remove("className")</code>
|-
| colspan="undefined" |<code>dojo.forEach(array, fn)</code>
| colspan="undefined" |Array Utilities
| colspan="undefined" |Iterates over an array.
| colspan="undefined" |<code>array.forEach(fn)</code>
|-
| colspan="undefined" |<code>dojo.map(array, fn)</code>
| colspan="undefined" |Array Utilities
| colspan="undefined" |Transforms an array by applying a function to each element.
| colspan="undefined" |<code>array.map(fn)</code>
|}


We now recommend making the zombie player playing randomly, instead of passing as a default. A new "Zombie Mode level" field has been added to the Game Metadata Manager, to indicated the Zombie Mode you implemented in your game.


https://en.doc.boardgamearena.com/Zombie_Mode
===Sound loading===
New functions load/play have been added for the sounds:


State classes
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Sounds


There is now a way to describe each game state in a State class, that will handle all logic and description of the state. It helps splitting the code into multiple files, instead of one big Game.php file.
📌 Replace template loading of sounds and global function playSound


https://en.doc.boardgamearena.com/State_classes:_State_directory
===Formatting of log message using bgaFormatText===
This function, if defined, will allow you to insert HTML in the logs without overriding format_string_recursive. Example: 📌https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Define_this.bgaFormatText%28%29_method


📌 Create a State class for each state of the game (except 1 and 99 if they are still described in states.inc.php), move the state definition in it, and adapt the "st", "arg", "actXXX" and "zombie" functions in the class. When all classes are migrated, you can remove the states.inc.php file in the FTP folder.
📌 Replace the override of format_string_recursive by bgaFormatText (the last line will change)


Counters
===Future support of dark mode===
BGA doesn't support dark mode yet. To have some games compatible when we do, we added a theme data tag you can use as described here:


2 new counter classes have been added to easily handle the various counters your game might have. You also have 2 prebuild PlayerCounter: playerScore and playerScoreAux, to handle the scoring values, so you don't need to update manually the DB when setting the scores.
https://en.doc.boardgamearena.com/Game_interface_stylesheet:_yourgamename.css#Support_of_the_Dark_mode


https://en.doc.boardgamearena.com/PlayerCounter_and_TableCounter
===Automata player panel===
A new framework function to add a player panel for your game automas https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_a_player_panel_for_an_automata


📌 Replace setting manually player_score/player_score_aux with new $this->playerScore and $this->playerScoreAux. Remove the notifications, or part of notifications, updating the scoreCtrl counter.
📌 Replace manually created automata player panel with this new function


Use $this-> instead of self:: by default
===New JS libraries===
New JS libraries are created to help you design your games, especially for components that you will find on numerous games. See [[Studio#BGA Studio game components reference]]


The new project template has been updated to remove this bad practice (that may be unsupported in a future PHP version)
📌 Replace manually created animation, stocks, etc with components (check the list above, don't want to duplicate it here)

Latest revision as of 10:24, 14 November 2025

This page is only for people who started long time ago and now need to re-write older projects into more modern versions. Also if you trying to fix older game you may have to look here.

Overview

See announcement here https://studio.boardgamearena.com/forum/viewtopic.php?f=12&t=45248

📌 This symbol: direct information about migration

Structural changes

gameoptions.inc.php => gameoptions.json, gamepreferences.json

Previously, options and preferences were specified in a single gameoptions.inc.php file.

Now options and preferences are 2 json files, follow Migration steps on this page https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Migration

See #User preferences and #Game options for API changes.

When building the game with this file you will see deprecation warning: The file gameoptions.inc.php is deprecated. click "Reload game options configuration" to generate the JSON content you can then put on a gameoptions.json and gamepreferences.json file. Then you can safely delete the gameoptions.inc.php file.

<gamename>.game.php => modules/php/Game.php

Move and refactor, see section Namespaced game class

<gamename>.action.php => remove

See section Autowire game actions

<gamename>.view.php, <gamename>_<gamename>.tpl => remove

See section Removal of view and template

gameinfos.inc.php

File still there. Deprecated keys designer, artist, year, presentation, tags, complexity, strategy, luck, diplomacy, is_beta are no longer in use. Please remove these keys and use the Game Metadata Manager instead.

material.inc.php => optional

See section #Material

states.inc.php => modules/php/States

See section #States

stats.inc.php => stats.json

Deprecation warning: The file stats.inc.php is deprecated. click "Reload statistics configuration" to generate the JSON content you can then put on a stats.json file. Then you can safely delete the stats.inc.php file.

<gamename>.js

File still there but massive API changes, see bottom sections

IDE Support

A new _ide_helper.php file is now provided in every project dir, allowing IDE to provide syntax error highlighting for the framework functions. This file is regularly updated to match the latest framework updates.

Same with bga-framework.d.ts for those using TypeScript.

📌 Sync the files from the FTP dir to your local copy to benefit from it. Most of the IDE like Visual Studio Code should handle _ide_helper.php if you already followed https://en.doc.boardgamearena.com/Setting_up_BGA_Development_environment_using_VSCode

Game configuration

User preferences

Access to user preferences and listener: https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#User_preferences

📌

  • If you had a custom function called setupPreferences() reading the <select> values, you can now use onGameUserPreferenceChanged instead.
  • If you had a copy of the user preferences on a DB table, it's not needed anymore. Remove all support of writing to this table. Replace access to this table with
       $pref = $this->userPreferences->get($playerId, $prefCode) ?? $defaultValue;
  • If you used $this->player_preferences - replace the use with use of proper API

Instant cssPref on user preferences

A reload is not needed anymore to apply cssPref on a user preference change.

📌 Remove forceReload: true if it was only set to update the cssPref. The player will appreciate to not reload the whole page!

Game options

New functions to access the table options (game options) without hassle

https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Game_Options

📌

  • Remove declaration of game options from "initGameStateLabels"
  • Instead of using $this->getGameStateValue or $this->gamestate->table_globals use
$this->tableOptions->get(int $optionId)

This new object can also return the Real-time/Turn-based setting: https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Reflexion_time

Server parts (php, sql, etc)

PHP migration

Oct 2025: The migration was made from PHP7.4 to PHP8.4 new syntax and functions.

New projects are generated using the strict mode

📌

  • Replace all self:: to $this-> - The new project template has been updated to remove this bad practice (that may be unsupported in a future PHP version)
  • Add declare(strict_types=1); to all .php files and fix compiler warnings (if you use IDE it will detect it before upload).

Namespaced game class

Game class from <gamename>.game.php are now namespaced (and moved to modules/php/Game.php) and can autoload other classes of the same namespace

Main game logic: Game.php#Creating other classes

📌 The class file should be moved to modules/php/Game.php and adopted

(In examples below YourGameName is NOT verbatim its your game name)

  • Move YourGameName.game.php to modules/php (create this dir if does not exists)
  • Rename to Game.php
  • Find the place below the copyright and add
     declare(strict_types=1);
     namespace Bga\Games\YourGameName;
  • Remove
 require_once APP_GAMEMODULE_PATH . "module/table/table.game.php";
  • Find you class declaration change YouGameName to Game (verbatim) and change extends
  class Game extends \Bga\GameFramework\Table
  • All references to non-namespaced classes in this file should be defined on top of the file with "use", for example "use \BgaUserException;" as it is this non-namespaced exception is used in the zombieTurn function.
  • All includes with relative path will need to be updated too.
  • The material.inc.php to have be moved and included directly (see below)

Multiple functions of "Table" base class are now deprecated, see how to migrate in corresponding section

  • notifyAllPlayers
  • notifyPlayer
  • mysql_fetch_assoc
    • Deprecation warning: mysql_fetch_assoc function detected. It is deprecated, and may be removed someday. Please replace it by standard framework DB functions!
  • Table (class access without namespace)
  • isMutiactiveState (misspelled version)
  • ...

Material

Material file material.inc.php is now optional. You can define all your material directly in php class. If you still like to keep it, and using namespaced Game.php you have to move it to subfolder and include directly Game material description: material.inc.php#Move it to modules/php

Autowire game actions

Simplify the action calls by removing <gamename>.action.php file

https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Actions_%28autowired%29

📌 Autowired actions needs to start with "act", so it's risky to change them (if you change all actions names in the states.php, game, action and JS file, Real-time players will call the old name until they refresh. So, it needs to be done in two steps with duplicates on back side, or to be deployed when there is no Realt-time table running.

When migration is done, the action.php file can be deleted.

Deprecation warning: Actions detected on .action.php file. You can now use Auto-wired actions to avoid pass-through functions in .action.php file. If you transform your project to use only auto-wired actions, you can then delete the .action.php file.

Notifications

Functions notifyAllPlayers and notifyPlayer from main game.php are deprecated

📌 Replace $this->notifyAllPlayers with $this->notify->all and Replace $this->notifyPlayer with $this->notify->player

Notification Decorators

New notify function that handles decorators, reducing the duplicate code on notification args.

https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Notification_decorators

Notification args consistency

Previously, when you sent an arg that was transformed by format_string_recursive or bgaFormatText, the args object was mutated and you got the transformed value in the notif_ handler.

The solution was to send the values in 2 different names like this:

[
 'roundNumber' => $roundNumber, // number, to update the round counter
 'round_number' => $roundNumber, // number that will be transformed to string by bgaFormatText, when shown in bold in the logs
]

📌 Do not duplicate the value, as the notif_ handler will now get unmutated args

Deprecated getGameName

The getGameName() function is now useless in the Game PHP file and can be deleted

📌 Delete the getGameName function in the Game PHP file.

Deprecation warning: getGameName function detected. It is deprecated. You can delete it, it is not used anymore

Deprecated APP_* Classes

Deprecation warning:

Reference to old APP_* class detected.

We recommend you to use composition instead of extend:

Pass `private Game $game` in the constructor of your object that need to access Table functions

If it's too complicated, at least replace APP_Object/APP_GameClass by APP_DbObject as APP_Object/APP_GameClass may be removed soon and don't contain anything more than APP_DbObject.

Don't hesitate to ask for help in the Dev Discord or in the Dev forum if you don't know how to do it!

class Tokens extends APP_GameClass {  

becomes:

class Tokens extends \APP_DbObject { 

Deprecated translation functions

On php side translation story is simplified

  • totranslate function is not longer needed and can be replaced with clienttranslate
  • $this->_() - can also be replaced with clienttranslate when use for non parameterized exceptions strings like
 throw new \BgaUserException(clienttranslate('You must choose 3 cards'));

See Translations

Deprecated getNew

Function getNew that was only used to create new deck object is now deprecated, use $this->deckFactory->createDeck() instead

Stats

The stats function such as initStat, setStat and getStat are also deprecated in favor of access via the objects $this->tableStats and $this->playerStats See https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php#Game_statistics

Legacy

New object to access the legacy functions, removing the need to manually decode the JSON result when getting the values.

https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Legacy_games_API

📌 Use $this->legacy->actionname instead of $this->actionnameLegacy and remove JSON decoding on getters

Any Globals

New database table and API to handle any type variables instead of numerical values only

https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Use_globals

📌 If you had custom tables just for that you can drop them and use standard table

Server Counters

2 new counter classes have been added to easily handle the various counters your game might have. You also have 2 prebuilt counters: playerScore and playerScoreAux, to handle the scoring values, so you don't need to update manually the DB when setting the scores.

https://en.doc.boardgamearena.com/PlayerCounter_and_TableCounter

📌 Replace setting player_score/player_score_aux using db queries with use of $this->playerScore and $this->playerScoreAux. Remove the notifications, or part of notifications, updating the scoreCtrl counter (if you had some custom notification you may still need them).

Updated Zombie Mode documentation and recommendations

We now recommend making the zombie player playing randomly, instead of passing as a default. A new "Zombie Mode level" field has been added to the Game Metadata Manager, to indicated the Zombie Mode you implemented in your game.

https://en.doc.boardgamearena.com/Zombie_Mode


View and template files: deprecated

<gamename>.view.php, <gamename>_<gamename>.tpl are now optional and are not generated anymore on a new project. The new project templates demonstrate how to work without them.

📌 The DOM should be built on the JS side to remove the view/template files, so it can be complicated for old projects using them intensively. It would look like this:

this.getGameAreaElement().insertAdjacentHTML('beforeend', `
  <span>${_('My translated text')}</span><div id="player-tables"></div>
`);
 

See more in #Access template elements

Forbid access to global BGA variables and direct DB access on action/view files

If you did not remove action and view files, you cannot longer use some stuff in them, such $g_user global and db access functions.

A new getCurrentPlayerId() function has been added to those action/view classes for easier migration

📌 Replace $g_user->get_id() by $this-> getCurrentPlayerId()

Replace DB calls by $this->game->DbQuery() (and such...)

States

There is now a way to describe each game state in a State class, that will handle all logic and description of the state. It helps splitting the code into multiple files, instead of one big Game.php file.

https://en.doc.boardgamearena.com/State_classes:_State_directory

📌 Create a State class for each state of the game (except 1 and 99 if they are still described in states.inc.php), move the state definition in it, and adapt the "st", "arg", "actXXX" and "zombie" functions in the class. When all classes are migrated, you can remove the states.inc.php file in the FTP folder.

If still using states.php

The new class GameStateBuilder helps you build the state machine, allowing auto-completion, and avoid typo errors on state types. Complete example: 📌 https://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php

States 1 and 99, that must not be changed, are now optional.

📌 Replace the array definition by GameStateBuilder use. You can remove the declaration of states 1 and 99.

Note: it's only useful if you don't migrate to State classes described above

Client parts (js, html, css)

Deprecated ajaxcall

Introduced function bgaPerformAction to replace ajaxcall and checkAction combination, with a simpler syntax:

https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Actions

Deprecation warning: The ajaxcall function is deprecated, check the bgaPerformAction function.

📌 Replace combination of checkAction/ajaxcall by bgaPerformAction. Beware of the options (3rd param) if it was an ajaxcall without checkAction.

Access to DOM elements

New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()

https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_stuff_to_player%27s_panel

📌 Code like dojo.place(html, player_board_${player.id}); would be replaced by this.getGameAreaElement().insertAdjacentHTML('beforeend', html);

Notification setup

Notifications can now be automatically scanned and called without needing to register them one by one. They'll handle Promises, so they end synchronously when the Promise resolves.

https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Notifications

A wait function has been added to return a Promise when a delay is passed (compatible with fast-replay mode)

A new utility function has been added to support Promises for old Dojo animations

https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animation_Callbacks

📌 Dojo.subscribe calls in setupNotifications must be removed if bgaSetupPromiseNotifications is used. Notif_ function should be async and return a Promise, make sure they wait for the expected amount of time if the sync setup was using a numerical duration

If you used Dojo animation, make them Promise compatible with "await this.bgaPlayDojoAnimation(dojoAnim);"

Status bar manipulation

Function to change the title from the JS https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Title_bar

📌 Replace direct title div manipulation with this.statusBar.setTitle(title: string, args?: object), and benefit from replacement of ${actplayer}/${you}/... (see example in the link above).

This also includes a new function to create action buttons, that are more screen-reader compatible than the previous version. The new button parameters also allow you to set a confirm popin or an autoclick for confirmation buttons

📌 Replace this.addActionButton by this.statusBar.addActionButton. Notice the parameters have changed, so they need to be adapted too! Remove manual setActionTimer or manual confirm with the new parameters.

Dojo usage

Dojo usage has been reduced to minimum in the new project template and the doc, as native JS is now able to do almost the same things, with better performance and more knowledge for newcomers of the native (vanilla) JS.

📌 Replace dojo by vanilla JS where possible

Dojo API Category Description Vanilla JS Replacement
dojo.byId("id") DOM Selection Selects a single DOM element by its ID. document.getElementById("id")
dojo.query("selector") DOM Selection Selects a collection of DOM elements using CSS selectors. document.querySelectorAll("selector") or document.querySelector("selector")
dojo.connect(node, "onclick", fn) Event Handling Connects an event handler to a DOM element. node.addEventListener("click", fn)
dojo.disconnect(handle) Event Handling Removes an event handler created with dojo.connect. handle.remove() for event listeners, or node.removeEventListener("click", fn)
dojo.place(node, parent, "last") DOM Manipulation Places a DOM node inside a parent node at a specific position. parent.appendChild(node)
dojo.create("tag", props, parent) DOM Manipulation Creates a new DOM element with optional properties. document.createElement("tag"), then set properties and use parent.appendChild()
dojo.style(node, "color", "red") Styling Sets an inline CSS property on a DOM node. node.style.color = "red"
dojo.hasClass(node, "className") Styling Checks if a DOM node has a specific CSS class. node.classList.contains("className")
dojo.addClass(node, "className") Styling Adds a CSS class to a DOM node. node.classList.add("className")
dojo.removeClass(node, "className") Styling Removes a CSS class from a DOM node. node.classList.remove("className")
dojo.forEach(array, fn) Array Utilities Iterates over an array. array.forEach(fn)
dojo.map(array, fn) Array Utilities Transforms an array by applying a function to each element. array.map(fn)


Sound loading

New functions load/play have been added for the sounds:

https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Sounds

📌 Replace template loading of sounds and global function playSound

Formatting of log message using bgaFormatText

This function, if defined, will allow you to insert HTML in the logs without overriding format_string_recursive. Example: 📌https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Define_this.bgaFormatText%28%29_method

📌 Replace the override of format_string_recursive by bgaFormatText (the last line will change)

Future support of dark mode

BGA doesn't support dark mode yet. To have some games compatible when we do, we added a theme data tag you can use as described here:

https://en.doc.boardgamearena.com/Game_interface_stylesheet:_yourgamename.css#Support_of_the_Dark_mode

Automata player panel

A new framework function to add a player panel for your game automas https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_a_player_panel_for_an_automata

📌 Replace manually created automata player panel with this new function

New JS libraries

New JS libraries are created to help you design your games, especially for components that you will find on numerous games. See Studio#BGA Studio game components reference

📌 Replace manually created animation, stocks, etc with components (check the list above, don't want to duplicate it here)