CONTENTS OF THREAD:
-
saving/loading/updating databases using SQL
-
-
(By Yashi)
-
(By Grasshoppa)
-
-
-
So I figured I'd post some basic guides and tutorials for coding. These are NOT source dependent. You will simply need to understand how to modify the codes.
Nothing in here is a working feature, when I use things like Pk events as an example I have NOT posted full working codes to add a pk event to your server. I'm giving you examples of how to program parts of these events yourself.
These are all intended as basic conceptual help for coding. If I made a mistake in my explanations, please let me know (flame if you want, I'm far from sensitive lol). I am by no means an expert coder and especially not so at C#. I am working with the 1.0 source simply because it's what has been interesting me lately, feel free to apply these theories to sources you use though.
That being said, enjoy.
If you have any requests for advice (again, NOT FULL CODES) let me know
If I got something wrong, please let me know and I'll fix it (and give credit obviously)
Note: this thread will be updated in time. These are just some basic things I had time to write up right now.
How to do something to/retrieve all online players [CoFuture: 4267 source]
Finding online players can be useful for all sorts of things, random events, pk wars, finding number of players online and countless other things. Here is a brief explanation of how to go about it.
*Note* These structures will work for all sorts of sources, you just need to know how to modify it.
Code:
Start.Clients
Start.Clients can be used in a number of ways such as to find out how many players are online (Start.Clients.Count). Perhaps the most useful way to apply this though is to use of "foreach".
foreach means exactly what it says. The loop occurs once for each item in the structure (in this case a Dictionary named Clients)
foreach (KeyValuePair<uint, COClient> Player in Start.Clients)
{
if (Player.Value.Char.Map == 1507)//if CURRENT player is on map # 1507 (bird island pk map)
{
Start.PkEventPlayers.Add(Player.Value.Char.ID, 0);// this will add the CURRENT player Id to the Dictionary PkEventPlayers (you would have to code this yourself)
Player.Value.Char.CharPkEvent = true;//sets bool CharPkEvent for CURRENT character to true
Player.Value.Char.CanKillPkWar = true;// sets bool CanKillPkWar for CURRENT character to true
Client.SendData(ConquerPacket.Message(0, "SYSTEM", Player.Value.Char.Name, "[PkWar] The pk war has started!!.", Struct.ChatType.Top));// Displays that the pk war has started
}
else//if player is NOT on that pk map
{
Player.Value.Char.CharPkEvent = false;//they are not in the pk event
Player.Value.Char.CanKillPkWar = false;// they can't pk in that event even if they got to the map
Client.SendData(ConquerPacket.Message(0, "SYSTEM", Player.Value.Char.Name, "[PkWar] Pk war has started without you!.", Struct.ChatType.Top));//Displays to players who are not in the war that they have not joined the war (they missed out)
}
}
Hopefully that will help you understand how to do that a little bit better. To do it in other sources should function exactly the same! You will just need to modify the variable names.
Intro to hashtables: (Just starting to learn these myself so bear with me)
Hashtables can be thought of a bit like an in-source database. They are data structures that are intended to map keys (player name for example) to certain values (player score in an event)
To make a new hashtable all you have to do [CoFuture: 4267 source, should be identical in others though] is place something like this in the Start.cs file (will differ with other sources)
{
if (Start.PkWarScore.Contains(Client.Char.Name))//If the player is already in the hashtable
{
Start.PkWarScore[Client.Char.Name] = (int)Start.PkWarScore[Client.Char.Name] + 1;//add one to their existing score
Client.SendData(ConquerPacket.Message(0, "SYSTEM", Client.Char.Name, "[PkWar] You have gained a kill!", Struct.ChatType.Top));//tell the player they gained a kill
}
else//if player is not in the existing hashtable
{
Start.PkWarScore.Add(Client.Char.Name, 1);//add them to the table and set their score to 1
Client.SendData(ConquerPacket.Message(0, "SYSTEM", Client.Char.Name, "[PkWar] You have gotten your first kill!", Struct.ChatType.Top));//tell the player they gained their first kill of the event.
}
}
To reiterate: When using hashtables you have multiple ways to modify things.
Add (adds a new item to a hashtable)
Clear (clears/wipes entire hashtable)
Contains (checks if hashtable contains something)
Remove (Removes/clears a specific entry to a hashtable)
PkWarScore[Client.Char.Name] (updates an existing entry for lack of a better explanation. Just look at the code. It will help you more.)
So for example to clear an entire hashtable (event is over for example) just do
Start.PkWarScore.Clear
If there are any further questions on the basics behind hashtables please let me know, bearing in mind that I am just picking up some of this stuff myself still.
Writing your own commands and Database functions (Thanks for correcting my old terminology Basser)
A very useful thing when adding new features, is having the ability to create new databases and modify existing ones
eg: adding composition co CoEmu you have to modify the Items database to have a field for progress. You then need to modify all the item related database functions in the source to understand what progress is and where/how to insert it into the database. If you were not able to do that you wouldn't be able to add, load or remove items from the database and have them with progress/composition.
On the flip side of adding Databases, a very useful feature for any beta server is the ability to quickly test new features in a controlled manner. This is an area where adding custom commands comes in very handy.
For this example I will explain how to add a quest to a new database (You would obviously have to create the database first) and add data to it using a gm command (npcs will function the exact same way but by doing it through a command we will get much better instant, customizable feedback.
NOTE: THIS IS COFUTURE: 4267 SOURCE. Other sources will need to convert the code to make it work the same BUT! The coding examples are still valid, this is THEORY, not copy/paste scripts.
When first looking at this, it will look like a complete bitch (unless you already have some idea what you are doing with sql and database functions, in which case you have no point reading this most likely ^^).
To start we will focus on the void.
The function simply states what the command name is, and the parameters it requires to function (input)
public static means it can be accessed from anywhere in the source and is not instanced (no 'new' or '.this' + other changes... you want most of your functions to be static)
the data inside the brackets are the parameters. For a more simple example that you may be able to relate to lets write a small function (which is essentially what this is, again terminology differs between programing language but w/e!) to divide numbers.
Code:
public static void DivideXByY(double x, double y)
{
double z = x / y;
Console.WriteLine(" X divided by Y = " + z);
}
Can you understand how this tiny section of code works? It's quite simple really.
DivideXByY involves 2 inputs (x and y) which are both int (full numbers, no decimals)
z = x / y
simply sets variable z = to x divided by y (again, obvious, just stating it for people)
Console.WriteLine("text" + z); writes text to the console (game server window) saying "text *valueofz*"
This function can be called now from anywhere in the source (because we made it public!)
Seeing as in our example it's within the Database class, you would simply write
Database.DivideXByY(10, 2);
this would print out to the game server console " X divided by Y = 5" because 10 / 2 = 5
KEEP IN MIND YOU CAN STILL USE RETURN TYPES!
eg: instead of void make it double and then just do return (x/y);. Then you can do something like
Console.WriteLine("X divided by Y = "+ Database.DivideXByY(10,2));
>Jump Back< Ok: now that I've done my super basic explanation of voids/functions I'll go back to the AddQuest example.
Means it is going to Insert (add) into Quests (database name)
('DatabaseColumn1', 'DatabaseColumn 2', .......)
values (what to insert into the previous fields. They fit together so first database column = first entry into values)
then it builds the string of what it is trying to insert. THESE ARE LOADED FROM THE FUNCTION ITSELF. Notice that wherever the type of data was a string (text) it is surrounded by ' '. This is REQUIRED for Mysql to view it as a string. if not it will throw an exception (we will get to exceptions later)
I know this explanation of mysql wasn't perfect but I'm tired and it's always a ugly mess whenever I look at sql. If anyone has a description of Sql queries that is more legible, go for it.
NOTE: Using immune's sexy mysql wrapper is strongly suggested. It simplifies the use of database functions and makes everything far more efficient and reduces the chance of you doing something stupid which may crash sql.
Adding commands
Very useful for testing database functions, you get to see if there are all sorts of lovely errors!
As with the last SQL statement, I'll post the fully functioning command that I wrote to go along with it and then break it down into more simple stages after that.
if (Splitter[0] == "/quest")
{
try
{
Database.AddQuest(Client.Char.ID, Client.Char.Name, Convert.ToInt32(Splitter[1]), Convert.ToString(Splitter[2]), Convert.ToInt32(Splitter[3]), Convert.ToInt32(Splitter[4]));
}
catch
{
Client.SendData(ConquerPacket.Message(0, "SYSTEM", Client.Char.Name, " Invalid formating, should be /Quest int string int int", Struct.ChatType.Top));
}
return 2;
}
Now first of all notice the 'try' and 'catch'. Those will be your new best friend when FINALIZING new features. It keeps major errors from popping up. The downside to that is that if you are initially testing something you may WANT those nasty error messages (in his case if it was invalid input or not working correctly it would give you a Mysql error with a bit of data concerning what was wrong. This can help you fix things!)
How try/catch works:
When you write a program and tell it to do something such as converting between data types (int, float, string), the program will take your word ass god and not check for errors. If you mess something up it can crash the entire program or at the very least print out a very unfriendly error message. When dealing with user input especially (yay input fields and player commands!!!!), we want to be able to check for validity and if something goes wrong, provide a more user friendly feedback.
[code]
try
{
//code
}[/quote]
Does exactly what it says, it TRIES to do what code you have entered.
catch
{
//nice friendly error msg or other code
}
Does exactly what it says also. Catch will only run if try ran into an exception (error) and could not complete its code. Instead the program will jump to the catch section of code and execute it in its place.
>Jump< Back into the topic of this command. (re-pasting in spoiler for reference)
if (Splitter[0] == "/quest")
{
try//attempts to take the user input from the command, convert it to acceptable types to be entered into the database and then invokes the AddQuest code that we looked at earlier. This code fills in the fields as explained below
{
Database.AddQuest(Client.Char.ID, Client.Char.Name, Convert.ToInt32(Splitter[1]), Convert.ToString(Splitter[2]), Convert.ToInt32(Splitter[3]), Convert.ToInt32(Splitter[4]));
//explanation of how it fills in the database
//Our table is structured as followed
//CharacterId, CharacterName, QuestId, QuestName, QuestStage, QuestCompletion
//CharacterId = id of character who used the command (found through Client.Char.ID)
//CharacterName = name of character who use the command (found through Client.Char.Name)
//QuestId = the first thing entered in the chat after /quest (/quest 1 means quest id = 1)
// QuestName = the second thing entered in the chat after /quest (/quest 1 TestQuestName means the quest name = TestQuestName)
// QuestStage = third thing entered in the chat after /quest
//QuestCompletion = fourth thing entered in the chat after /quest
}
catch//code is invoked if there is an error completing top code. Most likely due to the player formatting the command wrong
{
Client.SendData(ConquerPacket.Message(0, "SYSTEM", Client.Char.Name, " Invalid formating, should be /Quest int string int int", Struct.ChatType.Top));
//prints out a more helpful error msg to player saying how the cmd needs to be formatted.
}
return 2;
}
To recap: When looking at creating new player commands you use [number] to determine position in the player chat.
For use in our database these need to be converted to the correct type. This can be done through Convert.Totype(data)
I should take a break because I think I'm becoming less and less understandable. Hope this helps people but again if you have a question/error to point out/request. Lemme know!
<edit>
Slightly updated thanks to Basser pointing out some of my very poor knowledge of terminology. I did write this many months ago but it really is laughable how poor most of my terminology was. I've updated a few sections of it but I'm not going to re-write the entire post right now. Basically take it as is but don't limit yourself to this knowledge. These are meant as examples + explanation of them more than an actual "tutorial" on how to add something. When I write these I intend to simply draw attention to some certain tools that C# has and then demonstrate how to use them in a very basic way. Where you go from there is up to you. I strongly recommend a quick google of them and then attempt using them yourself in some different ways so that you are comfortable with them down the line.
Now some more basic stuff for people just getting into Servers: Seeing as the bulk of people are using CoEmu I'll do this one on the base CoEmu source.
Npc Coding:
Npcs in CoEmu are rather easy to code but alot of newcomers can find them intimidating. I'll try to break down exactly how they can be coded (this is less theory and more structure for people who don't know what they are doing)
In CoEmu, npc codes can be found under GameServer>Handlers>NpcTalk.cs
The first thing you should know about NPC coding is how to determine which script goes to which npc.
case 45: // Mark. Controller
{
if(LinkBack == 0)
{
Text("Hello I can teleport You outside of the market for free! Do you want to leave?", CSocket);
Link("Why would you be so kind to do so?", 1, CSocket);
Link("No, Thank you anyway.", 255, CSocket);
End(CSocket);
}
else if(LinkBack == 1)
{
Teleport(1002, 439, 390, 0, CSocket);
}
break;
}
All codes start at LinkBack == 0 (this is the code that will pop up when you talk to an npc)
Lines of code consisting of: Text("", CSocket); are simply npc output (that is what the npc says)
Each line of Text creates a new line of text ingame, you can force a new line by typing \n in the npc text code
Text("This is a rather long string so lets break it up\n ooh look this is on a new line!", Csocket);
Lines of code consisting of Link("text", #, CSocket); are user options. 255 closes the dialogue, all other numbers go to the corresponding LinkBack number!
End(CSocket); ends the current section of code (required for each link back to avoid fucking up the script)
---------
Now that we've covered a little bit of how the npc scripts are laid out all that is left to do is checks.
The simplest check is using an if statement. If statements are true or false statements
Eg
if (x > 10)
{
//code
}
means if (x > 10) is true (if x = 1, it is not > 10 so it is false. The statement is therefor not activated)
You can apply this to npc scripts by checking player levels, cash, job or any other character stat.
Lets write a little script that will tell the player their job, level and current map and charge them 1000 gold to do it (hehehe, pointless but a good code example)
Note: Not tested npc at all but should work fine. Besides its an EXAMPLE lol
case 390: // Useless test npc (USING SAME CASE AS LOVE STONE IN MARKET)
{
if (LinkBack == 0)//start section of code
{
Text("Hey! I can tell you your job, level and current map for only 1k gold!", CSocket);//simple text
Link("Wow that sounds so useful!", 1, CSocket);//goes to link back 1
Link("How pointless", 255, CSocket);//closes dialogue
End(CSocket);//required!!!
}
else if (LinkBack == 1)//the #1 option goes here because it is LinkBack 1!
{
if (CSocket.Client.Money >= 1000)//checks for money
{
CSocket.Client.Money -= 1000;//removes 1k gold, there is a better way to do this but seeing as it's base source I don't have time/energy to go through everything
Database.Database.SaveCharacter(CSocket.Client);//saves database, updates money
Text("You are Job #" + CSocket.Client.Class + " \nYou are level: " + CSocket.Client.Level + "\nYou are on map number: " + CSocket.Client.Map, CSocket);//prints out string, notice + combines things
Link("Wow! So useful! Thanks", 255, CSocket);
End(CSocket);
}
else//if player does not have 1k gold
{
Text("You lied! You don't even have 1k gold!", CSocket);//prints out msg
Link("Sorry!", 255, CSocket);//closes dialogue
End(CSocket);
}
}
break;
}
Please note that all voids and database sections can be used in these scripts. What you want your npc to do is completely up to you!
No time to write more right now, hopefully a super basic Npc guide helps some ppl. I may finish it later.
I saw hundred of people mistaking in the defining of things and not being able to fix simple errors for example:
public bool RebornCount = ""; WRONG
So in this guide i will explain HOW-TO define.
C# Type : Int(eger)
.Net Framework (System) Type : System.Int32
Possible values : -128 to 127
Used as in : int Money = 0;
Adding value as in : Money += 1;
Decreasing value as in : Money -= 1;
Decreasing value with the current value : Money -= Money;
Setting a absolute value: Money = 1;
How to know if something is an integer? :
For example if it adds a value in numbers like : Money += 100000; , Money -= 10000; Money = 10000; and if(Money ==/>/</! == 1300)
Why use an integer?: It stores much easier though it would be weird if you used a string basicly text to store numbers.
I'm too lazy to finish the rest off maybe if i came back from school tomorrow.
I saw hundred of people mistaking in the defining of things and not being able to fix simple errors for example:
public bool RebornCount = ""; WRONG
So in this guide i will explain HOW-TO define.
C# Type : Int(eger)
.Net Framework (System) Type : System.Int32
Possible values : -128 to 127
Used as in : int Money = 0;
Adding value as in : Money += 1;
Decreasing value as in : Money -= 1;
Decreasing value with the current value : Money -= Money;
Setting a absolute value: Money = 1;
How to know if something is an integer? :
For example if it adds a value in numbers like : Money += 100000; , Money -= 10000; Money = 10000; and if(Money ==/>/</! == 1300)
Why use an integer?: It stores much easier though it would be weird if you used a string basicly text to store numbers.
I'm too lazy to finish the rest off maybe if i came back from school tomorrow.
Ooh nice job, I didn't even think to go into definitions... I guess maybe it's just cause I've had to do it so much for other things that I don't even really think about having to declare what type of data they are holding....
Then again python has spoiled me because you don't have to define variables before use and it figures out what type of data it's holding all by itself.
Ooh nice job, I didn't even think to go into definitions... I guess maybe it's just cause I've had to do it so much for other things that I don't even really think about having to declare what type of data they are holding....
Then again python has spoiled me because you don't have to define variables before use and it figures out what type of data it's holding all by itself.
+T for being helpful
Python you do have to define them - it's just dynamically typed (well, it's pretty much the same thing, lol.)
Python you do have to define them - it's just dynamically typed (well, it's pretty much the same thing, lol.)
Python ftw?
Ahaha actually school has turned me off of python. I made the mistake of going into the advanced programing class w/o having any experience really other then some basic scripting and stuff...
Let's just say that didn't turn out well so I had to switch to the introductory one lol.
Spending like 8+ hours trying to write your FIRST assignment in like week 2.... not a fun experience. But yah, in general python is kinda nice.
This indicates "whether the Timer should raise the Elapsed
event each time the specified interval elapses or only after the first time it elapses."
That means if you want a recurring timer, leave this as true.
This indicates "the time, in milliseconds, between raisings of the Elapsed
event. The default is 100 milliseconds." You will almost certainly want to
make this interval longer than the default. For example, for 30 seconds,
use 30000 as the Interval.
This is the event that is invoked each time the Interval of the Timer
has passed. You must specify this function in your code. To add the event, you can
press tab twice after typing "_timer.Elapsed +=".
Process IE = new Process();
IE.StartInfo.FileName = "iexplorer.exe";
IE.StartInfo.Arguments = "http://www.google.com";
IE.Start();
Explaining them :
Next, we specifiy what program will be run. This could be done by assigning the program name to the FileName member of the IE's Process object's StartInfo property. For example:
The StartInfo property also has a member called Arguments, which is used to specify command-line options that are passed to the program. In the following example, the string "google.com" is passed as an argument, so IEX will know what url to open:
[Guide]cofuture source 06/11/2011 - CO2 PServer Guides & Releases - 91 Replies hi guys am new here and i hope stay here for long time
------------
i make this guide Couz i found alot pll cant work with cofuture source
---------------
Coder source:future <<<Thanks to hime 1st
helping me:haydeZ<<<<Thanks to hime 2nd
---------------------------------------
What we are need?
1:cofuture source>>>Download Here
2:AppServ(MySQL, Apache, and PhpMyAdmin all in one)>>>>AppServNetwork
Guide/Release: Conquer Server (CoFuture) Using MySql! 07/14/2010 - CO2 PServer Guides & Releases - 1162 Replies Hello Everyone, Im Future and im releaseing CoFuture aka CoFusion
This server was created by Korvacs & Myself (Future)
The server was created from scratch with the inspiration of CoEmu and also some help from the CoEmu source helping code & navigate through this project. The server was created in C# (C Sharp) and uses MySql.
Server Information:
- Server Name: CoFuture aka CoFusion
- Authors: Korvacs & Future
- Database Type: MySql
- Inspired By: CoEmu
Need help Guide/Release: Conquer Server (CoFuture) Using MySql! 05/28/2008 - Conquer Online 2 - 1 Replies Hello i tryed that Guide/Release: Conquer Server (CoFuture) Using MySql!
But it don't work i can't do that phpmyadmin think anyone can help me the language is german but i wanted to change it to english but idk how.
If anyone got Teamviewer or somethink like that would be nice
greetz