diff --git a/.env.example b/.env.example
new file mode 100644
index 000000000..39f40a884
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,11 @@
+# ENVIRONMENT determines the folder where we'll look for binaries.
+# If you're using Release, change the build command to: docker compose run --rm melia-server dotnet publish
+# Release performance tends to have better performance, Debug will have more info for development.
+
+ENVIRONMENT="Debug" # Options: Release | Debug
+
+# Database password
+MYSQL_ROOT_PASSWORD="123456" # Use a strong password, change in ./user/conf/database.conf too
+
+# Automatically restart server. If using on-failure, sets amount of retries
+SERVER_RESTART="unless-stopped" # Options: no | unless-stopped | always | on-failure:5
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index d75bfd214..df9864c6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,10 +5,12 @@
/log/
/logs/
/cache/
-
+/.mysql/
/user/**
+/.env
!/user/conf/database-example.conf
+!/user/conf/database-example-for-docker.conf
!/user/db/items-example.txt
!/user/scripts/scripts_custom-example.txt
!/user/scripts/scripts_content-example.txt
diff --git a/README.md b/README.md
index 23de2e0fd..2964038d2 100644
--- a/README.md
+++ b/README.md
@@ -12,13 +12,6 @@ with any services provided by game developers or publishers, and we don't
endorse such actions. We're here to learn and create, not to steal or
destroy.
-Client
------------------------------------------------------------------------------
-
-Melia does not have a client of its own at this time. Instead, it's designed
-to be network compatible with the latest client of the international
-version of ToS, which is freely available on Steam.
-
State of Development
-----------------------------------------------------------------------------
@@ -29,6 +22,7 @@ of the typical features you would expect from an online RPG, but
there's still a way to go before we'd call it truly playable.
Specifically, some of the major features that are working are as follows:
+
- Characters (creation, deletion, etc.)
- Inventory (managing items, equipping, etc.)
- Chat
@@ -41,7 +35,116 @@ Specifically, some of the major features that are working are as follows:
- Monster spawns
- Quests
-Requirements
+Installation with Docker
+-----------------------------------------------------------------------------
+
+This branch aims to make Melia easier to setup and run in any environment.
+To achieve this, we're making a few changes do add the capability of building
+and running Melia on Linux, as well as building and running the server in a
+few Docker containers.
+
+For this to work, you will need [Docker](https://docs.docker.com/) installed
+on your system. Recent versions of Docker comes with [Docker Compose](https://docs.docker.com/compose/)
+pre-installed, so you don't have to worry about it.
+
+After cloning or downloading this repository, rename file `.env.example` to
+`.env` and change configuration as needed. Then, navigate to the project folder
+(where you'll find `docker-compose.yml` ) and run:
+
+```bash
+docker compose build
+```
+
+This will download the necessary Docker Images for our project to run and
+build a new image with `./Servers/Dockerfile`, where our server dependencies
+are listed.
+
+Now, you can run:
+
+```bash
+docker compose run --rm melia-server dotnet build
+```
+
+This will create our server binaries, making it ready to start with our next
+command:
+
+```bash
+docker compose up -d
+```
+
+Wait for a few seconds for everything to initialize. Then, you can go to your
+browser and access [http://127.0.0.1/toslive/patch/serverlist.xml] to check
+if server is up and running.
+
+You can restart server if anything goes wrong using:
+
+```bash
+docker compose restart
+```
+
+If you change anything on source code, you need to run
+`docker compose run --rm melia-server dotnet build` again and restart your
+server with `docker compose restart`
+
+Database with Docker
+-----------------------------------------------------------------------------
+
+With the Docker containers, we've added a PHPMyAdmin container, which can be
+accessed via [http://127.0.0.1:8080]. Default user is `root` and password
+is `123456` (You can change password on `.env`, but remember to change on
+`user/conf/database.conf` as well).
+
+Client
+-----------------------------------------------------------------------------
+
+Melia does not have a client of its own at this time. Instead, it's designed
+to be network compatible with the latest client of the international
+version of ToS, which is freely available on Steam.
+
+After downloading, open your client folder (Steam > Right-Click on Game >
+Manage > Browse Local Files). Then, open `release/client.xml` with a text
+editor.
+
+Change the line which starts with `
+```
+
+Note: If your server is not on the same machine you're playing, change
+`127.0.0.1` to your Server's LAN / WAN IP.
+
+Now you can open your game and play.
+
+If you're using Docker, you can't use server's console to create your
+account, so, when logging in for the first time, use `new__` as a prefix
+to your username.
+
+Example:
+
+```bash
+Username: new__myaccount
+Password: mypassword
+```
+
+This will create an account with username `myaccount` and password
+`mypassword`. You can check the database to make sure everything is okay,
+but you'll already be connected and playing. Next time, just login with
+your username without the `new__` prefix.
+
+Installation from scratch
+-----------------------------------------------------------------------------
+
+- Compile Melia
+- Run `sql/main.sql` to setup the database
+- Copy `system/conf/database.conf` to `user/conf/`,
+ adjust the necessary values and remove the rest.
+
+Afterwards, you should be able to start Melia via the provided scripts or
+directly from the bin directories. If not, or if you need a more detailed
+guide, head over to our forum, the chat, or the wiki.
+
+Requirements to build from scratch
-----------------------------------------------------------------------------
Melia is being developed in C# (.NET 8+) and uses a MySQL database for
@@ -57,18 +160,6 @@ macOS, you will need to install the SDK as well.
For more detailed instructions, please wait patiently while we give
our documentation a much-needed overhaul. It's only a matter of time.
-Installation
------------------------------------------------------------------------------
-
-* Compile Melia
-* Run `sql/main.sql` to setup the database
-* Copy `system/conf/database.conf` to `user/conf/`,
- adjust the necessary values and remove the rest.
-
-Afterwards, you should be able to start Melia via the provided scripts or
-directly from the bin directories. If not, or if you need a more detailed
-guide, head over to our forum, the chat, or the wiki.
-
Contribution
-----------------------------------------------------------------------------
@@ -77,8 +168,7 @@ Check the file CONTRIBUTING.md for instructions on how you may contribute.
Links
-----------------------------------------------------------------------------
-* GitHub: https://github.com/NoCode-NoLife/melia
-* Wiki: https://github.com/NoCode-NoLife/melia/wiki
-* Forum: https://nocodenolife.org/forum/65-melia/
-* Chat: https://discord.gg/5sszEgw
-
+- GitHub: https://github.com/NoCode-NoLife/melia
+- Wiki: https://github.com/NoCode-NoLife/melia/wiki
+- Forum: https://nocodenolife.org/forum/65-melia/
+- Chat: https://discord.gg/5sszEgw
diff --git a/Servers/Dockerfile b/Servers/Dockerfile
new file mode 100644
index 000000000..67fdb3b52
--- /dev/null
+++ b/Servers/Dockerfile
@@ -0,0 +1,10 @@
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
+
+WORKDIR /
+
+RUN apt update -y && apt upgrade -y && apt install -y dotnet-sdk-8.0 aspnetcore-runtime-8.0 git php libapache2-mod-php php-cgi php-mysql vim
+
+WORKDIR /melia
+
+CMD ["./start", "Debug", "BarracksServer"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 000000000..911b399b6
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,65 @@
+name: "melia"
+services:
+ melia-database:
+ container_name: melia-database
+ image: mysql:8.3
+ networks:
+ - melia-network
+ ports:
+ - 3306:3306
+ environment:
+ - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
+ volumes:
+ - ./sql:/docker-entrypoint-initdb.d
+ - ./.mysql/:/var/lib/mysql
+ restart: ${SERVER_RESTART}
+ env_file:
+ - ./.env
+ healthcheck:
+ test: "/usr/bin/mysql --user=root --password=${MYSQL_ROOT_PASSWORD} --execute \"SHOW DATABASES;\""
+ interval: 5s
+ timeout: 10s
+ retries: 40
+
+ melia-server:
+ container_name: melia-server
+ command: "./start ${ENVIRONMENT}"
+ # command: "tail -f /dev/null"
+ build: "./Servers"
+ networks:
+ - melia-network
+ volumes:
+ - ./:/melia
+ depends_on:
+ melia-database:
+ condition: service_healthy
+ ports:
+ - "2000:2000"
+ - "6001:6001"
+ - "7001:7001"
+ - "7002:7002"
+ - "80:80"
+ restart: ${SERVER_RESTART}
+ env_file:
+ - ./.env
+ phpmyadmin:
+ container_name: melia-dbadmin
+ networks:
+ - melia-network
+ image: phpmyadmin
+ ports:
+ - 8080:80
+ restart: ${SERVER_RESTART}
+ environment:
+ - PMA_HOST=melia-database
+ - PMA_USER=root
+ - PMA_PASSWORD=${MYSQL_ROOT_PASSWORD}
+ - UPLOAD_LIMIT=300M
+ profiles: []
+ env_file:
+ - ./.env
+ depends_on:
+ melia-database:
+ condition: service_healthy
+networks:
+ melia-network:
diff --git a/sql/updates/update_2024-08-11_1.sql b/sql/updates/update_2024-08-11_1.sql
index 7ce4ba50d..e83a8e58d 100644
--- a/sql/updates/update_2024-08-11_1.sql
+++ b/sql/updates/update_2024-08-11_1.sql
@@ -1,18 +1,17 @@
-CREATE TABLE `character_etc_properties` (
- `propertyId` bigint(20) NOT NULL,
+CREATE TABLE IF NOT EXISTS `character_etc_properties` (
+ `propertyId` bigint(20) NOT NULL AUTO_INCREMENT,
`characterId` bigint(20) NOT NULL,
`name` varchar(64) NOT NULL,
`type` varchar(1) NOT NULL,
- `value` varchar(255) NOT NULL
+ `value` varchar(255) NOT NULL,
+ PRIMARY KEY (`propertyId`),
+ KEY `characterId` (`characterId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-ALTER TABLE `character_etc_properties`
- ADD PRIMARY KEY (`propertyId`),
- ADD KEY `characterId` (`characterId`);
-
-ALTER TABLE `character_etc_properties`
- MODIFY `propertyId` bigint(20) NOT NULL AUTO_INCREMENT;
+-- Drop the foreign key if it exists
+-- ALTER TABLE `character_etc_properties`
+-- DROP FOREIGN KEY `character_etc_properties_ibfk_1`;
+-- Add the foreign key constraint again
ALTER TABLE `character_etc_properties`
- ADD CONSTRAINT `character_etc_properties_ibfk_1` FOREIGN KEY (`characterId`) REFERENCES `characters` (`characterId`) ON DELETE CASCADE ON UPDATE CASCADE,
- ADD CONSTRAINT `character_etc_properties_ibfk_2` FOREIGN KEY (`characterId`) REFERENCES `characters` (`characterId`) ON DELETE CASCADE ON UPDATE CASCADE;
+ADD CONSTRAINT `character_etc_properties_ibfk_1` FOREIGN KEY (`characterId`) REFERENCES `characters` (`characterId`) ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/sql/updates/update_2024-08-11_2.sql b/sql/updates/update_2024-08-11_2.sql
index 69fee9512..948950c7f 100644
--- a/sql/updates/update_2024-08-11_2.sql
+++ b/sql/updates/update_2024-08-11_2.sql
@@ -1,13 +1,23 @@
-CREATE TABLE `storage_team` (
+CREATE TABLE IF NOT EXISTS `storage_team` (
`accountId` bigint(20) NOT NULL,
`itemId` bigint(20) NOT NULL,
- `position` int(11) NOT NULL
+ `position` int(11) NOT NULL,
+ PRIMARY KEY (`accountId`, `itemId`),
+ KEY `itemId` (`itemId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+-- Drop the first foreign key if it exists
+-- ALTER TABLE `storage_team`
+-- DROP FOREIGN KEY `storage_team_ibfk_1`;
+
+-- Drop the second foreign key if it exists
+-- ALTER TABLE `storage_team`
+-- DROP FOREIGN KEY `storage_team_ibfk_2`;
+
+-- Add the first foreign key constraint
ALTER TABLE `storage_team`
- ADD PRIMARY KEY (`accountId`,`itemId`),
- ADD KEY `itemId` (`itemId`);
+ADD CONSTRAINT `storage_team_ibfk_1` FOREIGN KEY (`accountId`) REFERENCES `accounts` (`accountId`) ON DELETE CASCADE ON UPDATE CASCADE;
+-- Add the second foreign key constraint
ALTER TABLE `storage_team`
- ADD CONSTRAINT `storage_team_ibfk_1` FOREIGN KEY (`accountId`) REFERENCES `accounts` (`accountId`) ON DELETE CASCADE ON UPDATE CASCADE,
- ADD CONSTRAINT `storage_team_ibfk_2` FOREIGN KEY (`itemId`) REFERENCES `items` (`itemUniqueId`) ON DELETE CASCADE ON UPDATE CASCADE;
+ADD CONSTRAINT `storage_team_ibfk_2` FOREIGN KEY (`itemId`) REFERENCES `items` (`itemUniqueId`) ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/src/BarracksServer/BarracksServer.cs b/src/BarracksServer/BarracksServer.cs
index 6af6bbb60..601f57862 100644
--- a/src/BarracksServer/BarracksServer.cs
+++ b/src/BarracksServer/BarracksServer.cs
@@ -231,9 +231,9 @@ private void Communicator_OnRequestReceived(string sender, RequestMessage reques
var message = new ResServerListMessage(servers);
var responseMessage = new ResponseMessage(requestMessage.Id, message);
- this.Communicator.Send(sender, responseMessage);
- break;
- }
+ this.Communicator.Send(sender, responseMessage);
+ break;
+ }
}
}
diff --git a/src/Shared/Configuration/Files/Web.cs b/src/Shared/Configuration/Files/Web.cs
index a457c18f8..f30ea2620 100644
--- a/src/Shared/Configuration/Files/Web.cs
+++ b/src/Shared/Configuration/Files/Web.cs
@@ -1,4 +1,5 @@
-using System.IO;
+using System;
+using System.IO;
using Yggdrasil.Configuration;
namespace Melia.Shared.Configuration.Files
@@ -17,8 +18,12 @@ public class WebConfFile : ConfFile
public void Load(string filePath)
{
this.Include(filePath);
-
- this.PhpCgiFilePath = this.GetString("php_cgi_bin", Path.Combine("user", "tools", "php", "php-cgi.exe"));
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ {
+ this.PhpCgiFilePath = this.GetString("php_cgi_bin", Path.Combine("user", "tools", "php", "php-cgi.exe"));
+ } else {
+ this.PhpCgiFilePath = this.GetString("php_cgi_bin", "/usr/bin/php-cgi");
+ }
}
}
}
diff --git a/src/ZoneServer/Commands/ChatCommands.Handlers.cs b/src/ZoneServer/Commands/ChatCommands.Handlers.cs
index 22fadaaa2..49667bc16 100644
--- a/src/ZoneServer/Commands/ChatCommands.Handlers.cs
+++ b/src/ZoneServer/Commands/ChatCommands.Handlers.cs
@@ -65,7 +65,21 @@ public ChatCommands()
this.Add("item", "- [amount]", "Spawns item.", this.HandleItem);
this.Add("silver", "", "Spawns silver.", this.HandleSilver);
this.Add("spawn", " [amount=1] ['ai'=BasicMonster] ['tendency'=peaceful] ['hp'=amount]", "Spawns monster.", this.HandleSpawn);
- this.Add("madhatter", "", "Spawns all headgears.", this.HandleGetAllHats);
+
+ this.Add("madhatter", "", "Spawns all hair accessories.", this.HandleGetAllHairAccessories);
+ this.Add("getallwings", "", "Spawns all wings.", this.HandleGetAllWings);
+ this.Add("getalltoys", "", "Spawns all toys.", this.HandleGetAllToys);
+ this.Add("getallarmbands", "", "Spawns all armbands.", this.HandleGetAllArmbands);
+ this.Add("getallcostumes", "", "Spawns all costumes.", this.HandleGetAllCostumes);
+ this.Add("getalllens", "", "Spawns all lens.", this.HandleGetAllLens);
+ this.Add("getalleffectcostumes", "", "Spawns all effect costumes.", this.HandleGetAllEffectCostumes);
+ this.Add("getallspecialcostumes", "", "Spawns all special costumes.", this.HandleGetAllSpecialCostumes);
+ this.Add("getallspecialcostumeskins", "", "Spawns all special costume skins.", this.HandleGetAllSpecialCostumeSkins);
+ this.Add("getallhairs", "", "Spawns all hairs.", this.HandleGetAllHairs);
+ this.Add("getallhelmets", "", "Spawns all helmets.", this.HandleGetAllHelmets);
+ this.Add("getalldolls", "", "Spawns all dolls.", this.HandleGetAllDolls);
+ this.Add("removeallfromgender", "", "Remove All from gender.", this.HandleRemoveAllFromGender);
+
this.Add("levelup", "", "Increases character's level.", this.HandleLevelUp);
this.Add("joblevelup", "", "Increases character's job level.", this.HandleJobLevelUp);
this.Add("speed", "", "Modifies character's speed.", this.HandleSpeed);
@@ -684,10 +698,284 @@ private CommandResult HandleSpawn(Character sender, Character target, string mes
///
///
///
- private CommandResult HandleGetAllHats(Character sender, Character target, string message, string command, Arguments args)
+ private CommandResult HandleGetAllHairAccessories(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=628001;
+ int endId=629511;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "hair accessories";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available wings to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllWings(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=637000;
+ int endId=637999;
+ int[] additionalItems = new int[] { 635572 }; // Add the Little Ghost Balloon which is off ID range
+ string itemTypeName = "wings";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available toys to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllToys(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=630001;
+ int endId=635121;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "toys";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available armbands to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllArmbands(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=11101;
+ int endId=11147;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "armbands";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available costumes to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllCostumes(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=620101;
+ int endId=635510;
+ int[] additionalItems = new int[] { 635570, 635571 }; // Reissue Cafe T-shirt Male and Female
+ string itemTypeName = "costumes";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available lens to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllLens(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=18001;
+ int endId=18016;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "lens";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available effect costumes to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllEffectCostumes(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=639101;
+ int endId=639126;
+ int[] additionalItems = new int[] { 640000 }; // White Snowflake Crystal
+ string itemTypeName = "effect costumes";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available special costumes to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllSpecialCostumes(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=638000;
+ int endId=638012;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "special costumes";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available special costume skins to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllSpecialCostumeSkins(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=750000;
+ int endId=750008;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "special costume skins";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available hairs to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllHairs(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=12111;
+ int endId=19003;
+ int[] additionalItems = new int[] { 635054, 635055 }; // [EVENT] Cockatrice Head (Male, Female)
+ string itemTypeName = "hairs";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available helmets to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllHelmets(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=10001;
+ int endId=19030;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "helmets";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+ ///
+ /// Adds all available dolls to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllDolls(Character sender, Character target, string message, string command, Arguments args)
+ {
+ int startId=900001;
+ int endId=900004;
+ int[] additionalItems = new int[] { };
+ string itemTypeName = "dolls";
+ return HandleGetAllSelectedItems(sender, target, message, command, args, startId, endId, additionalItems, itemTypeName);
+ }
+
+
+ ///
+ /// Remove all available gendered items from target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleRemoveAllFromGender(Character sender, Character target, string message, string command, Arguments args)
+ {
+ string itemTypeName = "item";
+ var addedCount = 0;
+
+ string strCompare = sender.Gender == Gender.Male ? "(Female)" : "(Male)";
+
+ foreach (var item in sender.Inventory.GetItems())
+ {
+
+ Log.Warning(item.Value.Data.Name);
+ var itemIsToBeDeleted = item.Value.Data.Name.Contains(strCompare, StringComparison.InvariantCultureIgnoreCase);
+ if(itemIsToBeDeleted)
+ {
+ sender.Inventory.Remove(item.Value, 1, InventoryItemRemoveMsg.Destroyed);
+ addedCount++;
+ }
+ };
+ if (sender == target)
+ {
+ sender.ServerMessage(Localization.Get("Removed {0} {1} from your inventory."), addedCount, itemTypeName);
+ }
+ else
+ {
+ target.ServerMessage(Localization.Get("{1} removed {0} {2} from your inventory."), addedCount, sender.TeamName, itemTypeName);
+ sender.ServerMessage(Localization.Get("Removed {0} {1} to target's inventory."), addedCount, itemTypeName);
+ }
+
+ return CommandResult.Okay;
+ }
+
+ ///
+ /// Adds all requested and availabled items to target's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private CommandResult HandleGetAllSelectedItems(Character sender, Character target, string message, string command, Arguments args, int startId, int endId, int[] additionalItems, string itemTypeName)
{
var addedCount = 0;
- for (var itemId = 628001; itemId <= 629503; ++itemId)
+ for (var itemId = startId; itemId <= endId; ++itemId)
+ {
+ if (!ZoneServer.Instance.Data.ItemDb.Contains(itemId))
+ continue;
+
+ if (!sender.Inventory.HasItem(itemId))
+ {
+ sender.Inventory.Add(new Item(itemId), InventoryAddType.PickUp);
+ addedCount++;
+ }
+ }
+
+ // for each additional item
+ foreach (var itemId in additionalItems)
{
if (!ZoneServer.Instance.Data.ItemDb.Contains(itemId))
continue;
@@ -701,12 +989,12 @@ private CommandResult HandleGetAllHats(Character sender, Character target, strin
if (sender == target)
{
- sender.ServerMessage(Localization.Get("Added {0} hats to your inventory."), addedCount);
+ sender.ServerMessage(Localization.Get("Added {0} {1} to your inventory."), addedCount, itemTypeName);
}
else
{
- target.ServerMessage(Localization.Get("{1} added {0} hats to your inventory."), addedCount, sender.TeamName);
- sender.ServerMessage(Localization.Get("Added {0} hats to target's inventory."), addedCount);
+ target.ServerMessage(Localization.Get("{1} added {0} {2} to your inventory."), addedCount, sender.TeamName, itemTypeName);
+ sender.ServerMessage(Localization.Get("Added {0} {1} to target's inventory."), addedCount, itemTypeName);
}
return CommandResult.Okay;
diff --git a/src/ZoneServer/ZoneServer.cs b/src/ZoneServer/ZoneServer.cs
index 84e7cdc59..1dd849778 100644
--- a/src/ZoneServer/ZoneServer.cs
+++ b/src/ZoneServer/ZoneServer.cs
@@ -101,7 +101,11 @@ public override void Run(string[] args)
var title = string.Format("Zone ({0}, {1})", groupId, serverId);
ConsoleUtil.WriteHeader(ConsoleHeader.ProjectName, title, ConsoleColor.DarkGreen, ConsoleHeader.Logo, ConsoleHeader.Credits);
- ConsoleUtil.LoadingTitle();
+
+ // Skip the following command on incompatible systems
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ ConsoleUtil.LoadingTitle();
+
// Set up zone server specific logging or we might run into
// issues with multiple servers trying to write files at the
@@ -124,8 +128,21 @@ public override void Run(string[] args)
this.StartCommunicator();
this.StartAcceptor();
- ConsoleUtil.RunningTitle();
- new ConsoleCommands().Wait();
+
+ // If running on Windows system, enable console inputs
+ // otherwise, start an event loop to keep server running until stopped
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ {
+ ConsoleUtil.RunningTitle();
+ new ConsoleCommands().Wait();
+ }
+ else
+ {
+ while (true)
+ {
+ System.Threading.Thread.Sleep(5000);
+ }
+ }
}
///
diff --git a/start b/start
new file mode 100755
index 000000000..0ebc9e0f8
--- /dev/null
+++ b/start
@@ -0,0 +1,56 @@
+#!/bin/sh
+# killall -9 BarracksServer
+# killall -9 ZoneServer
+# killall -9 WebServer
+echo "Starting Melia Project..."
+SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+ENVIRONMENT=$1
+FILENAME=$2
+GROUP_ID=$3
+SERVER_ID=$4
+SUBFOLDER="net8.0"
+
+do_error () {
+ echo ""
+ echo $1
+ echo ""
+ exit 1
+}
+
+run_all() {
+ cd "$SCRIPTPATH/bin/$ENVIRONMENT/$SUBFOLDER"
+ for FILEN in BarracksServer ZoneServer WebServer
+ do
+ sh -c "./$FILEN $GROUP_ID $SERVER_ID" &
+ sleep 10
+ done
+ tail -f /dev/null
+}
+
+run_process() {
+ cd "$SCRIPTPATH/bin/$ENVIRONMENT/$SUBFOLDER"
+ sh -c "./$FILENAME $GROUP_ID $SERVER_ID"
+}
+
+if [ -z "$ENVIRONMENT" ]
+then
+ ENVIRONMENT="Debug"
+fi
+
+if [ -z "$GROUP_ID" ]
+then
+ GROUP_ID="1001"
+fi
+
+if [ -z "$SERVER_ID" ]
+then
+ SERVER_ID="1"
+fi
+
+if [ -z "$FILENAME" ]
+then
+ run_all
+else
+ run_process
+fi
+
diff --git a/stop b/stop
new file mode 100755
index 000000000..8ef4cc2e7
--- /dev/null
+++ b/stop
@@ -0,0 +1,6 @@
+#!/bin/sh
+echo "Stoping Melia Project..."
+
+killall -9 BarracksServer
+killall -9 ZoneServer
+killall -9 WebServer
diff --git a/system/conf/commands.conf b/system/conf/commands.conf
index 9f55aff87..f15f3ca11 100644
--- a/system/conf/commands.conf
+++ b/system/conf/commands.conf
@@ -93,6 +93,22 @@ spawn : 50,50
// Adds all hats to inventory
madhatter : 50,50
+// Adds all {item type} to inventory
+getallwings : 50,50
+getalltoys : 50,50
+getallarmbands : 50,50
+getallcostumes : 50,50
+getalllens : 50,50
+getalleffectcostumes : 50,50
+getallspecialcostumes : 50,50
+getallspecialcostumeskins : 50,50
+getallhairs : 50,50
+getallhelmets : 50,50
+getalldolls : 50,50
+
+// Remove all items in inventory that are for the other gender
+removeallfromgender : 50,50
+
// Levels character up
levelup : 50,50
diff --git a/system/conf/database.conf b/system/conf/database.conf
index 314324f8e..a385611e9 100644
--- a/system/conf/database.conf
+++ b/system/conf/database.conf
@@ -7,4 +7,4 @@ user : root
pass :
database : melia
-include "/user/conf/database.conf"
+include "/user/conf/database.conf"
\ No newline at end of file
diff --git a/system/conf/web.conf b/system/conf/web.conf
index 68a02359c..e06fbc756 100644
--- a/system/conf/web.conf
+++ b/system/conf/web.conf
@@ -5,6 +5,6 @@
// Path to the PHP CGI executable
// If the file doesn't exist, and the configured path is in user/tools/,
// PHP is downloaded automatically on Windows.
-php_cgi_bin: user/tools/php/php-cgi.exe
+php_cgi_exe: /usr/bin/php-cgi
include "/user/conf/web.conf"
diff --git a/user/conf/database-example-for-docker.conf b/user/conf/database-example-for-docker.conf
new file mode 100644
index 000000000..0fc5648f6
--- /dev/null
+++ b/user/conf/database-example-for-docker.conf
@@ -0,0 +1,8 @@
+// Melia
+// Configuration file
+//----------------------------------------------------------------------------
+
+host : melia-database
+user : root
+pass : 123456
+database : melia