Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!
I´ve been working on CodeDragon´s release recently and after asking him permission I decided to open this thread. The aim of this project is to learn how the sources work and to fix and expand this awesome release TOGETHER WITH THE COMMUNITY.
EDIT[11-1-14]: I deleted all the fixes since none is actually contributing. Please, read this post:
Since none has contributed but CodeDragon and it takes a lot of time to explain and update my changes, I have decided to stop posting fixes. I still work on this release and I will post it one I finish it (everything but the userlist packet, sorry. It is private), but I wont update this post with code, only screenshots.
What I added so far:
* Improved the healing system. Now its fully funcional.
* Improved the player damage calculations to be more like the vanilla game. Headshot detected properly.
* Added Team Death Match to CQC and UO/BG.
* Added Conquest.
* Flags are working.
* Ammo recharge works.
* You can place any item on the ground and use it (TMA has to be debugged)
* The launcher packet is now configurable. So you can update the client easily.
* Level check for the Itemshop added.
* Level check for joining a room added.
* Fixed notice manager
* Added some config parameters: bombTime, dinar and exp rate, maximum team difference
* Added the classic coupon system. You can add new codes in the database.
* Added some missing packets: death confirmed, logout packet.
Im working on vehicles a.t.m. Once I finish them Ill move to clan system and then I will fix a couple of bugs in CQC and some bugs about the lobby update. The last step will consist on more security checks and optimization.
Thanks for posting! Before you post in this topic, please consider if this post is useful. If it's not don't reply to this. If you need help you can post your questions in the help section. I'll report every post that isn't useful in this topic! This thread is only for contributions and not for (childish) feedback.
[DB] the levels_gained table has been modified: Now it has 5 rows: id, game_id, current_level, levels_gained, timestamp.
ID is an int type row. game_id has been changed from int to Text. Now the log works like this: id (player id matching the DB index), game_id (nickname of the player, can be changed to use user id lol), current_level (player´s level), levels_gained (number of levels gained during the level up, most times 1), timestamp (date in unix format).
* Fixed a bug in the level up event. The player could lose the money earned if he logged out the game without buying anything (anything that updated the DB info, to be more accurate).
AlterEmu\Game\Entities\User.cs Added a direct DB insertion. I don´t know why, updating user.Money didn´t update the DB if the player logged off.
Add this line just before the lof query to update game_levels_gained
Code:
Databases.Game.AsyncQuery("UPDATE user_details SET money=" + this.Money + " WHERE id=" + this.ID);
* Added dinar rate and XP rate to the configuration file (.ini).
AlterEmu\Game\Config.cs
Code:
using Core.IO;
using System;
namespace Game {
class Config {
public static string AUTH_SERVER_IP = "127.0.0.1";
public static byte SERVER_ID = 0;
public static string SERVER_KEY = "SERVER-KEY";
public static string SERVER_NAME = "AlterEmu";
public static string SERVER_IP = "";
public static int MAXIMUM_ROOM_COUNT = 5;
public static int MAXIMUM_TEAM_DIFFRENCE = 1;
public static double EXPRATE = 1.0;
public static double DINARRATE = 1.0;
public static uint LEVEL_UP_MONEY_REWARD = 25000u;
public static string[] GAME_DATABASE;
public static bool Read()
{
INIFile configFile = new INIFile("config");
bool result = false;
if (configFile.Exists())
{
AUTH_SERVER_IP = configFile.Read("auth-server", "ip");
SERVER_KEY = configFile.Read("auth-server", "key");
SERVER_NAME = configFile.Read("server", "name");
SERVER_IP = configFile.Read("server", "bindip");
//Game configuration
string _expRate = configFile.Read("game-configuration", "exprate");
string _dinarRate = configFile.Read("game-configuration", "dinarrate");
double.TryParse(_expRate, out EXPRATE);
double.TryParse(_dinarRate, out DINARRATE);
if (EXPRATE == 0 || DINARRATE == 0)
{
Log.Instance.WriteError("Exprate or dinarrate values are 0 or not a number " + _expRate + "/" + _dinarRate);
Log.Instance.WriteError("Using default values");
EXPRATE = 1.0;
DINARRATE = 1.0;
}
else
{
//Just in case some dumbass tries to put a negative number
EXPRATE = Math.Abs(EXPRATE);
DINARRATE = Math.Abs(DINARRATE);
}
GAME_DATABASE = new string[]
{
configFile.Read("game-database", "host"),
configFile.Read("game-database", "port"),
configFile.Read("game-database", "username"),
configFile.Read("game-database", "password"),
configFile.Read("game-database", "database")
};
result = true;
}
return result;
}
}
}
Thanks CodeDragon! Later I´ll update the first post with all the changes done so far. I´m also implementing a simple ban check. I hope I can post it here soon.
EDIT: Added all the changes made until now to the first post.
EDIT2: This project is still alive and running. I´m just too busy with exams a.t.m.
Sorry for double-posting but I´ve made a lot of changes to the code and I felt like a post was needed after 2 weeks.
First of all I´M VERY SORRY, the NOTICE MANAGER WAS BUGGY. I just fixed it. The format of the messages sent were wrong and the data management was a disaster.
FIXED NOTICE MANAGER:
AlterEmu\Game\Managers\NoticeManager.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using Game.Enums;
using Game.Networking;
using MySql.Data.MySqlClient;
namespace Game.Managers
{
class NoticeManager
{
List<string> ActiveNotices = new List<string>();
public NoticeManager()
{
}
public bool Load()
{
MySqlCommand cmd = new MySqlCommand("SELECT * FROM notices", Databases.Game.connection);
MySqlDataReader Reader = cmd.ExecuteReader();
int _inactiveNotices = 0;
if(Reader.HasRows)
{
while(Reader.Read())
{
byte _id = Reader.GetByte("id");
string _message = Reader.GetString("message");
byte _active = Reader.GetByte("active");
if(_active == 1)
{
ActiveNotices.Add(_message);
}
else
_inactiveNotices++;
}
Log.Instance.WriteLine("Notice manager found " + ActiveNotices.Count.ToString() + " active notices");
Reader.Close();
if(ActiveNotices.Count > 0)
{
System.Timers.Timer Timer = new System.Timers.Timer();
Timer.Enabled = true;
Timer.Interval = 600000;
Timer.Elapsed += (sender, e) => NoticeLoop(sender, e, ActiveNotices);
}
}
else
{
Reader.Close();
Log.Instance.WriteError("Notice manager couldn´t parse the notice table");
return false;
}
return true;
}
private static void NoticeLoop(object sender, ElapsedEventArgs e, List<string> messages)
{
Random Random = new Random();
int _index = Random.Next(0, messages.Count());
string _message = MessageTranslator("Notice: " + messages[_index]);
Core.Networking.OutPacket Notice = new Packets.Chat("Server", ChatType.Notice2, _message, 100, "NULL");
Managers.ChannelManager.Instance.SendAllLobbies(Notice.BuildEncrypted());
}
public static string MessageTranslator(string _message)
{
string _codedMessage = _message.Insert(0, ">>" + Convert.ToChar(0x1D));
_codedMessage = _codedMessage.Replace(Convert.ToChar(0x20), Convert.ToChar(0x1D));
return _codedMessage;
}
private static NoticeManager instance = null;
public static NoticeManager Instance { get { if (instance == null) instance = new NoticeManager(); return instance; } set { } }
}
}
DATABASE: The notice table was completely rebuilt
notice tables has 3 rows; id, message, active. id is a tinyint, message is a string and active is another tinyint. I uploaded an SQL dump
Maximum team difference to start a room rebuilt. Now you can configure it easily from the INI files.
CodeDragon, if you ever read this, I´m very curious about the code you used to calculate the team difference (powering and then square rooting to get the original team difference).
These modifications also allow you to configure the bomb time from the INI files too.
AlterEmu\Game\Config.cs
Code:
using Core.IO;
using System;
namespace Game {
class Config {
public static string AUTH_SERVER_IP = "127.0.0.1";
public static byte SERVER_ID = 0;
public static string SERVER_KEY = "SERVER-KEY";
public static string SERVER_NAME = "AlterEmu";
public static string SERVER_IP = "";
public static int MAXIMUM_ROOM_COUNT = 5;
public static short MAXIMUM_TEAM_DIFFERENCE = 1;
public static double EXPRATE = 1.0;
public static double DINARRATE = 1.0;
public static uint LEVEL_UP_MONEY_REWARD = 25000u;
public static string[] GAME_DATABASE;
public static long BOMBTIME = 45000;
public static bool Read()
{
INIFile configFile = new INIFile("config");
bool result = false;
if (configFile.Exists())
{
AUTH_SERVER_IP = configFile.Read("auth-server", "ip");
SERVER_KEY = configFile.Read("auth-server", "key");
SERVER_NAME = configFile.Read("server", "name");
SERVER_IP = configFile.Read("server", "bindip");
//Game configuration
string _expRate = configFile.Read("game-configuration", "exprate");
string _dinarRate = configFile.Read("game-configuration", "dinarrate");
string _bombTime = configFile.Read("game-configuration", "bombtime");
string _maximumTeamDifference = configFile.Read("game-configuration", "team_difference");
double.TryParse(_expRate, out EXPRATE);
double.TryParse(_dinarRate, out DINARRATE);
long.TryParse(_bombTime, out BOMBTIME);
Int16.TryParse(_maximumTeamDifference, out MAXIMUM_TEAM_DIFFERENCE);
if (EXPRATE == 0 || DINARRATE == 0)
{
Log.Instance.WriteError("Exprate or dinarrate values are 0 or not a number " + _expRate + "/" + _dinarRate);
Log.Instance.WriteError("Using default values");
EXPRATE = 1.0;
DINARRATE = 1.0;
}
else
{
//Just in case some dumbass tries to put a negative number
EXPRATE = Math.Abs(EXPRATE);
DINARRATE = Math.Abs(DINARRATE);
}
if (BOMBTIME == 0)
{
Log.Instance.WriteError("Invalid bomb time or the time is 0 " + _bombTime);
Log.Instance.WriteError("Using default value");
BOMBTIME = 45000;
}
else
BOMBTIME = Math.Abs(BOMBTIME); //Trolling is not allowed ;)
if (MAXIMUM_TEAM_DIFFERENCE == 0)
{
Log.Instance.WriteError("Invalid team difference or team difference is 0 " + _maximumTeamDifference);
Log.Instance.WriteError("Using default value");
MAXIMUM_TEAM_DIFFERENCE = 1;
}
else
MAXIMUM_TEAM_DIFFERENCE = Math.Abs(MAXIMUM_TEAM_DIFFERENCE);
GAME_DATABASE = new string[]
{
configFile.Read("game-database", "host"),
configFile.Read("game-database", "port"),
configFile.Read("game-database", "username"),
configFile.Read("game-database", "password"),
configFile.Read("game-database", "database")
};
result = true;
}
return result;
}
}
}
AlterEmu\Game\Handlers\Game\Lobby\Start.cs
Code:
using System;
using System.Linq;
using Game.Enums;
using Game.Managers;
namespace Game.Handlers.Game {
class Start : Networking.GameDataHandler {
protected override void Handle() {
if (Room.Master == Player.Id) {
if (Room.State == Enums.RoomState.Waiting) {
lock (Room._playerLock) {
if (Room.Players.All(p => p.Value.Ready)) {
var debTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.Derbaran).Count();
var niuTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.NIU).Count();
/* int diff = (int)Math.Sqrt(Math.Pow(debTeam - niuTeam, 2));
//Codedragon method: 1. debTeam - niuTeam
// 2. difference^2
// 3. Square root of 2
// The result is the same of debTeam - niu Team
// Was it a check?????
if (Config.MAXIMUM_TEAM_DIFFERENCE >= diff) {
respond = updateLobby = true;
type = Enums.GameSubs.StartReply;
Room.State = Enums.RoomState.Playing;
Set(2, Room.Map);
Room.Start();
}
*/
//DarkRaptor Method: In WarRock you can always start a room if player difference is 1, BUT only if you aren´t alone!!!
int _curTeamDifference = debTeam - niuTeam;
if(_curTeamDifference <= Config.MAXIMUM_TEAM_DIFFERENCE && (debTeam > 0) && (niuTeam > 0))
{
respond = updateLobby = true;
type = Enums.GameSubs.StartReply;
Room.State = Enums.RoomState.Playing;
Set(2, Room.Map);
Room.Start();
}
else
{
string _message = "You need more players to start this room";
Core.Networking.OutPacket NeedMorePlayers = new Packets.Chat("SYSTEM", ChatType.Room_ToAll,NoticeManager.MessageTranslator(_message), 999, "NULL");
Room.Send(NeedMorePlayers.BuildEncrypted());
}
}
}
}
} else {
Player.User.Disconnect(); // Cheating? - Not a master!
}
}
}
}
I´m currently working on the chat system. Whispering is not coded and also the variable targetId is overflowed when someone tries to whisp. That´s due to the packet sending a negative value for targetId (targetId is a simple, unsigned byte).
Sorry for double-posting but I´ve made a lot of changes to the code and I felt like a post was needed after 2 weeks.
First of all I´M VERY SORRY, the NOTICE MANAGER WAS BUGGY. I just fixed it. The format of the messages sent were wrong and the data management was a disaster.
FIXED NOTICE MANAGER:
AlterEmu\Game\Managers\NoticeManager.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using Game.Enums;
using Game.Networking;
using MySql.Data.MySqlClient;
namespace Game.Managers
{
class NoticeManager
{
List<string> ActiveNotices = new List<string>();
public NoticeManager()
{
}
public bool Load()
{
MySqlCommand cmd = new MySqlCommand("SELECT * FROM notices", Databases.Game.connection);
MySqlDataReader Reader = cmd.ExecuteReader();
int _inactiveNotices = 0;
if(Reader.HasRows)
{
while(Reader.Read())
{
byte _id = Reader.GetByte("id");
string _message = Reader.GetString("message");
byte _active = Reader.GetByte("active");
if(_active == 1)
{
ActiveNotices.Add(_message);
}
else
_inactiveNotices++;
}
Log.Instance.WriteLine("Notice manager found " + ActiveNotices.Count.ToString() + " active notices");
Reader.Close();
if(ActiveNotices.Count > 0)
{
System.Timers.Timer Timer = new System.Timers.Timer();
Timer.Enabled = true;
Timer.Interval = 60000;
Timer.Elapsed += (sender, e) => NoticeLoop(sender, e, ActiveNotices);
}
}
else
{
Reader.Close();
Log.Instance.WriteError("Notice manager couldn´t parse the notice table");
return false;
}
return true;
}
private static void NoticeLoop(object sender, ElapsedEventArgs e, List<string> messages)
{
Random Random = new Random();
int _index = Random.Next(0, messages.Count());
string _message = MessageTranslator("Notice: " + messages[_index]);
Core.Networking.OutPacket Notice = new Packets.Chat("Server", ChatType.Notice2, _message, 100, "NULL");
Managers.ChannelManager.Instance.SendAllLobbies(Notice.BuildEncrypted());
}
public static string MessageTranslator(string _message)
{
string _codedMessage = _message.Insert(0, ">>" + Convert.ToChar(0x1D));
_codedMessage = _codedMessage.Replace(Convert.ToChar(0x20), Convert.ToChar(0x1D));
return _codedMessage;
}
private static NoticeManager instance = null;
public static NoticeManager Instance { get { if (instance == null) instance = new NoticeManager(); return instance; } set { } }
}
}
DATABASE: The notice table was completely rebuilt
notice tables has 3 rows; id, message, active. id is a tinyint, message is a string and active is another tinyint. I uploaded an SQL dump
Maximum team difference to start a room rebuilt. Now you can configure it easily from the INI files.
CodeDragon, if you ever read this, I´m very curious about the code you used to calculate the team difference (powering and then square rooting to get the original team difference).
These modifications also allow you to configure the bomb time from the INI files too.
AlterEmu\Game\Config.cs
Code:
using Core.IO;
using System;
namespace Game {
class Config {
public static string AUTH_SERVER_IP = "127.0.0.1";
public static byte SERVER_ID = 0;
public static string SERVER_KEY = "SERVER-KEY";
public static string SERVER_NAME = "AlterEmu";
public static string SERVER_IP = "";
public static int MAXIMUM_ROOM_COUNT = 5;
public static short MAXIMUM_TEAM_DIFFERENCE = 1;
public static double EXPRATE = 1.0;
public static double DINARRATE = 1.0;
public static uint LEVEL_UP_MONEY_REWARD = 25000u;
public static string[] GAME_DATABASE;
public static long BOMBTIME = 45000;
public static bool Read()
{
INIFile configFile = new INIFile("config");
bool result = false;
if (configFile.Exists())
{
AUTH_SERVER_IP = configFile.Read("auth-server", "ip");
SERVER_KEY = configFile.Read("auth-server", "key");
SERVER_NAME = configFile.Read("server", "name");
SERVER_IP = configFile.Read("server", "bindip");
//Game configuration
string _expRate = configFile.Read("game-configuration", "exprate");
string _dinarRate = configFile.Read("game-configuration", "dinarrate");
string _bombTime = configFile.Read("game-configuration", "bombtime");
string _maximumTeamDifference = configFile.Read("game-configuration", "team_difference");
double.TryParse(_expRate, out EXPRATE);
double.TryParse(_dinarRate, out DINARRATE);
long.TryParse(_bombTime, out BOMBTIME);
Int16.TryParse(_maximumTeamDifference, out MAXIMUM_TEAM_DIFFERENCE);
if (EXPRATE == 0 || DINARRATE == 0)
{
Log.Instance.WriteError("Exprate or dinarrate values are 0 or not a number " + _expRate + "/" + _dinarRate);
Log.Instance.WriteError("Using default values");
EXPRATE = 1.0;
DINARRATE = 1.0;
}
else
{
//Just in case some dumbass tries to put a negative number
EXPRATE = Math.Abs(EXPRATE);
DINARRATE = Math.Abs(DINARRATE);
}
if (BOMBTIME == 0)
{
Log.Instance.WriteError("Invalid bomb time or the time is 0 " + _bombTime);
Log.Instance.WriteError("Using default value");
BOMBTIME = 45000;
}
else
BOMBTIME = Math.Abs(BOMBTIME); //Trolling is not allowed ;)
if (MAXIMUM_TEAM_DIFFERENCE == 0)
{
Log.Instance.WriteError("Invalid team difference or team difference is 0 " + _maximumTeamDifference);
Log.Instance.WriteError("Using default value");
MAXIMUM_TEAM_DIFFERENCE = 1;
}
else
MAXIMUM_TEAM_DIFFERENCE = Math.Abs(MAXIMUM_TEAM_DIFFERENCE);
GAME_DATABASE = new string[]
{
configFile.Read("game-database", "host"),
configFile.Read("game-database", "port"),
configFile.Read("game-database", "username"),
configFile.Read("game-database", "password"),
configFile.Read("game-database", "database")
};
result = true;
}
return result;
}
}
}
AlterEmu\Game\Handlers\Game\Lobby\Start.cs
Code:
using System;
using System.Linq;
using Game.Enums;
using Game.Managers;
namespace Game.Handlers.Game {
class Start : Networking.GameDataHandler {
protected override void Handle() {
if (Room.Master == Player.Id) {
if (Room.State == Enums.RoomState.Waiting) {
lock (Room._playerLock) {
if (Room.Players.All(p => p.Value.Ready)) {
var debTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.Derbaran).Count();
var niuTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.NIU).Count();
/* int diff = (int)Math.Sqrt(Math.Pow(debTeam - niuTeam, 2));
//Codedragon method: 1. debTeam - niuTeam
// 2. difference^2
// 3. Square root of 2
// The result is the same of debTeam - niu Team
// Was it a check?????
if (Config.MAXIMUM_TEAM_DIFFERENCE >= diff) {
respond = updateLobby = true;
type = Enums.GameSubs.StartReply;
Room.State = Enums.RoomState.Playing;
Set(2, Room.Map);
Room.Start();
}
*/
//DarkRaptor Method: In WarRock you can always start a room if player difference is 1, BUT only if you aren´t alone!!!
int _curTeamDifference = debTeam - niuTeam;
if(_curTeamDifference <= Config.MAXIMUM_TEAM_DIFFERENCE && (debTeam > 0) && (niuTeam > 0))
{
respond = updateLobby = true;
type = Enums.GameSubs.StartReply;
Room.State = Enums.RoomState.Playing;
Set(2, Room.Map);
Room.Start();
}
else
{
string _message = "You need more players to start this room";
Core.Networking.OutPacket NeedMorePlayers = new Packets.Chat("SYSTEM", ChatType.Room_ToAll,NoticeManager.MessageTranslator(_message), 999, "NULL");
Room.Send(NeedMorePlayers.BuildEncrypted());
}
}
}
}
} else {
Player.User.Disconnect(); // Cheating? - Not a master!
}
}
}
}
*
* Alter EMU - Written By CodeDragon
*
* Emulator Verion: 5
* Credits:
* - CodeDragon
* - Basser
*
* Special Thanks:
* - ToXiiC
*
*/
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Core.Networking;
using Core.Enums;
using Game.Networking;
namespace Game
{
class Program
{
private static bool isRunning = false;
public static ServerClient AuthServer;
static void Main(string[] args)
{
Console.Title = "AlterEmu - [Starting] Game Server";
Console.WindowWidth = Console.LargestWindowWidth - 25;
Console.WindowHeight = Console.LargestWindowHeight - 25;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(@" _______ _______ _______ ______ _______ _______ _ _");
Console.WriteLine(@" |_____| | | |______ |_____/ |______ | | | | |");
Console.WriteLine(@" | | |_____ | |______ | \_ |______ | | | |_____|");
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(new string('_', Console.WindowWidth));
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Modded by DarkRaptor");
Console.ForegroundColor = ConsoleColor.Gray;
if (!Config.Read())
{
Log.Instance.WriteError("Failed to load the configuration file.");
Console.ReadKey();
return;
}
if (!Databases.Init())
{
Log.Instance.WriteError("Failed to initilize all database connections.");
Console.ReadKey();
return;
}
if (!Managers.ItemManager.Instance.Load())
{
Log.Instance.WriteError("Failed to initilize the item manager.");
Console.ReadKey();
return;
}
if (!Managers.MapManager.Instance.Load())
{
Log.Instance.WriteError("Failed to initilize the map manager.");
Console.ReadKey();
return;
}
//DarkRaptor Notice Manager
if(!Managers.NoticeManager.Instance.Load())
{
Log.Instance.WriteError("Failed to initialize the notice manager.");
Console.ReadKey();
return;
}
// CONNECT TO THE AUTHORIZATION SERVER //
AuthServer = new ServerClient(Config.AUTH_SERVER_IP, (int)Ports.Internal);
if (!AuthServer.Connect())
{
return;
}
if (!new UDPListener((int)Ports.UDP1).Start())
{
return;
}
if (!new UDPListener((int)Ports.UDP2).Start())
{
return;
}
//Configuration reminder (in case everything is well configured)
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Dinar rate is: " + Config.DINARRATE.ToString());
Console.WriteLine("EXP rate is: " + Config.EXPRATE.ToString());
Console.WriteLine("Bomb time is " + Config.BOMBTIME.ToString());
Console.WriteLine("Maximum team difference is " + Config.MAXIMUM_TEAM_DIFFERENCE.ToString());
Console.ForegroundColor = ConsoleColor.Gray;
// Start up the listener :)
isRunning = (new ServerListener((int)Ports.Game)).Start();
while (isRunning)
{
Parallel.ForEach(Managers.UserManager.Instance.Sessions.Values, user =>
{
if (user.Authorized)
user.SendPing();
});
Console.Title = "AlterEmu - Game Server - Players online: " + Managers.UserManager.Instance.Sessions.Values.Count;
Thread.Sleep(5000);
}
}
}
}
I´m currently working on the chat system. Whispering is not coded and also the variable targetId is overflowed when someone tries to whisp. That´s due to the packet sending a negative value for targetId (targetId is a simple, unsigned uint).
The reason why I took the power and then used a square root in the check was because to neutralize a negative value. Example: if there are no players on the deb team and 2 players on the NIU then the result would be -2, a normal human would know that the difference is 2. Your broke the code by removing that part by the way. You don't need to do it the very complicated way like I did. You can just grab the absolute value with Math.Abs().
Code:
int teamDifference = Math.Abs(debTeam - niuTeam);
Then replace this line:
Code:
if (Config.MAXIMUM_TEAM_DIFFERENCE >= diff) {
With this:
Code:
if (teamDifference <= Config.MAXIMUM_TEAM_DIFFERENCE) {
This would make it work correctly plus make it configurable.
Doh, Silly me. I didn´t thought of negatives values. Updated.
EDIT: I´m seriously considering stopping this project. None but CodeDragon and me has contributed to it, but I´ve received a lot of PMs asking about setting up a server using these files. None read the first post, where I clearly SAY: THESE FILES ARE NOT STABLE blablabla.
So, in the end, a lot of leechers but 0 contributions. It takes a lot of time to explain my changes file by file but people keep scrolling down to the latest upload.
Since none has contributed but CodeDragon and it takes a lot of time to explain and update my changes, I have decided to stop posting fixes. I still work on this release and I will post it one I finish it (everything but the userlist packet, sorry. It is private), but I wont update this post with code, only screenshots.
What I added so far:
* Improved the healing system. Now its fully funcional.
* Improved the player damage calculations to be more like the vanilla game. Headshot detected properly.
* Added Team Death Match to CQC and UO/BG.
* Added Conquest.
* Flags are working.
* Ammo recharge works.
* You can place any item on the ground and use it (TMA has to be debugged)
* The launcher packet is now configurable. So you can update the client easily.
* Level check for the Itemshop added.
* Level check for joining a room added.
* Fixed notice manager
* Added some config parameters: bombTime, dinar and exp rate, maximum team difference
* Added the classic coupon system. You can add new codes in the database.
* Added some missing packets: death confirmed, logout packet.
Im working on vehicles a.t.m. Once I finish them Ill move to clan system and then I will fix a couple of bugs in CQC and some bugs about the lobby update. The last step will consist on more security checks and optimization.
Why Darkraptor, no stoped this proyect is the best, my Clan alwais check you proyect to found bug and help you in this proyect.no lisend the leechers, the are boy wich -15 yeard old. my clan wich 23 player alwais help you. we know that is not much test the server and find bug but if you know another task on the server in which we can help tell me
Why Darkraptor, no stoped this proyect is the best, my Clan alwais check you proyect to found bug and help you in this proyect.no lisend the leechers, the are boy wich -15 yeard old. my clan wich 23 player alwais help you. we know that is not much test the server and find bug but if you know another task on the server in which we can help tell me
I don know what you mean since I never created a test server. I believe you wanted to say that you downloaded the sources and tested them with your clan, which is ok, but I see no reports here, so its kind of useless for me.
Please, read again. I still work on this release but I wont post more code nor explain what I changed since none cares but CodeDragon. Once I finish I will release everything except the userlist packet and handler. But as I said, no more code explanations, no more long posts with detailed spoilers. It takes a lot of time not only to post my changes, but to update them everytime I find a bug which I didn notice before and Its not worth it since I see no contributions.
What I really need (and I believe this section needs too) is real contributions, and more developers. Leechers and testers are fine, but without contributions (even if they are crappy like mine) there is no development.
There is something that beginners should know: if you arent capable of programming in your sources language, then you should start learning the programming lang. instead of creating a server. I started with C# 7 months ago and after many hours of practise I started to study CodeDragon sources to understand how WarRock works. This is the only path to have a real decent server. Programming skills + experience + deep understanding of the game mechanics.
Maybe one day someone will release a full emulator, good enough for someone without knowledge to start a server following a simple tutorial. But believe me, even then it will be difficult. Updating, adding new gamemodes, customizing the server... you need at least some knowledge.
And this is it for the offtopic, from now on stick to the topic please.
I'm updating my release so people have the latest fixed version available.
I'll add you do the thank you list for finding these bugs and making an attempt to fix them.
[DB] the levels_gained table has been modified: Now it has 5 rows: id, game_id, current_level, levels_gained, timestamp.
ID is an int type row. game_id has been changed from int to Text. Now the log works like this: id (player id matching the DB index), game_id (nickname of the player, can be changed to use user id lol), current_level (player´s level), levels_gained (number of levels gained during the level up, most times 1), timestamp (date in unix format).
* Fixed a bug in the level up event. The player could lose the money earned if he logged out the game without buying anything (anything that updated the DB info, to be more accurate).
I've managed to fix this bug correctly I messed the columns up, and the id in the database. I had a duplicate line, the second user_id should be re-named to game_id since I was implementing it based on each game. Anyways, here is the correct code
Also make sure you run this MySQL database command to fix the table!
Code:
DROP TABLE IF EXISTS `game_levels_gained`;
CREATE TABLE IF NOT EXISTS `game_levels_gained` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`game_id` int(10) unsigned NOT NULL,
`current_level` tinyint(3) unsigned NOT NULL,
`levels_gained` tinyint(3) unsigned NOT NULL,
`timestamp` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
I also updated the experience & dinar rate system you've written, I removed the math.abs and replaced the values with the default(1.0). I also re-wrote the error message that displays if the rates are configured wrongly.
Code:
// Experience & Dinar rates
string _expRate = configFile.Read("game-configuration", "exprate");
string _dinarRate = configFile.Read("game-configuration", "dinarrate");
double.TryParse(_expRate, out EXP_RATE);
double.TryParse(_dinarRate, out DINAR_RATE);
if (EXP_RATE <= 0 || DINAR_RATE <= 0)
{
Log.Instance.WriteError("One of the experience or dinar rates has been configured in a wrong way " + _expRate + "/" + _dinarRate);
Log.Instance.WriteError("Setting the wrong configured rate(s) to the default state.");
if (EXP_RATE <= 0)
EXP_RATE = 1.0;
if (DINAR_RATE <= 0)
DINAR_RATE = 1.0;
}
I also updated my code for team starting, it now load the maximum team difference from the config file.
Thanks you very much for updating the server and my "fixes". I have improved a lot during my experience with your files, but some of the earliest fixes can be improved due to my poor understanding of your files. Ill be updating the post once I finish testing extensively my own files to make sure Im not releasing shenanigans.
Actually I´m rewritting most of them because when I started fixing CodeDragon´s release I wasn´t as skilled as I am now. I should be posting some updates in a month or so after further testing.
Actually I´m rewriting most of them because when I started fixing CodeDragon´s release I wasn´t as skilled as I am now. I should be posting some updates in a month or so after further testing.
Not a "big" release but I found a little bug in Entities\Room.cs
Code:
for (byte i = 0; i < 0; i++)
Flags[i] = -1;
Don´t ask me why because I didn´t went into it too much, but this line is setting Flag[0] to 0 and basically breaking the clean and intelligent Flag system and therefore bugging any FlagCapture handler you code. Every flag must be -1 but the spawn flags, whose states are 0 and 1 depending on the owner.
To fix it, just change it to:
Code:
for (byte i = 0; i < flagCount; i++)
Flags[i] = -1;
this is my handler for FlagCapture.cs. If you are smart enough to code Team DeathMatch, I´m sure you´ll find this useful. If you are not, then wait for me to release it:
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using Game.Enums;
namespace Game.Handlers.Game.Ingame
{
sealed class FlagCapture : Networking.GameDataHandler
{
protected override void Handle()
{
if (Room.State == RoomState.Playing && (Room.Channel == ChannelType.Urban_Ops || Room.Channel == ChannelType.Battle_Group))
{
if (!Player.IsAlive || Player.Team == Team.None)
return;
//Flag information: 0 DERB, 1 NIU, -1 WHITE
//TODO BUILD ENUMERATION FOR THIS :D :D :D
byte _capturedFlagId = GetByte(2);
Objects.Map CurrentMap = Managers.MapManager.Instance.Get(Room.Map);
if (CurrentMap == null || CurrentMap.SpawnFlags.Contains(_capturedFlagId)) //do not rely on Room.Flag (0-1) to determine the spawn flag...CONQUEST!
return;
if (Room.Flags[_capturedFlagId] == -1) //neutral flag
Room.Flags[_capturedFlagId] = (sbyte)Player.Team;
else
Room.Flags[_capturedFlagId] = -1;
Set(2, _capturedFlagId);
Set(3, Room.Flags[_capturedFlagId]);
respond = true;
Player.AddFlags();
//Calls the event to update gamemode
Room.CurrentGameMode.OnFlagCapture(Player);
}
else
Player.User.Disconnect(); //cheating
}
}
}
This is only a snippet. For the handler to work you need to make some changes to GameModes.cs and Player.cs. It´s pretty easy, though.