[OSP] MP COOP campaign "engine" V0.2 gamma (1.10.2013)

Status
Not open for further replies.

The_dragon

Master Knight
WBNW
Best answers
0
after weeks of hard work, I finnaly managed to make a "working" multiplayer campaign mod. And i share It with you guys, so you can make others life better.
(i am a noob in presenting/explaining something, so excuse me)

THIS IS NOT A PLAYABLE VERSION YET!!!


here you can see the very old first design of multicamp

WARNING! BAD ENGLISH BELOW!!!!!!!
I must warn you now that modding this requires PHP knowledge!!! If you don't have any PHP knowledge, then quit reading this.


So first let's start with how to set up everything.
What you need to set up:
This mod allows you to play singleplayer world map into multiplayer. In order to play a multiplayer game, you need a server. The server that we use in this case is a webserver.
So the first thing that you need to set up is a webserver. I use xampp simple because it is easy to install and it is very easy to use. After you choosed your webserver and after you installed it, you need to find the root folder of it.
Download the mod from the link at the bottom. Then unzip it, and copy the files from webserver files folder (you need to copy the files, not hte folder!!!!) and paste them inside the root of the server.

Now the server setup is complete.
Next you will need to test your server. To do that, open your web browser, and type in the adress bar this "127.0.0.1/test.php" and press enter. Now you should see the message "All setups are fine!". If you do not see this message, then you did something wrong, or there are some permissions  that needs to be edited(google.com is your best friend)
If you see that message, then it is good, and you will need to test with your external ip. Open the web browser again and type in "your_external_ip/test.php" , where your_external_ip needs to be replaced with your ip(you can get your ip here http://whatismyipaddress.com/). You should see the same message. If you do not see that message, then you did something wrong, or there are some permissions that needs to be edited.
If you see that message, then to make sure that it is all good, give the link with the external ip to a friend, and let him confirm that it works.]

Now the server setup is completed and it is working.

The client is just a regular warband mod, but the module system needs an extra setup. After you put your export dir in module_info, you need to specifie the ip of the server that the mod will play.
Setting the ip is very simple: open up module_strings and scrool down to the bottom. The last string should be called "ip", and it's content should be "http://127.0.0.1/multiplayer.php?".Replace "127.0.0.1" with the ip of the server that you want to connect..and you are done!

What you need to know about modding it:
This mod only allows you to send messages(ints and strs) between server and client. It is like the normal multiplayer warband, but instead of having hardwired syncs (player movement, scene props positions, attack, defense) , you would need to write them manually with "multiplayer_send_int_to_server" and "multiplayer_send_string_to_server" (and the others) .

Client modding
The messages that you receive from the server will get into the "code" (that is the name of the script) script.
At the beggining, there is this part
Code:
(store_script_param,":args",1),
   (store_script_param,":num_integers",2),
   (store_script_param,":num_strings",3),
:args stores a slot (troop slot), that contains all the integers that you need to use received from the server (not actually all, you will understand later).  the index 0 will always store the event!
:num_integers stores the number of integers (ex: if you have these integers "2,45,123", num_integers will be 3).
:num_strings stores the number of strings (ex as the integers)
all the received strings will be stored into string regs starting from s1!!!(ex: if you have the first string "asd" and the second "test", then s1 will store"asd" and s2 will store "test")

Sending messages to server is quite easy. You need to use these 2 sintaxes
Code:
(call_script,"script_send_string_to_server",<event>,<number of strings>,<str1>,<str2>,...),
(call_script,"script_send_int_to_server",<event>,<number_of_ints>,<int1>,<int2>...),
To send ints to server, you will first put the event (you can use/define new mpcamp events in module_constants (search for this "MULTI CAMP SLOTS" without quotes)) , then you will put the total number of ints that you want to send (ex: if you want to send ints "2,5,76", then the total nr will be 3), then you will need to put the ints (variables or constants), separated with comma.
ex: for sending the variables ":id",":gold",":cost" , with the event "mpcamp_event_example" you will use (call_script,"script_send_int_to_server",mpcamp_event_example , 3 ,":id",":gold",":cost"),

To send strings to server, you need to specifie the event, how many strings you want to save, and the string registers.
Ex: if you want to send 2 strings (s7 and s13) with the event "mpcamp_event_example", you will use this (call_script,"script_send_string_to_server",mpcamp_event_example,2,s7,s13),

If you want to send strings and ints, then you can store the ints into strings, and then send the entire thing with (call_script,"script_send_string_to_server",<event>,<number of strings>),

Server modding
Your main file for modding webserver is code.php.

the first line is this
Code:
main_code($unique_id,$event,$nr_args,$args)
$unique_id stores the unique id of the player that sended that message
$event stores the event number
$args is a array of all ints and strings received. Note $args[0] stores the event number (idk why i did put the parameter $event...i will fix this in the future version)
$nr_args stores the number of ints and strings

sending messages to client is done using this syntax
Code:
send_data_to_player(<unique_id>,<data_array>,[strings_number])
<unique_id> the unique id of the player that we want the message to be sended
<data_array> is an array that needs to store the desired ints and strs to send. Note!!!! data_array[0] needs to be the event number!!!!!!!!!!!!
[strings_number] needs to be the number of strings (if it is not set, then the nr of strs is 0)

lets have a look at a example
Code:
send_data_to_player($unique_id,[1,23,$example_var])
$unique_id is the id that we will send data to

the first int (1) represents the event number
the second int(23) represents a constant int that will be sended
$example_var is a variable that will be sended
and also the nr of strings is 0, because it is not specified

another example
Code:
send_data_to_player($unique_id,[2,46,"this is just a test",$example_var,"just a string"],2)
$unique_id is the id that we will send data to

the first int (2) represents the event number
the second int(46) represents a constant int that will be sended
"this is just a test" is a string
$example_var is a variable that will be sended
"just a string" another string that we will send

2 represents the nr of strings

--to be done

The structure is a bit complicated...All of the variables are stored in a .txt database (idk if anybody else done this before).
Every player have a unique id. This id is given by the server when the player registers first time (actually it is just a counter). When the player log in, to his unique id is attribuite a local id (1-10).The local id can vary if you logout and then log back in.

(I took this entire ideea from the actual warband mp.Each player have a unique id (based on his cd-key), and when he joins a server, the server will attribuite a local id (0-250).)

When a player registers, a new folder with the name of his unique id is created under "players" folder, then inside are created some .txt files, that will holds his variables( ip, local id, gold , etc). You will notice that the folder "to_send" will be created.

Now i hope you understood what the unique id represents.


Here is a example of how to make and use a new event:
So now, that you know how to send/receive, lets have an example.I choosed the chat function, just because it is simple and it's easy to understand.


To create the chat, first we need a way to get a input.The best way (and the only way) is to make a chat presentation.So i grab the madmin admin chat presentation, and tweaked it a bit and it looked like this
Code:
("chat_message",prsntf_manual_end_only, 0,[
    (ti_on_presentation_load,
       [	   
		(set_fixed_point_multiplier, 1000),
        (init_position, pos1),
        (str_store_string, s1, "@Send to everybody:"),
        (create_text_overlay, reg1, s1,tf_with_outline),
		(overlay_set_color, reg1, 0xFFFF0000), 
		
        (position_set_x, pos1, 200),
        (position_set_y, pos1, 530),
        (overlay_set_position, reg1, pos1),
        (overlay_set_text, reg1, s1),
        (position_set_x, pos1, 1000),
        (position_set_y, pos1, 1000),
        (overlay_set_size, reg1, pos1),
		
        (create_simple_text_box_overlay, "$g_message", tf_center_justify),
        (position_set_x, pos1, 200),
        (position_set_y, pos1, 500),
        (overlay_set_position, "$g_message", pos1),
        (position_set_x, pos1, 600),
        (position_set_y, pos1, 1000),
        (overlay_set_size, "$g_message", pos1),
		(overlay_obtain_focus, "$g_message"),
      
        (assign, "$g_waiting_to_sendMessage", 1),
        (str_clear, s0),
        (overlay_set_text, "$g_message", s0),
        (assign,"$g_waiting_for_confirmation_to_terminate", 1),
        (presentation_set_duration, 999999),
      ]),

      (ti_on_presentation_event_state_change,
        [   (try_begin),
                 (neq,"$g_waiting_to_sendMessage",1),
				  (try_begin),
					(neg|str_is_empty, s0),
					(str_store_string_reg, s1, s0),
					(call_script,"script_send_string_to_server",mpcamp_event_chat,1,s1),
				  (try_end),
                  (assign, "$g_waiting_for_confirmation_to_terminate", 0),
                  (presentation_set_duration, 0),
            (try_end),
        ]),

       (ti_on_presentation_run,
           [
		   
           (try_begin),
                 (key_clicked, key_escape),
                 (assign, "$g_waiting_for_confirmation_to_terminate", 0),
                 (presentation_set_duration, 0),
                 (assign, "$g_waiting_to_sendMessage", 0),
           (else_try),
                  (key_clicked, key_enter),
                  (assign, "$g_waiting_to_sendMessage", 0),
           (try_end),
        ]),
		multiplayer_sync,
		
    ]),
The most important thing is this
Code:
(ti_on_presentation_event_state_change,
        [   (try_begin),
                 (neq,"$g_waiting_to_sendMessage",1),
				  (try_begin),
					(neg|str_is_empty, s0),
					(str_store_string_reg, s1, s0),
					(call_script,"script_send_string_to_server",mpcamp_event_chat,1,s1),
				  (try_end),
                  (assign, "$g_waiting_for_confirmation_to_terminate", 0),
                  (presentation_set_duration, 0),
            (try_end),
        ]),
So we checked if the string is not empty, and then we send it to server with "(call_script,"script_send_string_to_server",mpcamp_event_chat,1,s1),".
The client-server sending is done.

Now the string arrived to the server.
In code.php, we add a new case, case 3. then we check if there is a string (because the cheaty player can use a modified version of the mod)
Code:
if(isset($args[1]))
.
If everything is ok, we will need to send the username of the player that wants to send the message, and we do it with get_player_username($unique_id)  (you can see all the defined function in the readme.txt file)

Now that we got the message, and also the username, we want to send them to each player that is online.So we make a loop that will check every local id
Code:
for($i=1;$i<=10;$i++)
then we get the unique id of the specific local id.
Code:
$u_id = get_unique_id_by_local($i)
then we check if there is an online player at the specified local id(0 = no player)
Code:
if($u_id!=0)
and if everything is ok, then we send the message string and teh username to the client
Code:
send_data_to_player($u_id,[3,$args[1],$username],2);
The server-client sending is done!

Now the message is received by all online players. Next we want to display it in the clients. So we go to "code" script, and we add a new case
Code:
(else_try),
	
		(eq,":event",mpcamp_event_chat),
and then we display the message
Code:
(display_message,"@[{s2}]:{s1}"),
and that's it! that is how the chat function is made...

Hardwired stuffs
-the events register and log in
-"to_send" folder and all contents from it
-the folder "players/0"
-the scripts "send_string_to_server","send_int_to_server","send_data"
-the slots
Code:
slot_to_send_1						=200
slot_to_send_2						=201
slot_to_send_3						=202
slot_to_send_4						=203
slot_to_send_5						=204
slot_to_send_6						=205
slot_to_send_7						=206
slot_to_send_8						=207
slot_to_send_9						=208
slot_to_send_10						=209
slot_nr_arg							=210
slot_data_type						=211 #1 for int,2 for string
slot_temp							=212
slot_event_to_use					=213
-all string registers above the string 65. USE ONLY STRINGS WITH INDEX BELOW 65!!!!!!!!all the string above 65 (66 - 127) are HARDWIRED!!!!!!!!

Note: there are more stuffs, but i need to think of them...


Limitations
-supports up to 10 players
-You can't send more than 10 send_str or send_int per 0.1 ingame hour(you can tweak this from module_triggers, but make sure you don't put it too fast, because the game will **** up)
-everything that will pop up(tutorial messages, game menues, presentations, all game windows(inventory, party, character etc) , etc) will lead to desync, and you will need to log in again. Only use presentations, and at the end of them add "multiplayer_sync," to keep everything in sync.
-You can send 31 max strings one time (don't force it...will lead to broke output)
-You can receive 31 max strings(again, don't use too many)
Note: there are much many things...

How sending/receiving works
Every time you use (call_script,"script_send blah blah, it doesen't sends them immediately, but it actually save the contents into a slot(it is is int), or into strings from 66-96, and when the script "send_data" is called , it reads all the slots and all the strings and send them to server. the same thing hapens on the server too, the int/strs are saved into a file in the folder to_send.


Changelog
v0.1:
-this is the initial version
v0.2:
        -fixed server sending invalid messages to client, causing fake events
        -changed server sending syntax from "send_data_to_player(<unique_id>,<arguments_number>,<data_array>,[strings_number])" to send_data_to_player(<unique_id>,<data_array>,[strings_number])
        -changed client sending syntax from (call_script,"script_send_string_to_server",<event>,<nr_of_strings>), to (call_script,"script_send_string_to_server",<event>,<nr_of_strings>,<first_string>,<second_string>,...),
        -inventory and gold are now synced with the server
        -added new events like show color text
        -added player stats window, by pressing the button TAB
        -added ping function
        -added FPS counter on the key N (i will add more stuffs on this key)
        -added a simple menu window, on key M
        -added a simple inventory window
        -added two server simple triggers : on_connect , on_deconnect
        -added server logs
        -added server config file
        -added anti-teleport (you can enable or disable from server config; now the player movement is server controlled)
        -optimized a little the receiving server part
     

multiplayer campaign mod files download -> HERE .

v0.1:  link.

Credits:
*taleworlds for creating warband
*Gotha for indirectly giving me the ideea that multi camp is possible
*MadocComadrin for madmin (i took the chat presentation from there)

What you are not allowed:
it is not allowed to use scripts/part of scripts without giving credits to me

first appearence of this kind of mod was here!


Thread created in 3+ hours.
 

The_dragon

Master Knight
WBNW
Best answers
0
When you install the mod, make sure you copy the files from mod_files and paste them in the mod folder.

What to do if...
1."Desync" message show up (centered-bottom of the screen) - kepp the spacebar down for 2 seconds, then release it.The message should dissapeare.
2.I need to click multiple time to make the party move - this is something normal, it is caused by nopause mod(which keeps all the things in sync)
3.Random error messages appeares - if you didn't modified the files at all, then exit the game, then go to game folder, and send me the rgl_log.txt , along with a description of the situation
4."Waiting for confirmation screen" stays for more than 10 seconds - this is cause by a network problem.Open up a internet browser, and type in <server_ip>/test.php  (replace the <server_ip> with the server's ip). If the message " All setups are fine!" does not appeare, then there is a server issue. It can be caused by the firewall, or by using a router.



Ingame controls:
1.Register
To register an account, go to start new game->register account. Then choose your awesome name and pass, then click continue, and follow the ingame screens, until you reach the world map

2.Log in
There are 2 ways of log in:
-go to load game, select your savegame, hten hit load and log in
-go to start new game->log in forced -> and follow the ingame screens

3.Chat
The chat key is exactly the multiplayer global key (default is T)

4.Player stats
The player stats is the same as the normal mp, press Tab and you will see a list of all online players, along with their ping(many times the ping is bugged).

5.Menu
The main window is assigned to the key M. Press it once, the menu will be up, press it again, the menu will go away. From there you can choose other submenues(currently only one functionally)

6.Inventory window
The inventory window is a very basic one (many many details needs to be added, but since presentations are pain in a** for me....). You can move the items from one slot to another one, by clicking on them. When you click a slot, that slot will become red, that means that it is selected. Click it again to deselect it. Select a slot, then click on anotherone to swap the item/equip the items. At the bottom you can see the gold, and also you can see two arrows. Those arrows scrool throu items pages.

7.FPS
You can see your current FPS by pressing the key N once, then wait 1 sec, and the fps will show in a message(it is accurately, I tested it with Fraps).

Other things:
1.Currently, the inventory is synced up with the server, and if you want to test it, you need to manually add items for each player. To do that, first find his unique id, then go to players/<his unique id>  and open up the file inventory.txt . You will add the items by replacing a -1 value(or an already existing one) with the item id you want to add(the items id can be found in id_items.py in module system). Make sure that you replace the value, and not delete a '|' . The first -1 (is the first one) is hardwired, changing it will not add a intem into the game.
 

Swyter

Grandmaster Knight
WBM&BWF&S
Best answers
0
Wow, this is crazy! I don't think that you guys are getting it.
He has written his own networking layer on top of the single player module system by using the HTTP operations and a supplementary main server as middleware. Syncing, chat, movement, everything. Hats off.

The_dragon, mate. You are an pretty talented coder.
Oh, and embed the video using the Youtube tag, its a neat proof of concept.
 

The_dragon

Master Knight
WBNW
Best answers
0
Swyter said:
Wow, this is crazy! I don't think that you guys are getting it.
He has written his own networking layer on top of the single player module system by using the HTTP operations and a supplementary main server as middleware. Syncing, chat, movement, everything. Hats off.

The_dragon, mate. You are an pretty talented coder.
Oh, and embed the video using the Youtube tag, its a neat proof of concept.
Thank you man. I wish i could just change my username(i choosed it when i was a kid... :sad: )
 

Swyter

Grandmaster Knight
WBM&BWF&S
Best answers
0
The_dragon said:
Swyter said:
Wow, this is crazy! I don't think that you guys are getting it.
He has written his own networking layer on top of the single player module system by using the HTTP operations and a supplementary main server as middleware. Syncing, chat, movement, everything. Hats off.

The_dragon, mate. You are an pretty talented coder.
Oh, and embed the video using the Youtube tag, its a neat proof of concept.
Thank you man. I wish i could just change my username(i choosed it when i was a kid... :sad: )
Ask Janus, he will help you with that. By the way, keep us informed, the ping looks decent in the video, I must admit that I'm surprised, all this module system <-> HTTP/TCP <-> PHP server <-> HTTP/TCP <-> module system seemed like a lot of overhead to keep everything on sync and dandy, without many latency issues.

I also like that you are using some kind of deferred buffering using slots and then send everything together in batches. It's all a juxtaposition of something so rudimentary, complex and inventive, that how nobody else had thought about this... Well, let's just say that this is a good groundwork start.
 

The_dragon

Master Knight
WBNW
Best answers
0
the version from the video is an old version...that version was faster, but not optimized. The current version doesn't have a ping thing.
In the old version, i didn't used buffers, i was sending the data directly with send_message_to_url and then the string (wich wasn't optimise at all because there was a limit of sending /second , and many of the mesages was only one int and blank response). The ping thing was in a rustique way...basically the server stores the time in miliseconds, then it sends a message to client, wich tell the client to send a message back, and then it substract the saved time from current time in milisecond (i am not sure if it was divided by 2). And the result was the ping.
 

Swyter

Grandmaster Knight
WBM&BWF&S
Best answers
0
The_dragon said:
the version from the video is an old version...that version was faster, but not optimized. The current version doesn't have a ping thing.
In the old version, i didn't used buffers, i was sending the data directly with send_message_to_url and then the string (wich wasn't optimise at all because there was a limit of sending /second , and many of the mesages was only one int and blank response). The ping thing was in a rustique way...basically the server stores the time in miliseconds, then it sends a message to client, wich tell the client to send a message back, and then it substract the saved time from current time in milisecond (i am not sure if it was divided by 2). And the result was the ping.
Makes sense. Have you tried anything with action mode agents? That part seems to be more tricky to get right, with position delay, viewing angle, animations, combat, actions, and so on.
 

The_dragon

Master Knight
WBNW
Best answers
0
i didn't tried. I was only thinking about it, but it is too complicated to make multiplayer battle in this way (i think it is not possible to make a playable battle, because there are not enough data sended every second). I was thinking of making all the world map things in this way, and making the battles in the normal multiplayer with a dedicated server.

I will try making a mp battle in this way (i am curious how will it be :grin:).
 

Swyter

Grandmaster Knight
WBM&BWF&S
Best answers
0
The_dragon said:
i didn't tried. I was only thinking about it, but it is too complicated to make multiplayer battle in this way (i think it is not possible to make a playable battle, because there are not enough data sended every second). I was thinking of making all the world map things in this way, and making the battles in the normal multiplayer with a dedicated server.

I will try making a mp battle in this way (i am curious how will it be :grin:).
Just like battle time!... I'm curious too. But if the limitations imposed on the timing are so great then this is a dead end.

Syncing the bots would be a headache. Things like how to decide who is the one doing the AI simulation and relaying back and forth using stringified TCP packets is an overkill in native code, I don't want to know how that works within the M&B interpreter. *shivers*

Well. At least we have a shared multiplayer campaign, just like in Medieval II: Total War, the battles can be simulated (or optionally played in a temp server) and just enjoy the strategic part of the game, which isn't that bad. It's an attractive concept, and much better than using a web browser like Strategus or the other mod from nijis, which is a TaleWorlds dev.
 

The_dragon

Master Knight
WBNW
Best answers
0
currently i managed to get around 18 succesfull transmisions per second(that means 18 things sended, 18 thing received / second, and in one thing i can send max 10 events (in the current version) ). Now i didn't tested how much it decrease if i use all 10 slots for sending (i realised that i can send how much data i want to server(i can send even 40 events at a time, if i tweak the scripts), but the receiving is only limited to 128 ints and 31 strings one time).
i was thinking of removing the AI completely from the game, and let only players to build/ make quests. Tthis is only a started mod...long way to a final version.
 

Swyter

Grandmaster Knight
WBM&BWF&S
Best answers
0
The_dragon said:
currently i managed to get around 18 succesfull transmisions per second(that means 18 things sended, 18 thing received / second, and in one thing i can send max 10 events (in the current version) ). Now i didn't tested how much it decrease if i use all 10 slots for sending (i realised that i can send how much data i want to server(i can send even 40 events at a time, if i tweak the scripts), but the receiving is only limited to 128 ints and 31 strings one time).
i was thinking of removing the AI completely from the game, and let only players to build/ make quests. Tthis is only a started mod...long way to a final version.
Well, then is not that bad. Maybe by limiting the update radius things can be kept under control. For example, sync all the moving parties under 100 map units as soon as possible and everything else every 2-5-7 seconds. Or if you want something smarter, then do it event-based; when something happens, like somebody entering a city, recruiting troops, fire a broadcast event. That way you won't be sending bogus information, just send when and what needs it.

I know that this is talking in broad lines, and the details of an implementation aren't as easily done.
But hey, first let's theorize with something more of less workable and go down there with code.
 

Lumos

Section Moderator
WBWF&SNWM&BVC
Best answers
0
You'll need to work hard your ass off to bring it to a very functional state, but it's impressive and it's cleverly thought of. Good work. Now keep doing it. :lol:
 
Status
Not open for further replies.