Added a bunch of base level focumentation

This commit is contained in:
2024-03-09 02:15:34 -05:00
parent 9a6b5a6d35
commit 63486d2909
12 changed files with 1511 additions and 5 deletions

View File

@@ -1,7 +1,10 @@
- [About](/)
- Eluna Typescript
- Getting Started
- Configuration
- [Getting Started](./ets/GettingStarted.md)
- [Configuration](./ets/Configuration.md)
- [Building Modules](./ets/Modules.md)
- [VSCode Integration](./ets/VSCodeIntegration.md)
- [Advanced Topics](./ets/AdvancedTopics.md)
- Eluna Classes
- [Aura](./classes/Aura.md)
- [BattleGround](./classes/BattleGround.md)

View File

@@ -38,7 +38,7 @@ function TriggerCustomEventForPlayer(player: Player) {
```
This snippet demonstrates how to use `GetAreaId` to trigger a custom event when a player enters a specific area. By checking the area ID where the player moves, developers can script immersive experiences tailored to different locations in the game.
# GetDifficulty
## GetDifficulty
This method retrieves the difficulty level of the current map where the EMap instance is located. It's important to note that if the game expansion is before The Burning Crusade (pre-TBC), this method will always return `0`, implying that difficulty levels introduced in later expansions are not applicable.
### Returns
@@ -352,7 +352,7 @@ RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_CHANGE, (...args) => onPla
This example attempts to retrieve a specific NPC on the map using its GUID when a player enters a new area. If the NPC is found and is currently spawned on the map, it will say designated text, offering countless opportunities for dynamic player interactions in the game world.
# IsArena
## IsArena
Check if the current map is an Arena BattleGround. It can be useful to determine the type of battleground environment players are in to apply specific logic for arenas.
@@ -419,7 +419,7 @@ This example demonstrates how you can utilize the `IsBattleground` method to che
The `IsBattleground` method is useful in scenarios where specific game behavior, events, or conditions must be applied or checked only in non-arena battleground maps, providing a straightforward way of distinguishing between different types of PvP environments in the game.
# IsDungeon
## IsDungeon
Determines if the current map is a dungeon.

732
docs/classes/ElunaQuery.md Normal file
View File

@@ -0,0 +1,732 @@
Based on your guideline for converting TypeScript class definitions into readme documentation, here's the documentation for the `GetBool` method of the `ElunaQuery` class.
## GetBool
Retrieves the data in the specified column of the current row and returns it casted to a boolean. This function is handy when working with database query results, particularly when dealing with boolean values stored in the database.
### Parameters
- **column**: `number` - The column index in the query result from which to retrieve the boolean value.
### Returns
- `boolean` - The value from the specified column, casted to a boolean.
### Example Usage
Let's say you have a query that checks if a certain player has obtained a particular item, indicated by a boolean value in the database (1 for true, 0 for false). You can use `GetBool` to simplify the verification process in your script.
```typescript
// Example script that checks if a player has obtained a specific item
const CHECK_ITEM_OBTAINED_QUERY = "SELECT has_obtained FROM player_items WHERE player_id = ? AND item_id = ?";
const onPlayerLogin: player_event_on_login = (event: number, player: Player) => {
// Let's assume 42 is the player's ID and 101 is the item's ID
const playerId = 42;
const itemId = 101;
const query = WorldDBQuery(CHECK_ITEM_OBTAINED_QUERY, playerId, itemId);
if (query && query.GetRow()) {
// Using GetBool to check the 'has_obtained' column
const hasObtained = query.GetBool(0);
if (hasObtained) {
player.SendBroadcastMessage("Congratulations! You've obtained the special item.");
} else {
player.SendBroadcastMessage("You have not obtained the special item yet. Keep trying!");
}
} else {
player.SendBroadcastMessage("Unable to check item status.");
}
};
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => onPlayerLogin(...args));
```
In this example, `GetBool` is used to directly fetch and evaluate the boolean value from the database query result. This avoids the need for manual conversion and makes the code cleaner and more readable.
## GetColumnCount
Returns the number of columns in the result set of a query. This method can be particularly useful when you need to know the structure of the data returned by a custom SQL query executed through Eluna on AzerothCore.
### Returns
columnCount: number - The number of columns in the result set.
### Example Usage
In the example below, we demonstrate how to use `GetColumnCount` in a scripted event. When a player logs in, a custom query is executed to fetch some data, and then `GetColumnCount` is used to print out the number of columns retrieved by this query. This kind of script can be useful for developers during the testing phase to ensure their queries are returning the expected structure.
```typescript
const MY_CUSTOM_QUERY = "SELECT id, name, level FROM characters WHERE online = 1;";
const onPlayerLogin: player_event_on_login = (event: number, player: Player): void => {
// Let's assume we have a function named ExecuteQuery that executes the SQL and returns an ElunaQuery object
let queryResult = ExecuteQuery(MY_CUSTOM_QUERY);
if(queryResult) {
let columnCount = queryResult.GetColumnCount();
player.SendBroadcastMessage(`The query result has ${columnCount} columns.`);
// Optional: Iterate over rows and columns if needed
// This is just conceptual as further methods would be required for row iteration and data extraction
for(let i = 0; i < columnCount; i++) {
// Process each column
}
} else {
player.SendBroadcastMessage("Failed to execute the query or no results found.");
}
}
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => onPlayerLogin(...args));
```
In this script, `ExecuteQuery` is a hypothetical function that executes a SQL query through Eluna's database interface and returns an object of type `ElunaQuery`, which represents the result set. Through the `GetColumnCount` method, we are able to retrieve the number of columns in this result set and inform the player, aiding in database management or debugging procedures.
## GetDouble
Retrieve the data within the specified column of the current row, represented as a 64-bit floating point value. This method is crucial for situations where you need to process numeric data retrieved from a database query.
### Parameters
* `column`: number - The index of the column from which you want to retrieve the data. Note that the column index starts from 0.
### Returns
* `number` - The value present in the specified column, cast to a 64-bit floating point number.
### Example Usage:
Below is a script example demonstrating how to use the `GetDouble` method within a gameplay scenario. In this case, we'll assume there's a custom table in the database that tracks the amount of gold each player has in a bank vault not directly accessible through the standard game interface. The method retrieves the gold value for a specific player by their character ID.
```typescript
// Define a custom function to fetch and print the total gold a player has in the vault.
// This could be attached to a custom chat command or a game event.
const ShowPlayerVaultGold: CustomScript = (player: Player): void => {
// Example query string, assuming a table named `player_vault` and a column `gold_amount`.
const query = "SELECT gold_amount FROM player_vault WHERE char_id = ?";
const playerId = player.GetGUIDLow(); // Get the low part of the player's GUID, which is often used as the character ID in custom tables.
// Execute the query, replace '?' with playerId.
const result = WorldDBQuery(query.replace("?", playerId.toString()));
if (result && result.GetRowCount() > 0) {
result.NextRow(); // Move to the first (and in this case, only) row of the result.
const goldAmount: number = result.GetDouble(0); // Retrieve the gold amount from the first column.
// Inform the player about the amount of gold in their vault.
player.SendBroadcastMessage(`You have ${goldAmount} gold in your vault.`);
} else {
// Handle case where no data is returned, implying the player has no vault or no gold in it.
player.SendBroadcastMessage("No vault data found or you have no gold in the vault.");
}
}
// Registration of the custom event, function, or command goes here.
// This is just a placeholder as the registration method depends on the context in which it's used.
// e.g., RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => ShowPlayerVaultGold(...args));
```
This example provides a comprehensive way of using the `GetDouble` method to enhance gameplay by incorporating additional gameplay elements through server-side scripting.
## GetFloat
This method is used to retrieve data from the specified column of the current row in a database query result. The data is returned as a 32-bit floating point number (`float`). This is particularly useful when interacting with database fields that store numerical values with decimal points, such as character position coordinates, item weights, or other properties that require precision beyond integer values.
### Parameters
- `column`: `number` - The index of the column in the current row from which to retrieve the value. Column indexing starts at 0.
### Returns
- `number`: The value in the specified column casted to a `float`.
### Example Usage
This script demonstrates how to use the `GetFloat` method to obtain a player's X, Y, and Z coordinates from the database, which are stored as floating-point numbers. This could be part of a larger system for tracking player positions or teleporting players to specific locations.
```typescript
// Fetches player coordinates from the database
const fetchPlayerCoordinates = (playerGUID: number): { x: number, y: number, z: number } | undefined => {
// Assuming 'characters' database and 'character_position' is a table storing player positions
const query = `SELECT posX, posY, posZ FROM character_position WHERE guid = ?`;
const result = WorldDBQuery(query, playerGUID);
if (result && result.GetRowCount() > 0) {
// Move to the first (and expected only) row of the result
if (result.NextRow()) {
const x = result.GetFloat(0); // posX is in the first column
const y = result.GetFloat(1); // posY is in the second column
const z = result.GetFloat(2); // posZ is in the third column
return { x, y, z };
}
}
return undefined; // Return undefined if there was no result or any error occurred
};
// Example usage of fetchPlayerCoordinates within an event handler
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (player: Player) => {
const playerGUID = player.GetGUIDLow(); // Assuming GetGUIDLow returns the GUID used in DB
const coords = fetchPlayerCoordinates(playerGUID);
if (coords) {
console.log(`Player ${player.GetName()} logged in at X: ${coords.x}, Y: ${coords.y}, Z: ${coords.z}`);
} else {
console.error(`Failed to fetch coordinates for player ${player.GetName()}`);
}
});
```
In this example, a query is performed against a fictional `character_position` table to retrieve the X, Y, and Z coordinates of the player. The `GetFloat` method is utilized to ensure the coordinates are accurately read as floating-point numbers from the result set. This precise data is crucial for spatial computations or actions that require exact positioning in the game world.
## GetInt16
Extracts the data from the specified column in the current row and returns it as a signed 16-bit integer. This is particularly useful when dealing with data that fits within the bounds of a 16-bit integer, ensuring that the retrieved value is accurately represented within the constraints of this data type.
### Parameters
- **column**: number - The column index (starting from 0) from which to retrieve the data.
### Returns
- **number**: The value of the specified column in the current row, cast to a signed 16-bit integer.
### Example Usage:
Imagine you are working with a query result where you need to retrieve the level of a player, which is stored as an integer. For illustrative purposes, let's say the player's level is in the second column of the result set. Here's how you might use `GetInt16` to accurately get this data:
```typescript
const QUERY_GET_PLAYER_LEVEL = "SELECT player_id, player_level FROM players WHERE player_name = ?";
let playerName = "JohnDoe";
let queryResult = WorldDBQuery(QUERY_GET_PLAYER_LEVEL, playerName);
if (queryResult && queryResult.GetRowCount() > 0) {
while (queryResult.NextRow()) {
let playerLevel = queryResult.GetInt16(1); // Assuming 'player_level' is in the second column
print(`Player Level: ${playerLevel}`);
}
} else {
print("No results found or query execution error.");
}
```
In this script, `WorldDBQuery` executes a SQL command to select the player ID and level of a player with the name "JohnDoe". The `GetInt16` method is then called with the column index `1` (because indexes start at 0, 1 corresponds to the second column which is `player_level` in this case) to extract the player's level as a 16-bit signed integer. This allows for accurate and type-safe retrieval of integer data that is known to be within the range of a 16-bit number.
## GetInt32
Retrieves the data in the specified column of the current row and casts it to a signed 32-bit integer. This method is essential when working with database query results that return numerical values and ensures that the value can be easily manipulated or checked in your script.
### Parameters
- `column`: number - The column index in the query result set from which to retrieve the data. The column index is 0-based.
### Returns
- `value`: number - The data casted to a signed 32-bit integer.
### Example Usage:
Calculating Player's Total Quests Completed
In this example, we retrieve the total number of quests completed by a player from the database and log it. This can be useful for achievements, statistics, or checks within game logic.
```typescript
// Assuming playerGUID is the GUID of the player for whom we want to fetch the total quests completed.
const playerGUID = 1; // Example player GUID
const questCompletedQuery = `SELECT COUNT(*) as totalCompleted FROM character_queststatus_rewarded WHERE guid = ${playerGUID}`;
// Perform the SQL query using Eluna
WorldDBQuery(questCompletedQuery).Execute((result: ElunaQuery) => {
if (result) {
// We're only interested in the first row, column zero as our query only returns a single value.
const totalQuestsCompleted = result.GetInt32(0);
print(`Player GUID ${playerGUID} has completed ${totalQuestsCompleted} quests.`);
} else {
print(`No quests completion data found for player GUID ${playerGUID}.`);
}
});
```
This script starts by defining a SQL query that counts the number of quests a player with a specific GUID has completed. It then executes this query and, if results are found, uses the `GetInt32` method to retrieve the total counts from the first (and only) column of the result. This integer value is then printed to the console alongside the player's GUID. This example illustrates how to handle integer data from a database query within a script, enabling complex data manipulation and checks based on the game's database state.
## GetInt64
This method allows retrieval of data from a specified column of the current row in a query result set, casting the data to a signed 64-bit integer (a common type for database IDs and large count values).
### Parameters
- `column`: number - The index of the column from which to retrieve the data. Columns are indexed starting at 0.
### Returns
- `number`: The data from the specified column, casted to a signed 64-bit integer.
### Example Usage:
Imagine a scenario where you need to retrieve a player's total earned honor points, stored in a database under a column that contains large numbers, thus requiring the use of a 64-bit integer. Below is a simple script to fetch and log a player's total honor points based on their character ID.
#### Preparing the Database Query:
Firstly, ensure you have an appropriate SQL query to fetch the desired data. For example, if your database contains a table named `character_stats` with a column for honor points `honor_points` and a unique identifier `char_id`, your query might look something like:
```sql
SELECT honor_points FROM character_stats WHERE char_id=?
```
#### TypeScript Script:
```typescript
// Function to log player's total honor points
const logPlayerHonorPoints: (playerId: number) => void = (playerId: number): void => {
// Prepare your query - assume this query returns rows with a single column 'honor_points'
const queryString: string = "SELECT honor_points FROM character_stats WHERE char_id=?";
// Execute the query with playerId as the parameter
const result: ElunaQuery = WorldDBQuery(queryString, playerId);
// Assuming the query is successful and returns at least one row
if (result && result.GetRowCount() > 0) {
// Move to the first row of the result set (index 0)
result.NextRow();
// Get the 'honor_points' column value from the result set
const honorPoints: number = result.GetInt64(0); // Column index for 'honor_points' is 0
print(`Player with ID ${playerId} has a total of ${honorPoints} honor points.`);
} else {
print(`No data found for player with ID ${playerId}.`);
}
}
// Example player ID to fetch data for
const examplePlayerId: number = 12345;
// Call the function with an example player ID
logPlayerHonorPoints(examplePlayerId);
```
In this example, a `WorldDBQuery` function is assumed to execute a database query and return an `ElunaQuery` object representing the result set. The `GetInt64` method of the `ElunaQuery` class is used to retrieve the `honor_points` value for a specific player by their character ID (`char_id`). This method is beneficial when dealing with large numbers that may exceed the limitations of a 32-bit integer.
## GetInt8
This method extracts the data from the specified column of the current row, casting it to a signed 8-bit integer for efficient data handling.
### Parameters
* column: number - The index of the column in the query result set, from which the data is to be retrieved and converted to an 8-bit integer.
### Returns
* number - The data value in the specified column, casted to a signed 8-bit integer.
### Example Usage:
Let's create a script that queries the database for specific player data and utilizes the `GetInt8` method to handle a character's level, assuming that level values are stored within the scope of an 8-bit integer's range.
First, we execute a query to fetch player information, including the player's level, from the database. Then, we access this level value with `GetInt8` and use it to make in-game decisions or adjustments to the player's status.
```typescript
// The player's unique ID for querying their data
const PLAYER_GUID: number = 1;
// The SQL query to get player info. Here, 'char_level' is a hypothetical column containing the player's level.
const QUERY_STRING: string = `SELECT char_level FROM player_data WHERE guid = ${PLAYER_GUID}`;
// Execute the query
const playerQuery: ElunaQuery = WorldDBQuery(QUERY_STRING);
if (playerQuery) {
// Assuming the first column in our result contains the character's level. Column indexes start from 0.
const columnIdx: number = 0;
const playerLevel: number = playerQuery.GetInt8(columnIdx);
// Now, you can use playerLevel to make game logic decisions
if (playerLevel < 10) {
console.log(`Player with GUID ${PLAYER_GUID} is a beginner.`);
} else {
console.log(`Player with GUID ${PLAYER_GUID} has progressed beyond beginner status.`);
}
} else {
console.log("Query returned no results. Check if the player GUID is correct.");
}
```
This example illustrates how to retrieve and utilize a player's level from the database, providing a simple yet practical use case for the `GetInt8` method. It showcases how to interact with the game's database within a modding context for AzerothCore, specifically leveraging the capabilities of the Eluna scripting engine to query and manipulate player data effectively.
## GetRow
This method fetches the current row from an executed query result. It organizes the data into a table where each column's name is a key, and its corresponding row value is the pair. This allows easy access to SQL query results through key-value pairs. Numerical columns will have their values returned as numbers, while all other types of data will be returned as strings.
### Returns
- **Record<string, unknown>**: A table containing the fields of the current row, where keys are column names and values are the row's corresponding values.
### Example Usage:
The following example demonstrates how to use `GetRow` to retrieve NPC information from the `creature_template` table. It prints out the entry ID and name of the first NPC found with the specified conditions.
```typescript
// This function is triggered when a player chats ".getnpcinfo" followed by the NPC's entry ID.
const onChat: player_event_on_chat = (event: number, player: Player, message: string, msgType: number, lang: number): void => {
// Split the player's message by spaces
const args = message.split(' ');
// Check if the chat command is ".getnpcinfo"
if (args[0] === ".getnpcinfo" && args.length === 2) {
// Parse the NPC's entry ID from the second word in the chat message
const npcEntryId = parseInt(args[1]);
// Form the SQL query to retrieve the NPC's info from the creature_template table
const queryStr = `SELECT entry, name FROM creature_template WHERE entry = ${npcEntryId};`;
// Execute the query
const result = WorldDBQuery(queryStr);
// Check if the query returned any row
if (result && result.GetRow()) {
// Fetch the row data
let npcInfo = result.GetRow();
// Bind the NPC info (entry and name) to variables for easy access
let npcEntry = npcInfo.entry;
let npcName = npcInfo.name;
// Inform the player about the NPC info
player.SendBroadcastMessage(`NPC Info - Entry: ${npcEntry}, Name: ${npcName}`);
// Logic to move to the next row if needed can be implemented here
// For instance: while(result.NextRow()) { /* Process next row */ }
} else {
// Inform the player in case no NPC was found with the given entry ID
player.SendBroadcastMessage("No NPC found with the specified entry ID.");
}
}
}
// Register the chat event listener
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => onChat(...args));
```
This script makes use of the `ElunaQuery:GetRow` method to access NPC information by entry ID through a chat command. The resulting NPC data is displayed to the player who issued the command.
## GetRowCount
Returns the number of rows in the result set of a database query. This method can be used to verify the size of data retrieved, ensuring your operations can proceed with the expected amount of data.
### Returns
number - The number of rows in the result set.
### Example Usage:
Suppose you want to check the number of active players in a specific area before performing an operation, such as granting a temporary buff. You can use `GetRowCount` to ascertain the number of affected rows before proceeding.
```typescript
const REGION_ID = 123; // Example region ID
const TEMP_BUFF_ENTRY = 45678; // Example temporary buff entry
// Function to grant a temporary buff to all players in a specific region
function GrantTempBuffToRegionPlayers(regionId: number, buffEntry: number): void {
// Here we're simulating a query to select all players in a specific region
// In a real scenario, you would replace this with an actual database query
const query = `SELECT player_id FROM player_table WHERE region_id = ${regionId}`;
// Execute the query here. For demonstration, we'll pretend `dbQuery` is a function that executes the SQL and returns an ElunaQuery object
const result = dbQuery(query);
// Check the number of players in the region
const playerCount = result.GetRowCount();
if(playerCount > 0) {
console.log(`Granting buff to ${playerCount} players in region ${regionId}.`);
// Process each player and grant them the temporary buff
// For demonstration, 'processPlayersAndGrantBuff' is a placeholder for the logic to iterate over query results and grant buffs.
processPlayersAndGrantBuff(result, buffEntry);
} else {
console.log(`No players found in region ${regionId}. No buffs granted.`);
}
}
// Assume RegisterGameEvent is a method to hook into game events for execution
RegisterGameEvent(GameEvents.SOME_EVENT, () => GrantTempBuffToRegionPlayers(REGION_ID, TEMP_BUFF_ENTRY));
```
In this example, before attempting to grant temporary buffs to all players in a given region, the script checks how many players are currently present in that region using the `GetRowCount` method. This check is crucial to avoid unnecessary operations or to handle scenarios differently based on the player count.
## GetString
This method retrieves the data from the specified column of the current row of a query result, casting it to a string type. It is useful for accessing database columns that contain text-based data.
### Parameters
* column: number - The zero-based index of the column from which to retrieve the data.
### Returns
* string: The data content of the specified column casted to a string.
### Example Usage:
The following script demonstrates how to use the `GetString` method to get a player's name from the database, based on the player's GUID. This can be used, for example, in custom scripts that need to log or display the player's name without requiring the player to be online.
```typescript
const GET_PLAYER_NAME_BY_GUID: string = `
SELECT name
FROM characters
WHERE guid = ?`;
function LogPlayerNameByGuid(playerGuid: number): void {
const query = WorldDBQuery(GET_PLAYER_NAME_BY_GUID, playerGuid);
if (query) {
// Since we're selecting only one column, it's column index 0
const playerName: string = query.GetString(0);
print(`Player Name: ${playerName}`);
} else {
print(`Player with GUID ${playerGuid} not found.`);
}
}
// Register a command to test grabbing player names
RegisterPlayerCommand("logPlayerName", (player, args): void => {
if (args.length < 1) {
player.SendBroadcastMessage("Usage: .logPlayerName <playerGUID>");
return;
}
const playerGuid: number = Number(args[0]);
if (isNaN(playerGuid)) {
player.SendBroadcastMessage("Please provide a valid player GUID.");
return;
}
LogPlayerNameByGuid(playerGuid);
});
```
In this example, we define a custom command `.logPlayerName` which takes a player GUID as an argument. The script then retrieves the player's name from the `characters` table in the database using the `GetString` method to extract the name column from the result set.
The purpose of this script is to provide a simple demonstration of how to retrieve player information from the database without the need for the player to be in-game. It shows the versatility of directly interfacing with the server's database for custom scripts and functionalities within mod-eluna on Azerothcore.
## GetUInt16
Retrieve the data from the specified column of the current row, casting it to an unsigned 16-bit integer. This method is useful for fetching numerical values from a database query result where the data type is expected to be within the range of a 16-bit unsigned integer.
### Parameters
- **column**: number - The column index (starting from 0) from which to retrieve the data in the current row.
### Returns
- **value**: number - The value retrieved from the specified column, casted to an unsigned 16-bit integer.
### Example Usage:
In the example below, we perform a database query to fetch a specific NPC "entry" from the "creature_template" table. We then use `GetUInt16` to extract the NPC's model ID from the query result, assuming that the model ID is stored in the first column (index 0) of the result and can be appropriately cast to a 16-bit unsigned integer.
```typescript
import { ElunaQuery, WorldDBQuery } from 'mod-eluna';
// Function to fetch an NPC model ID by its entry ID
function fetchNPCModelID(npcEntry: number): number {
// Prepare the SQL query to retrieve the NPC model ID
const sql = `SELECT modelid1 FROM creature_template WHERE entry = ? LIMIT 1;`;
// Execute the query with the npcEntry parameter
const queryResult: ElunaQuery = WorldDBQuery(sql, npcEntry);
// Check if the query successfully returned a row
if (queryResult && queryResult.GetRowCount() > 0) {
// Retrieve the model ID from the first column of the result
const modelID: number = queryResult.GetUInt16(0);
console.log(`Model ID for NPC entry ${npcEntry} is: ${modelID}`);
return modelID;
} else {
console.log(`No data found for NPC entry ${npcEntry}.`);
return 0;
}
}
// Example usage of fetchNPCModelID function
const npcEntry = 12345; // Example NPC entry ID
const modelID = fetchNPCModelID(npcEntry);
```
This example demonstrates fetching a specific piece of numerical data from a database query result. The `GetUInt16` method efficiently casts the data to match the expected data type, allowing for straightforward handling of database query results.
## GetUInt32
Retrieves the data in the specified column of the current row from a database query's result set and casts it to an unsigned 32-bit integer. This method is integral for handling database results where the data type expected is a numeric value. It's commonly used in scenarios where integral values like item IDs, character IDs, or other numeric table identifiers are being queried from the database.
### Parameters
- **column**: number - The zero-based index of the column from which to retrieve the data.
### Returns
- **number** - The value in the specified column of the current row, casted to an unsigned 32-bit integer.
### Example Usage:
Suppose you have a database table `character_achievements` which tracks achievements that players have earned. Each row in the table contains, among other information, an achievement ID as an unsigned integer. The following script demonstrates how to query this table for a particular character's achievements and retrieve the achievement IDs using `GetUInt32`.
```typescript
const CHARACTER_ID: number = 1; // Example character ID
const QUERY = `SELECT achievement_id FROM character_achievements WHERE character_id = ${CHARACTER_ID}`;
const ProcessCharacterAchievements = (characterId: number): void => {
// Execute the query to get achievements for the given character ID
let results = WorldDBQuery(QUERY);
if (results) {
while (results.GetRow()) {
// Retrieve the achievement ID from the current row
let achievementId = results.GetUInt32(0); // Assuming 'achievement_id' is the first column
// Log or process the achievement ID as needed
console.log(`Achievement ID: ${achievementId}`);
// Example processing function - assuming it exists
ProcessAchievement(characterId, achievementId);
}
} else {
console.error(`No achievements found for character ID: ${characterId}`);
}
};
// Example usage would be triggered via some event or specific game logic condition
ProcessCharacterAchievements(CHARACTER_ID);
```
In this example, `WorldDBQuery` is a hypothetical function that executes a SQL query and returns a result set object with a method `GetRow` to iterate through rows. `GetUInt32` is used to fetch the `achievement_id` from each row. This way, each achievement ID associated with the specified character is processed.
## GetUInt64
Obtains data from the specified column of the current row and casts it to an unsigned 64-bit integer. This method can be particularly useful when dealing with values that might exceed the range of a 32-bit integer, ensuring precise data handling from database queries.
### Parameters
- **column**: number - The zero-based index of the column in the query result set from which to retrieve the data.
### Returns
- **value**: number - The data from the specified column, casted to an unsigned 64-bit integer.
### Example Usage:
In this example, we're creating a script to fetch and display a player's account creation date (stored as a UNIX timestamp in the database) in a human-readable format. We assume this timestamp is stored in the second column (index 1) of our query result.
```typescript
import * as moment from 'moment'; // Assuming moment.js is available for formatting dates
// Function to fetch and display account creation date for a player
function showAccountCreationDate(player: Player) {
// Replace '123' with the actual player ID variable or method to retrieve it
const accountId = 123;
const query = `SELECT id, creation_date FROM account WHERE id = ${accountId}`;
// Execute the query
const result = WorldDBQuery(query);
if (result) {
// Move to the first row of the result set
result.NextRow();
// Retrieve the account creation timestamp from the second column
const creationTimestamp = result.GetUInt64(1);
// Convert the UNIX timestamp to a readable date string using moment.js
const creationDate = moment.unix(creationTimestamp).format('YYYY-MM-DD HH:mm:ss');
// Notify the player of their account creation date
player.SendBroadcastMessage(`Your account was created on: ${creationDate}`);
} else {
player.SendBroadcastMessage("Unable to retrieve your account creation date.");
}
}
// Example event registration to demonstrate usage
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (_, player) => showAccountCreationDate(player));
```
In this example, `WorldDBQuery` is a fictional function used to represent the execution of a database query, and `PlayerEvents.PLAYER_EVENT_ON_LOGIN` denotes a hypothetical event triggered when a player logs in. We use `moment.js` to format the timestamp into a human-readable date.
## GetUInt8
This method is used to retrieve data from a specified column in the current row of a query result, and casts it to an unsigned 8-bit integer. This can be particularly useful when you are fetching numerical data that fits within the range of an 8-bit unsigned integer (0 to 255).
### Parameters
* **column**: number - The index of the column from which you want to fetch the data. Note that the indexing starts from `0`.
### Returns
* **number**: The data fetched from the specified column, casted to an unsigned 8-bit integer.
### Example Usage
Imagine you have a custom database table named `custom_npc_data` with the following structure:
- `id` INT (Primary Key)
- `name` VARCHAR
- `strength` TINYINT
You want to fetch the `strength` attribute (which is a TINYINT and perfectly fits into an 8-bit unsigned integer) of a specific NPC by its ID, and then use this value in your script.
```typescript
const NPC_DATA_QUERY = `SELECT strength FROM custom_npc_data WHERE id = ?`;
// Retrieved NPC ID for demonstration. In a real scenario, this might be dynamic.
const npcId = 1001;
// Prepare and execute the query by passing the NPC ID.
const queryResult = WorldDBQuery(NPC_DATA_QUERY, npcId);
// Assuming the query was successful and has at least one result row.
if (queryResult && queryResult.GetRowCount() > 0) {
// Move to the first row in the result set.
queryResult.NextRow();
// Fetch the 'strength' column value as an unsigned 8-bit integer.
const npcStrength = queryResult.GetUInt8(0); // 0 is the index for the first (and only) column in our SELECT.
// Here, `npcStrength` would hold the strength value of our NPC, ready to be used further.
print(`NPC with ID ${npcId} has a strength value of ${npcStrength}.`);
}
```
This example demonstrates how to execute a database query to the World database (assumed with `WorldDBQuery`), navigate through the result set, and utilize the `GetUInt8` method to fetch and use an 8-bit unsigned integer value from the database. This can be particularly useful in scenarios where values retrieved are known to be within the 8-bit unsigned integer range, optimizing memory and processing efficiency.
## IsNull
This method checks if the specified column in the current row of the executed query result is `NULL`. This is particularly useful when performing database operations that might return rows with optional values, ensuring that your script correctly handles NULL values to prevent errors or unintended behavior.
### Parameters
* column: number - The column index (starting from 0) to check for NULL value.
### Returns
* boolean: Returns `true` if the specified column is `NULL`, otherwise returns `false`.
### Example Usage:
Below is a script snippet that demonstrates how to use the `IsNull` method with an ElunaQuery result to check if a specific column in the retrieved data is null. This is particularly handy when dealing with optional fields in your database records.
```typescript
// Imagine you have a database table `character_optional_info`
// with a column `last_login_ip` that might be NULL for some rows.
const PLAYER_INFO_QUERY = "SELECT last_login_ip FROM character_optional_info WHERE guid = ?";
const handlePlayerLogin: player_event_on_login = (event: number, player: Player): void => {
const queryResult = WorldDBQuery(PLAYER_INFO_QUERY, player.GetGUID());
if (queryResult && !queryResult.IsNull(0)) { // Checks if the 'last_login_ip' column is not NULL
const lastLoginIp = queryResult.GetString(0); // Retrieving the IP as string
player.SendBroadcastMessage(`Welcome back! Your last login was from IP: ${lastLoginIp}`);
} else {
player.SendBroadcastMessage("Welcome! It seems like this is your first time logging in, or your IP wasn't recorded last time.");
}
}
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => handlePlayerLogin(...args));
```
In this example, when a player logs in, the script executes a query to retrieve their last login IP address from a hypothetical database table. Using `IsNull`, the script checks if the `last_login_ip` column is `NULL`. If it is not null, the player is greeted with a message including their last known IP address. If the column is null, implying the player has no recorded last login IP or this is their first login, a different message is displayed. This ensures a personalized interaction while handling potential null values effectively.
## NextRow
Advances the `ElunaQuery` object to the next row in the result set. It is important to note that this method should *not* be called immediately after executing a query because doing so will lead you to skip the first row of your results. This function is typically used within a loop to iterate through all rows returned by a query.
### Returns
boolean - `true` if the method successfully advanced to the next row; `false` if there were no more rows to advance to.
### Example Usage:
Consider a scenario where you need to iterate through all players with a specific item in their inventory and perform actions based on the players' data. You might execute a database query to get this data and then use `NextRow()` to loop through the results.
```typescript
// Example function to find players with a particular item and perform an action
const findPlayersWithItem = (itemId: number): void => {
let query = "SELECT guid, data FROM character_inventory WHERE item = " + itemId;
let result = WorldDBQuery(query); // Execute the query on the World Database
if (result) {
// Iterate through each row of the result set
while (result.NextRow()) { // Keep advancing to the next row until there are no more rows
let playerGuid = result.GetInt32(0); // Assuming the first column is the GUID
let playerData = result.GetString(1); // Assuming the second column contains some player data
// Perform actions with the player's guid and data
console.log(`Found player GUID: ${playerGuid} with data: ${playerData}`);
// Additional logic could be applied here, such as modifying the player's data, sending a message, etc.
}
} else {
console.log("No results found or query failed.");
}
}
// Call the function with an example item ID
findPlayersWithItem(12345);
```
In this example, the `NextRow()` method is crucial for iterating over all the rows returned by the query. Remember not to call `NextRow()` before starting this loop, as the initial call to `WorldDBQuery(query)` already positions the internal cursor before the first row. Subsequent calls to `NextRow()` are necessary to advance through the result set.

View File

@@ -569,3 +569,109 @@ In this example:
This example showcases how to utilize the `GetTargetDest` method to retrieve the spell's target destination coordinates and perform actions based on that information, such as spawning a creature or granting a buff to the caster depending on the landing position.
## IsAutoRepeat
Returns a boolean value indicating whether the spell is automatically repeating or not.
### Parameters
None
### Returns
boolean - `true` if the spell is automatically repeating, `false` otherwise.
### Example Usage
This example demonstrates how to check if a spell is automatically repeating and adjust the spell's behavior accordingly.
```typescript
const SPELL_SHOOT = 3018;
const SPELL_AUTO_SHOT = 75;
const onSpellCast: player_event_on_spell_cast = (event: number, player: Player, spell: Spell, skipCheck: boolean) => {
if (spell.GetEntry() === SPELL_SHOOT || spell.GetEntry() === SPELL_AUTO_SHOT) {
if (spell.IsAutoRepeat()) {
// Spell is automatically repeating
const autoRepeatCount = player.GetData("autoRepeatCount") || 0;
player.SetData("autoRepeatCount", autoRepeatCount + 1);
if (autoRepeatCount >= 5) {
// Cancel the auto-repeat after 5 repetitions
player.CastSpell(player, SPELL_SHOOT, true);
player.SetData("autoRepeatCount", 0);
}
} else {
// Spell is not automatically repeating
player.SendBroadcastMessage("You have manually cast the spell.");
}
}
};
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SPELL_CAST, (...args) => onSpellCast(...args));
```
In this example:
1. We define constants for the spell IDs of "Shoot" and "Auto Shot".
2. In the `PLAYER_EVENT_ON_SPELL_CAST` event handler, we check if the cast spell is either "Shoot" or "Auto Shot".
3. If the spell is automatically repeating (checked using `spell.IsAutoRepeat()`), we increment a counter stored in the player's data to keep track of the number of repetitions.
4. If the auto-repeat count reaches 5, we cancel the auto-repeat by manually casting the "Shoot" spell on the player and reset the auto-repeat count.
5. If the spell is not automatically repeating, we send a broadcast message to the player indicating that they have manually cast the spell.
This example showcases how the `IsAutoRepeat()` method can be used to determine if a spell is automatically repeating and make decisions based on that information, such as canceling the auto-repeat after a certain number of repetitions or performing specific actions for manually cast spells.
## SetAutoRepeat
Sets the [Spell] to automatically repeat.
### Parameters
* repeat: boolean - If 'true', the spell will automatically repeat, if 'false', the spell will not automatically repeat.
### Example Usage
This script demonstrates how to create a custom spell that will automatically repeat until the player cancels it or runs out of mana.
```typescript
// Create a custom spell ID
const CUSTOM_SPELL_ID = 123456;
// Create a spell script for the custom spell
const SpellScript = {
canCast: function(caster: Unit, target: Unit, spell: Spell): SpellCastResult {
// Only allow the spell to be cast by players
if (!caster.IsPlayer()) {
return SpellCastResult.SPELL_FAILED_DONT_REPORT;
}
return SpellCastResult.SPELL_CAST_OK;
},
onCast: function(caster: Unit, target: Unit, spell: Spell): void {
// Enable auto-repeat for the spell
spell.SetAutoRepeat(true);
},
onHit: function(caster: Unit, target: Unit, spell: Spell): void {
// Deal damage to the target
caster.DealDamage(target, 100, true);
},
onAfterCast: function(caster: Unit, target: Unit, spell: Spell): void {
// Check if the caster has enough mana to cast the spell again
const player = caster.ToPlayer();
if (!player || player.GetPower(Powers.POWER_MANA) < spell.GetPowerCost()) {
// Cancel the auto-repeat if the player doesn't have enough mana
spell.SetAutoRepeat(false);
}
}
};
// Register the spell script
RegisterSpellScript(CUSTOM_SPELL_ID, SpellScript);
```
In this example, we create a custom spell with the ID `123456`. We then register a spell script for this custom spell.
In the `canCast` function, we check if the caster is a player. If not, we return `SPELL_FAILED_DONT_REPORT` to prevent the spell from being cast.
In the `onCast` function, we enable auto-repeat for the spell using `spell.SetAutoRepeat(true)`. This will cause the spell to automatically repeat until it is canceled or the player runs out of mana.
In the `onHit` function, we deal damage to the target using `caster.DealDamage(target, 100, true)`. This will deal 100 damage to the target each time the spell hits.
Finally, in the `onAfterCast` function, we check if the player has enough mana to cast the spell again. We do this by getting the player object using `caster.ToPlayer()` and then checking their current mana using `player.GetPower(Powers.POWER_MANA)`. If the player doesn't have enough mana to cast the spell again, we cancel the auto-repeat using `spell.SetAutoRepeat(false)`.
With this script, players will be able to cast the custom spell, which will automatically repeat until they cancel it or run out of mana. Each time the spell hits a target, it will deal 100 damage.

View File

@@ -437,3 +437,413 @@ In this example, `ReadUShort` is used twice consecutively to read two 16-bit int
The use of `ReadUShort` is essential in custom packet handling, enabling mod developers to interact with complex data sent between the client and server. This method provides a way to accurately parse and utilize packet data within the AzerothCore framework for creating engaging and dynamic game experiences.
## SetOpcode
This method assigns a specific opcode to the `WorldPacket`. Opcodes are essentially identifiers that specify the type of action or message being communicated between the client and the server in World of Warcraft. Accurate assignment of opcodes is crucial for the correct handling of packets.
### Parameters
* `opcode`: number - The opcode identifier to be set for the `WorldPacket`.
### Example Usage:
In this example, we're creating a simple callback that is triggered when a player logs in. We send a custom welcome message packet to the player. To do so, we create a new `WorldPacket` and set its opcode to a hypothetical `SMSG_WELCOME_MESSAGE` (a made-up opcode for demonstration purposes), then proceed to write the message into the packet and finally send it to the player.
Assuming `SMSG_WELCOME_MESSAGE` has an opcode value of `12345`, and a fictional `SendPacket` function that sends the packet to the player.
```typescript
const WELCOME_OPCODE = 12345; // Hypothetical opcode for a welcome message
const WELCOME_MESSAGE = "Welcome to our custom World of Warcraft server!";
const onPlayerLogin: player_event_on_login = (event: number, player: Player): void => {
// Create a new WorldPacket object
let packet = new WorldPacket();
// Set the packet's opcode to our custom welcome message opcode
packet.SetOpcode(WELCOME_OPCODE);
// (Hypothetical) Writing the welcome message into the packet
// This part largely depends on how the server expects the data to be formatted
// packet.WriteString(WELCOME_MESSAGE);
// (Hypothetical) Function to send the packet to the player
// This is also server-specific and might require the player's GUID or similar identifier
// SendPacket(player, packet);
// Log to server console
console.log("Sent welcome message to player: " + player.GetName());
}
// Register the login event callback
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => onPlayerLogin(...args));
```
Note: The usage of `WriteString` and `SendPacket` functions in this example are hypothetical and serve to illustrate the concept. Actual implementations may vary based on the server's packet handling and API provided by AzerothCore and mod-eluna.
# WriteByte
This method appends a signed 8-bit integer value to the `WorldPacket`. This is essential when constructing custom packets to communicate various types of information within the AzerothCore server framework, especially when dealing with mod-eluna scripts that modify or extend default game functionality. The `WriteByte` method is critical in ensuring data is correctly packaged in the protocol's expected format.
### Parameters
- `value`: number - The signed 8-bit integer value to append to the WorldPacket.
### Example Usage:
In this example, we're sending a custom packet to the player to trigger a unique UI element or game behavior not covered by the default Eluna API. Assume in this fictional scenario, the custom packet with an opcode of `123` is handled client-side to show a special UI component that is not part of the typical game interface.
```typescript
// Opcode for our custom UI display packet
const CUSTOM_UI_DISPLAY_OPCODE = 123;
// The specific value that triggers our unique UI behavior
const UNIQUE_UI_TRIGGER = -57;
// Function to create the packet and send it to the player
function sendUniqueUIDisplay(player: Player): void {
let packet: WorldPacket = new WorldPacket(CUSTOM_UI_DISPLAY_OPCODE, 1); // 1 byte for our signed integer
packet.WriteByte(UNIQUE_UI_TRIGGER); // Appends our trigger value to the packet
player.SendPacket(packet); // Send the packet to the player
}
// Example on how to use sendUniqueUIDisplay
// This could be called from some event, like when a player enters a specific area or triggers a custom event
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ZONE_CHANGE, (player: Player) => {
// Assuming some condition is met that requires showing the unique UI
sendUniqueUIDisplay(player);
});
```
This script utilizes the `WriteByte` method to append a signed 8-bit integer to a custom packet. It demonstrates creating a packet, appending data, and sending it to a player. Custom packets like this can be used to extend gameplay in ways not initially provided by the AzerothCore platform, showing the flexibility of mod-eluna scripts when used creatively.
## WriteDouble
Writes a 64-bit floating-point value to the [WorldPacket]. This method is useful when you need to transmit numerical data that requires high precision, such as coordinates or mathematical calculations, over the network.
### Parameters
* `value`: number - A 64-bit floating-point number to write to the packet.
### Example Usage:
Consider an example where you need to send a precise location of an event happening in the game world, such as the exact position where a special item should appear.
```typescript
const EVENT_ITEM_SPAWN_ID = 40000; // Example item ID for a special event item
const EVENT_SPAWN_LOCATION_X = 1234.5678; // Precise X coordinate for the spawn location
const EVENT_SPAWN_LOCATION_Y = 9101.1121; // Precise Y coordinate for the spawn location
const EVENT_SPAWN_LOCATION_Z = 3141.5926; // Precise Z coordinate for the spawn location
/**
* A simple script to create a world event packet that defines where the special item should spawn.
* @param eventID Unique identifier for the custom event
*/
function createSpecialEventSpawnPacket(eventID: number): WorldPacket {
let packet = new WorldPacket(); // Assume WorldPacket is a constructible entity for example purposes
packet.WriteUInt32(eventID); // Write the event ID as an unsigned int
packet.WriteDouble(EVENT_SPAWN_LOCATION_X); // Write the X coordinate as a double
packet.WriteDouble(EVENT_SPAWN_LOCATION_Y); // Write the Y coordinate as a double
packet.WriteDouble(EVENT_SPAWN_LOCATION_Z); // Write the Z coordinate as a double
return packet;
}
/**
* A demonstration of how you might register and handle a custom event that makes use of the packet.
*/
function onSpecialEvent(): void {
let spawnPacket = createSpecialEventSpawnPacket(EVENT_ITEM_SPAWN_ID);
// SendPacket() is a hypothetical function demonstrating packet sending
SendPacket(spawnPacket);
}
// Hypothetical event registration, assuming an event system that can handle custom-defined events
RegisterCustomEvent("SpecialItemSpawnEvent", () => onSpecialEvent());
```
In this example, `createSpecialEventSpawnPacket` is a function that prepares a `WorldPacket` for broadcasting the spawn location of a special item during a world event. The location's precision is crucial for gameplay, hence the use of `WriteDouble` to ensure the coordinates are transmitted accurately.
This demonstrations an efficient use of the `WriteDouble` method, as part of an event that enhances the game world's dynamism and player engagement by precisely controlling the environment.
## WriteFloat
This method is utilized to write a 32-bit floating-point value to a [WorldPacket](./worldpacket.md), facilitating the communication of numeric data particularly useful for transmitting movement data, attributes, or any scenario where precision decimal values are required in packet transmission within the AzerothCore environment.
### Parameters
* value: number - The 32-bit floating-point value to be written into the [WorldPacket].
### Example Usage:
In this example, we demonstrate how to create a custom movement packet for a player. This could be part of a larger module designed to manipulate player movements or to apply custom effects that require precise location adjustments.
```typescript
import { PlayerEvents, WorldPacket, Opcode } from 'azerothcore';
const onPlayerJump: player_event_on_jump = (player: Player): void => {
// Creating a new WorldPacket with an opcode for movement (This is a made-up opcode for demonstration)
const movementPacket = new WorldPacket(Opcode.SMSG_PLAYER_CUSTOM_MOVEMENT);
// Example coordinates
const jumpHeight = 1.5; // Arbitrary jump height increase
// WriteFloat can be used to encode precise movement details
// Here, we're assuming a fictional method to encode the player's current x, y, z coordinates
// and append a jump height to influence in-game behavior
movementPacket.WriteFloat(player.GetPositionX());
movementPacket.WriteFloat(player.GetPositionY());
movementPacket.WriteFloat(player.GetPositionZ() + jumpHeight);
// Sending the customized packet back to the player, applying the effect
player.SendDirectMessage(movementPacket);
}
// Register the event listener for player jump actions
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_JUMP, (...args) => onPlayerJump(...args));
```
This script intercepts the player's jump action, creating a custom `WorldPacket` that alters the player's movement by artificially increasing the jump height. It demonstrates the use of `WriteFloat` to encode this change within the packet before it's dispatched back to the player, showcasing the versatility and precision of floating-point data in packet manipulation.
## WriteGUID
This method allows for writing an unsigned 64-bit integer value to a `WorldPacket`. This is particularly useful for network communication where you might need to send GUIDs (Globally Unique Identifiers) of entities or objects across the network.
### Parameters <hr />
* value: number - The unsigned 64-bit integer value to write into the WorldPacket.
### Example Usage:
In this example, we send a packet to update a player's pet GUID. This might be part of a larger function where a player gets a new pet, and the server needs to notify the client about the change.
```typescript
// Assuming there's a function to update player's pet, which requires sending the new pet's GUID to the player's client.
function updatePlayerPet(player: Player, petGUID: number): void {
// Create a new WorldPacket. Assuming OPCODE_UPDATE_PET_GUID exists and is correct for this hypothetical scenario.
let packet = new WorldPacket(OPCODE_UPDATE_PET_GUID);
// Write the pet's GUID into the packet.
packet.WriteGUID(petGUID);
// Send the packet to the player.
player.SendPacket(packet);
}
// Example usage within an event when a player acquires a new pet.
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_NEW_PET, (player: Player, petGUID: number) => {
updatePlayerPet(player, petGUID);
});
```
In this scenario, it's assumed that `OPCODE_UPDATE_PET_GUID` is an existing operation code in the system that handles updating a player's pet GUID. The `WorldPacket` class is used to package the data (in this case, the new pet's GUID), which is then sent to the client using the player's `SendPacket` method. This is a crucial part of handling server-client communication in an MMO framework like AzerothCore with mod-Eluna.
Remember to always consider the underlying data structure and requirements of the packets you are working with. The GUID should fit within an unsigned 64-bit integer range, and appropriate checks should be made to ensure data integrity and security.
## WriteLong
Writes a signed 32-bit integer (`int32`) value to the `WorldPacket`. This method is primarily used in packet creation, where you need to append various data types to your packet before sending it over the network. The `WorldPacket` class is a fundamental part of message handling and network communication within the AzerothCore framework.
### Parameters <hr />
`value`: number - The 32-bit signed integer to append to the packet.
### Example Usage:
This example demonstrates how to create a custom packet that sends a simple message containing a numeric value to the player. This hypothetical packet could inform the client about a specific state change that involves an integer value, such as a countdown timer, a score, or currency adjustment.
```typescript
// Example: Sending a custom packet with a countdown timer value
const MY_CUSTOM_OPCODE: number = 123; // Hypothetical custom opcode
const COUNTDOWN_VALUE: number = 10; // Example countdown value
const SendCountdownPacket: player_event_on_login = (event: number, player: Player): void => {
// Create a new WorldPacket object with our custom opcode
let packet = new WorldPacket(MY_CUSTOM_OPCODE);
// Write our countdown value to the packet
packet.WriteLong(COUNTDOWN_VALUE);
// Send the packet to the player
player.SendPacket(packet);
}
// Register our login event to send the packet when a player logs in
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => SendCountdownPacket(...args));
```
In this script, we create a new `WorldPacket` with a hypothetical opcode `123` and use the `WriteLong` method to append a numeric value (`COUNTDOWN_VALUE`) to it. Finally, we send this packet to the player upon login by registering the script to the `PLAYER_EVENT_ON_LOGIN` event. This is a simple example to demonstrate packet creation and handling; in a real-world scenario, opcodes and implementations may vary.
# WriteShort
This method is used to write a signed 16-bit integer (short) into a `WorldPacket`. In World of Warcraft's client-server communication, packets are used to send and receive data. Using `WriteShort`, developers can ensure that the data being sent conforms to the expected 16-bit signed integer format, crucial for various gameplay features.
### Parameters
- **value**: number - The 16-bit signed integer you want to write into the packet.
### Example Usage
Below is an example demonstrating how to use the `WriteShort` method to modify a `WorldPacket` by writing a player's health difference after taking damage. This could be part of a larger system where custom spell effects or damage calculations are implemented.
```typescript
const SPELL_DAMAGE_EVENT: player_event_on_spell_hit = (event: number, caster: Player, target: Unit, spell: Spell) => {
const spellDamage = 120; // Example spell damage value
const targetHealthBefore = target.GetHealth();
target.DealDamage(spellDamage);
const targetHealthAfter = target.GetHealth();
const healthDifference = targetHealthBefore - targetHealthAfter;
// Create a new WorldPacket
let damagePacket = new WorldPacket();
// Assuming -32768 <= healthDifference <= 32767 since WriteShort handles signed 16-bit
damagePacket.WriteShort(healthDifference);
// Further packet preparation and sending logic goes here
// For demonstration purposes only
console.log(`Damage packet prepared with health difference: ${healthDifference}`);
}
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SPELL_HIT, (...args) => SPELL_DAMAGE_EVENT(...args));
```
In this example, when a player hits a target with a spell, the system calculates the damage, modifies the target's health accordingly, and captures the health change. This health difference is then written into a `WorldPacket` using `WriteShort`. This packet could then be sent to the client or used in further server-side logic to, for example, display custom damage numbers, trigger specific effects based on the damage done, or log the event for analytics purposes. This demonstrates the creation and initial manipulation of packets, which is foundational for advanced gameplay mechanics and custom interactions in mods for Azerothcore utilizing Eluna.
## WriteString
This method is used to write a string to a [WorldPacket], which is a core component for handling data packets in AzerothCore's network communication. [WorldPacket](https://www.azerothcore.org/) is essentially a buffer that contains data to be sent between the server and the client. The `WriteString` function allows for dynamically adding text data to the packet, adhering to the protocol's formatting requirements.
### Parameters
- `value`: string - The string to be written into the [WorldPacket].
### Example Usage:
The following script exemplifies how to create a custom server message that can be sent to a player. This message contains dynamic content, in this case, a player's name, that is fetched at runtime and inserted into the WorldPacket before being sent.
```typescript
// Import necessary modules from Eluna/AzerothCore scripting environment
import { WorldPacket, Player } from "azerothcore-eluna";
// Custom function to send a welcome message to a player
function sendWelcomeMessage(player: Player): void {
// Define Server opcode for downstream messages (example opcode, actual opcodes differ)
const SERVER_MESSAGE_OPCODE = 123;
// Create a new WorldPacket with the defined opcode
let packet = new WorldPacket(SERVER_MESSAGE_OPCODE);
// Constructing the welcome message with dynamic player's name
const welcomeMessage = `Welcome to Azeroth, ${player.GetName()}! We're glad you're here.`;
// Writing constructed message string to packet
packet.WriteString(welcomeMessage);
// Sending packet directly to the player
player.SendPacket(packet);
console.log(`Sent welcome message to ${player.GetName()}`);
}
// Example of registering the function to be called upon player login
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (player) => {
sendWelcomeMessage(player);
});
```
This script dynamically constructs a welcome message including the player's name by fetching it at runtime with `player.GetName()`, writes the message into the `WorldPacket` using the `WriteString` method, and finally sends this packet to the player, effectively displaying the message to them in-game. This method of packet handling is crucial for custom server-client interactions within mods built for AzerothCore using mod-eluna.
## WriteUByte
Writes an unsigned 8-bit integer value to the [WorldPacket]. This is essential for constructing packets for custom commands or responses in a mod.
### Parameters
- `value`: number - The value to write as an unsigned 8-bit integer. Must be between 0 and 255.
### Example Usage
In this example, we create a simple custom packet to change the player's speed. This example showcases how to use the `WriteUByte` method to add an identifier byte and then how to use other hypothetical methods like `WriteFloat` to add a floating-point value for the speed.
```typescript
const SPEED_CHANGE_IDENTIFIER = 0xA1; // Custom identifier for our speed change packet
const NEW_SPEED = 1.5; // The new speed value
const onChangePlayerSpeed: player_event = (player: Player): void => {
let packet = new WorldPacket(); // Assuming WorldPacket is a creatable instance here
packet.WriteUByte(SPEED_CHANGE_IDENTIFIER); // Writes our custom packet identifier
packet.WriteFloat(NEW_SPEED); // Hypothetical method to write a float value for the new speed
player.SendPacket(packet); // Hypothetical method to send the packet to the player, affecting the player's speed
console.log("Speed change packet sent to player."); // Logging for debug purposes
}
// Register our custom event (hypothetical) that calls our function to change player speed
// Assuming there's a mechanism in place to trigger this event
RegisterPlayerEvent(PlayerEvents.CUSTOM_EVENT_SPEED_CHANGE, (...args) => onChangePlayerSpeed(...args));
```
In this script, we use a fabricated scenario where a custom packet identified by `SPEED_CHANGE_IDENTIFIER` is sent to the player, requesting their client to change speed to a specified value. The `WriteUByte` method is crucial for specifying the packet type, allowing the client to correctly interpret and process the following data, which in this case is the new speed value written by a hypothetical `WriteFloat` method.
This example aims to illustrate the use of `WriteUByte` in a packet construction context, showing how such low-level operations are foundational in custom mod development for AzerothCore using the Eluna engine.
## WriteULong
Writes an unsigned 32-bit integer value to the WorldPacket, which is used to send data between the server and the client. This allows developers to customize data packets for various features and functionality within the Azerothcore mod.
### Parameters
- **value**: `number` - The unsigned 32-bit integer value to write into the WorldPacket.
### Example Usage
In this example, we will create a simple feature that allows sending a custom server message to a player indicating their current health percentage rounded to the nearest whole number. This showcases the use of `WriteULong` to send packet data.
First, we define the packet structure and the message opcode, assuming `CUSTOM_OPCODE` is predefined in your mod environment:
```typescript
const CUSTOM_OPCODE = 123; // Example opcode, replace with actual opcode
```
Next, we create a function that constructs and sends the custom packet to the player:
```typescript
function SendHealthStatus(player: Player): void {
const playerHealth = player.GetHealthPct(); // Gets the player's current health percentage
const healthMessage = `Your current health is around ${Math.round(playerHealth)}%. Stay safe!`;
const packet = new WorldPacket(); // Create a new WorldPacket instance
packet.WriteULong(CUSTOM_OPCODE); // Write the custom message opcode
/*
Assuming that the custom opcode requires the message length followed by the message itself,
and considering an additional hypothetical WriteString method for simplicity.
*/
packet.WriteULong(healthMessage.length); // Write the length of the message
packet.WriteString(healthMessage); // Hypothetically write the message string
player.SendPacket(packet); // Send the custom packet to the player
}
// Registering an event for demonstration, such as player login
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (event: number, player: Player) => {
SendHealthStatus(player); // Send the health status message upon player login
});
```
In the above code, `WorldPacket` is used to create a custom data packet that includes a message opcode and the message contents tailored for the player. The `WriteULong` method is specifically used to write both the message opcode and its length as unsigned 32-bit integers, following a simplified and hypothetical structure of how packets might be constructed in a mod for Azerothcore.
This example illustrates a potential use case for `WriteULong`, enabling mod developers to craft custom interactions and communications within the game. Remember, the actual implementation and requirements may vary based on the specifics of your mod and Azerothcore's current capabilities.
# WriteUShort
This method allows for writing an unsigned 16-bit integer (also known as ushort) value to a `[WorldPacket]`. Coding for network communication or data packet manipulation often requires handling data in specific, compact formats. This method is particularly used when dealing with packet creation or editing in the context of server-client data exchanges in Azerothcore's mod-eluna scripting.
### Parameters
- `value`: number - The unsigned 16-bit integer to write to the packet.
### Example Usage:
Below is a scripted example demonstrating how to use `WriteUShort` to create a custom packet that sends a specific two-byte data structure—perhaps an action code or a smaller data set like an item's quantity. This custom packet could be part of a larger system, such as updating the UI or triggering specific client-side effects not typically exposed through the standard Eluna API.
```typescript
function SendCustomPacket(player: Player, actionCode: number): void {
const OPCODE: number = 123; // Example opcode for the custom packet
let packet = new WorldPacket(); // Assuming WorldPacket constructor is accessible and not simplified for illustration
packet.SetOpcode(OPCODE); // Method to set the packet's operation code - not defined but assumed for demonstration
packet.WriteUShort(actionCode); // Writing our hypothetical action code as an unsigned short to the packet
// Additional packet construction here...
// For instance, adding a string or another integer based on the packet's intended structure and use case
player.SendPacket(packet); // Sending the custom packet to the player
console.log(`Sent custom packet with action code ${actionCode} to ${player.GetName()}.`);
}
// Registering a hypothetical player event to trigger our custom packet as a demonstration
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (player: Player) => {
const WELCOME_ACTION_CODE: number = 256; // Example action code for welcoming the player
SendCustomPacket(player, WELCOME_ACTION_CODE);
});
```
In this hypothetical example, assume that sending this custom packet triggers a specific behavior on the client-side, represented by the `actionCode`. The `SendCustomPacket` function encapsulates the creation and dispatch of the packet, leveraging the `WriteUShort` method to insert the action code into the packet's payload. The script showcases a potential use case within the mod-eluna framework for enhancing interactive gameplay elements or extending the client-server communication beyond the available API functions in Azerothcore.

View File

@@ -0,0 +1,51 @@
# Advanced Topics
For developers looking to dive deeper into the capabilities of ETS-Cli, this section explores advanced features and integrations, including using Rochet2's AIO with WoW API for creating complex server-served addons.
## Using Rochet2's AIO with WoW API
Rochet2's AIO system is a powerful tool for creating intricate addons that can be served directly from the server to the client, enhancing gameplay with new features and interactions.
### Installation and Setup
Before incorporating AIO into your modules, you must first install and configure it on your server. Visit the [AIO GitHub page](https://github.com/Rochet2/AIO) for detailed installation instructions.
### Example: Creating a Gambling Game
This example demonstrates how to use AIO alongside the WoW API to build AIO UI elements into the client without requiring user patching or installing plugins.
**Server-side Script (aio.server.ts):**
```typescript
/** @ts-expect-error */
let aio: AIO = {};
const SLOT_GAME_OBJECT = 750001;
const ShowGambler: player_event_on_command = (event: number, player: Player, command: string): boolean => {
if (command === 'gamble') {
aio.Handle(player, 'GamblerMain', 'ShowFrame');
return false;
}
return true;
};
```
**Client-side Script (aio.client.ts)**
```typescript
/** @ts-expect-error */
let aio: AIO = {};
if (!aio.AddAddon()) {
const gamblerHandlers = aio.AddHandlers('GamblerMain', {});
function ShowSlots(player: Player) {
const GamblerMainFrame = CreateFrame("Frame", "GamblerMainFrame", UIParent, "UIPanelDialogTemplate");
GamblerMainFrame.SetSize(512, 324);
GamblerMainFrame.SetMovable(false);
GamblerMainFrame.SetPoint("CENTER");
GamblerMainFrame.EnableMouse(true);
GamblerMainFrame.EnableKeyboard(true);
GamblerMainFrame.Hide();
}
```

97
docs/ets/Configuration.md Normal file
View File

@@ -0,0 +1,97 @@
# Configuration
Proper configuration of the ETS-Cli environment is crucial for efficient development and deployment of your modules. This section provides detailed information on configuring your development environment and preparing for deployment.
### Environment Settings Configuration
After initializing your ETS project, an `ets.env` file is created in your project directory. This file contains essential configuration settings for your development and deployment process. Key settings include:
!> Unless you are building a complex project, you should keep the defaults that are
installed in the `ets.env` from init.
- **ETS_MODULE_DIR**: Defines where individual modules are transpiled to. Default is 'modules'.
- **ETS_COMMON_DIR**: Indicates where common functions are transpiled when running `npx ets libs`. Default is 'common'.
- **ETS_MODULES_TS_DIR**: The root directory for TypeScript module creation. Default is 'modules'.
### Deployment Configuration
Deployment configuration settings are also specified in the `ets.env` file. These settings are critical for deploying your modules to a development or production server. Key deployment configurations include:
- **DEV_HOST**: The host address for SCP file connections. Localhost or IP addresses can be used for local or remote deployment, respectively.
- **DEV_PATH**: The server directory path where files are copied during deployment.
- **DEV_USER**: Username for SCP login.
- **DEV_PASS**: Password for SCP login.
- **DEV_PORT**: Port used for SCP server connection. Defaults to 22.
- **DEV_PRIVATE_KEY**: Path to a private key for SSH connections, if applicable.
- **DEV_PRIVATE_KEY_PASS**: Passphrase for the private key, if applicable.
Remember to replace `DEV_` with `PROD_` for production environment configurations.
## Set up remote deployment
To deploy your modules to an Azerothcore or Trinitycore server via SSH, setting up SSH key authentication is recommended. This method enhances security by eliminating the need to enter a password for each deployment.
### Generating an SSH Key Pair
1. Open a terminal on your local machine.
2. Generate a new SSH key pair with the command:
```bash
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```
Replace your_email@example.com with your email address. This email is just a label to help you identify the key.
3. Follow the on-screen instructions to specify a file to save the key and enter a passphrase for extra security, or for simplicity leave it blank.
### Adding Your SSH Key to the Server
1. Copy your public SSH key. If you used the default save location, your public key can be found in ~/.ssh/id_rsa.pub.
```bash
cat ~/.ssh/id_rsa.pub
```
2. Login to your remote WoW Server
3. Now, append your public SSH key to the authorized_keys file, you copied from your local machine earlier. You can do this by editing ~/.ssh/authorized_keys using a text editor or by running:
```bash
echo (replace with your_public_key) >> ~/.ssh/authorized_keys
```
?> If you have not set up authorized keys on the server use the commands below when logged into to your remote server.
```bash
mkdir -p ~/.ssh
touch ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```
## Default configuration:
```bash
# ETS Build Settings
# In order for the build to work correctly all build setting values must be set
# The program does not have defaults and builds will fail.
# Root folder where built modules will be stored.
ETS_BUILD_ROOT="./dist"
# directory where transpiled lua modules will be built for deployment
ETS_MODULE_DIR="module"
# Build directory of where common tstl lualibraries if needed by modules
ETS_COMMON_DIR="common"
# Root where all TS Modules are found from root of project
ETS_MODULES_TS_DIR="modules"
# deployment dev settings
DEV_HOST=
DEV_PATH=
DEV_USER=
DEV_PASS=
#DEV_PORT=
#DEV_PRIVATE_KEY=
#DEV_PRIVATE_KEY_PASS=
# deploy prod settings
PROD_HOST=
PROD_PATH=
PROD_USER=
PROD_PASS=
#PROD_PORT=
#PROD_PRIVATE_KEY=
#PROD_PRIVATE_KEY_PASS=
```

View File

@@ -0,0 +1,43 @@
# Getting Started
### Overview
ETS-Cli simplifies the development process, enabling you to leverage TypeScript and TypeScriptToLua to enhance or create new server content without needing extensive Lua knowledge. Whether you're looking to introduce new gameplay features, automate server tasks, or customize player interactions, ETS-Cli provides the foundation you need to bring your ideas to life.
Getting started with the Eluna TypeScript Module (ETS-Cli) is your first step toward creating custom scripts for WoW servers with Eluna installed. This section covers the prerequisites, installation process, and initial setup to get your development environment ready.
### Prerequisites
Before you begin, ensure you have the following installed on your system:
- NodeJS (version 18 or higher). NodeJS is essential for running the ETS-Cli tool and its dependencies.
>Note Download and install NodeJS from the [official website](https://nodejs.org/en/download/).
### Installation
Once you've installed NodeJS, setting up ETS-Cli is straightforward. Follow these steps to create your first ETS project:
1. **Create Your Project Directory**:
```bash
mkdir my-ets-project
cd my-ets-project
```
2. **Initialize a New NodeJS Project**:
Initialize your project with npm. This will create a package.json file in your project directory.
```bash
npm init -y
```
3. **Install ETS-Cli**:
Install the ETS-Cli package using npm. This command adds ETS-Cli to your project's dependencies.
```bash
npm install wow-eluna-ts-module
```
4. **Initialize Your ETS Project**:
Use the ETS-Cli tool to initialize your project. This step sets up the necessary configuration files and directory structure.
```bash
npx ets init
```
After completing these steps, your development environment is set up, and you're ready to start creating your first module.
With your environment set up, you're now ready to dive into module development. Proceed to the Creating Modules section to learn how to create, build, and deploy your custom scripts.

45
docs/ets/Modules.md Normal file
View File

@@ -0,0 +1,45 @@
# Modules
Modules or scripts are individual scripts that are transpiled to Lua scripts and bundle to be used at runtime inside of a private server core. These enable developers to create small gameplay additions, without needing to recompile the private server core. This has an advantage in speed of delivery and rapid iteration.
## Building Your Module
Build your module with `npx ets build`. This compiles your TypeScript code into Lua, which can then be deployed to your server. This transpiles your code into the .dist folder, utilize the script `npm run depoy:dev` for local testing.
### Module Example
You can generate a sample module that is the traditional Hello World example by initializing your module with `npx ets init -x`.
?> You can find more examples of modules in the class sections of these docs and on the public [module registry](https://github.com/araxiaonline/wow.ets.modules)
## Deploying Your Module
Use `npx ets deploy -e [dev|prod]` to deploy your module to your server. Ensure your `ets.env` is configured correctly for deployment.
## Module template
Here is a recommended approach when designing modules that highlights sections of a module anatomy for consitent patterns.
```typescript
/**
* Module Purpose
* @author
* @date
*/
/**
* Configuration
*/
const CONFIG_OPTION: string = "DefaultConfig"
/**
* Event Handlers
*/
const OnCommand: player_event_on_command = ( event: number, player: Player, command: string ) {
// your code on that action
}
/**
* Event Registers
* EventHooks: https://www.azerothcore.org/pages/eluna/?search=Register
*/
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => onCommand(...args));
```

View File

@@ -0,0 +1,19 @@
# VSCode Integration
ETS-Cli offers integration with VSCode through snippets, making it easier to develop modules by providing templates for common patterns around event hooks.
The format of the snippets follows this convention:
```
[object name]_(event_name) // creature_on_... or player_on_...
```
## Installing Snippets
Run the following command in your project directory:
```bash
npx ets snippets
```
#### Here is a visual example of how snippets work inside of VScode for this project.
![Player Snippets](image.png)

BIN
docs/ets/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
docs/media/snippets.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB