Перейти к содержанию

Общие понятия


Рекомендуемые сообщения

Общие понятия
 
Авторитарный сервер (или мастер сервер)
На этом сервере хранятся все данные или наиболее важные данные и логика игры. Клиенты просят сервер что-то сделать, сервер пропускает через функции, условия игры и выдает ответ отвечающему или еще и на другие клиенты.

Клиент
На клиенте как правило хранятся данные копии. В зависимости от игры расчеты могут быть и на клиенте, чтобы снять нагрузку на цпу сервера и разгрузить траффик. Как правило расчеты физики, столкновений в сетевых играх стараются либо избежать, либо отводят на клиент или мастер клиент.

Мастер-клиент
Мастер клиент как правило, тот кто создает комнату, игру, лобби. Снимает всю или бОльшую часть нагрузки на серверную сторону. Мастер клиент берет полный или частичный контроль над игрой. А серверная сторона либо передает тупо пакеты между мастер-клиентами и клиентами, либо серверная сторона еще и контролирует как-то игру. 

Связи
 
Авторитарный + клиенты
Авторитарный сервер принимает "вопросы и предложения от клиентов" в течении игры. Реагирует на них и отправляет результаты тому кто спрашивал или еще и тем кто в игре.

Не авторитарный + мастер клиент + клиенты
Игрок, который создал игру примает "вопросы и предложения от клиентов" в течении игры. Реагирует на них и отправляет результаты тому кто спрашивал или еще и тем кто в игре. Т.е. мастер клиент хранит данные, все что происходит в игре синхронизируется с ним. Не авторитарный сервер выступает в качестве посредника рассылки пакетов между игроками минуя NAT.

Частично автоританый + мастер клиент + клиенты
Авторитарный сервер может влиять на игру между мастер клиентом и клиентами. Чем это влияние сильнее, тем больше ограничений в сетевой игре получается. Например. Сервер ведет счет времени на игру между клиентами и мастер клиентами. Если у кого-то так называемая "энергия" закончилась, то сервер, говорит, что Вам нельзя начать новую игру. Пример игры Трагедия Белок. Но я не уверен, что там есть мастер клиент. Возможно там полный контроль авторитарного сервера, т.е. физика и движения рассчитаются не мастер клиентом, а сервером.
 

Пример того как выглядят система Клиент + Частично авторитарный сервер
 
Игра-пример с yahoogames про игру поиск грибов игроками в темноте.
 
post-3-0-29548700-1425431474_thumb.jpg
 
Частично авторитарный сервер создает грибы в темноте по интервалу времени. В этом всего лишь и заключается авторитарность. Сервер только создает грибы, когда посчитает нужным. Взятие грибов серверная сторона НЕ КОТРОЛИРУЕТ. В общем этот пример для тех, кто хочет задуматься. Роль сервера и роль клиентов очень гибкая и в задачу разработчика входит много проблем, чтобы не допустить читов. Если разраб ничего делать не будет, будет чит на чите. Разраб преследует концепцию "никогда не доверять клиентам"
 

Клиентская сторона:





 
Серверная сторона



Полный проект можно скачать:
Yahoo Games Network SDK.zip

Документация: ссылка

//-----------------------------------------------------------------------------------------------------------------// //	Mushroom Example//	Created by : Luis Filipe (filipe@seines.pt)//	Dec 2010////	Source code in this example is in the public domain.//  The naruto character model in this demo is copyrighted by Ben Mathis.//  See Assets/Models/naruto.txt for more details////-----------------------------------------------------------------------------------------------------------------using UnityEngine;using System.Collections;using System.Collections.Generic;using PlayerIOClient;public class ChatEntry {	public string text = "";	public bool mine = true;}public class GameManager : MonoBehaviour {	public GameObject target;	public GameObject PlayerPrefab;	public GameObject ToadPrefab;	private Connection pioconnection;	private List<PlayerIOClient.Message> msgList = new List<PlayerIOClient.Message>(); //  Messsage queue implementation	private bool joinedroom = false;	// UI stuff	private Vector2 scrollPosition;	private ArrayList entries = new ArrayList();	private string inputField = "";	private Rect window = new Rect(10, 10, 300, 150);	private int toadspicked = 0;	private string infomsg = "";	void Start() {		// create a random userid 		System.Random random = new System.Random();		string userid = "Guest" + random.Next(0, 10000);		Debug.Log("Starting");		PlayerIOClient.PlayerIO.Connect(			"[Enter your game id here]",	// Game id (Get your own at playerio.com. 1: Create user, 2:Goto admin pannel, 3:Create game, 4: Copy game id inside the "")			"public",						// The id of the connection, as given in the settings section of the admin panel. By default, a connection with id='public' is created on all games.			userid,							// The id of the user connecting. This can be any string you like. For instance, it might be "fb10239" if youґre building a Facebook app and the user connecting has id 10239			null,							// If the connection identified by the connection id only accepts authenticated requests, the auth value generated based on UserId is added here			null,			null,			delegate(Client client) {				Debug.Log("Successfully connected to Player.IO");				infomsg = "Successfully connected to Player.IO";				target.transform.Find("NameTag").GetComponent<TextMesh>().text = userid;				target.transform.name = userid;				// Uncoment the line below to use the Development Server				client.Multiplayer.DevelopmentServer = new ServerEndpoint("localhost",8184);				//Create or join the room 				client.Multiplayer.CreateJoinRoom(					"UnityDemoRoom",					//Room id. If set to null a random roomid is used					"UnityMushrooms",						//The room type started on the server					true,								//Should the room be visible in the lobby?					null,					null,					delegate(Connection connection) {						Debug.Log("Joined Room.");						infomsg = "Joined Room.";						// We successfully joined a room so set up the message handler						pioconnection = connection;						pioconnection.OnMessage += handlemessage;						joinedroom = true;					},					delegate(PlayerIOError error) {						Debug.Log("Error Joining Room: " + error.ToString());						infomsg = error.ToString();					}				);			},			delegate(PlayerIOError error) {				Debug.Log("Error connecting: " + error.ToString());				infomsg = error.ToString();			}		);	}	void handlemessage(object sender, PlayerIOClient.Message m) {		msgList.Add(m);	}	void FixedUpdate() {		// process message queue		foreach(PlayerIOClient.Message m in msgList) {			switch(m.Type) {				case "PlayerJoined":					GameObject newplayer = GameObject.Instantiate(target) as GameObject;					newplayer.transform.position = new Vector3(m.GetFloat(1), 0, m.GetFloat(2));					newplayer.name = m.GetString(0);					newplayer.transform.Find("NameTag").GetComponent<TextMesh>().text = m.GetString(0);					break;				case "Move":					GameObject upplayer = GameObject.Find(m.GetString(0));					upplayer.transform.LookAt(new Vector3(m.GetFloat(1), 0, m.GetFloat(2)));					// set transform x axis to 0, so the character will be facing forward					upplayer.transform.eulerAngles = new Vector3(0, upplayer.transform.eulerAngles.y, upplayer.transform.eulerAngles.z);					// get distance between current position and target position,					// we'll need to value to know how much the tween will last					float dist = Vector3.Distance(upplayer.transform.position, new Vector3(m.GetFloat(1), 0, m.GetFloat(2)));					// create a tween between current and target position					iTween.MoveTo(upplayer, iTween.Hash("x", m.GetFloat(1), "z", m.GetFloat(2), "onstart", "startwalk", "oncomplete", "stopwalk", "time", dist, "delay", 0, "easetype", iTween.EaseType.linear));					break;				case "Harvest":					GameObject hvplayer = GameObject.Find(m.GetString(0));					hvplayer.transform.LookAt(new Vector3(m.GetFloat(1), .5f, m.GetFloat(2)));					// set transform x axis to 0, so the character will be facing forward					hvplayer.transform.eulerAngles = new Vector3(0, hvplayer.transform.eulerAngles.y, hvplayer.transform.eulerAngles.z);					// get distance between current position and target position,					// we'll need to value to know how much the tween will last					float distance = Vector3.Distance(hvplayer.transform.position, new Vector3(m.GetFloat(1), 0, m.GetFloat(2)));					// create a tween between current and target position					iTween.MoveTo(hvplayer, iTween.Hash("x", m.GetFloat(1), "z", m.GetFloat(2), "onstart", "startwalk", "oncomplete", "stopharvest", "time", distance, "delay", 0, "easetype", iTween.EaseType.linear));					break;				case "Picked":					// remove the object when it's picked up					GameObject removetoad = GameObject.Find("Toad" + m.GetInt(0));					Destroy(removetoad);					break;				case "Chat":					if(m.GetString(0) != "Server") {						GameObject chatplayer = GameObject.Find(m.GetString(0));						chatplayer.transform.Find("Chat").GetComponent<TextMesh>().text = m.GetString(1);						chatplayer.transform.Find("Chat").GetComponent<MeshRenderer>().material.color = Color.white;						chatplayer.transform.Find("Chat").GetComponent<chatclear>().lastupdate = Time.time;					}					ChatText(m.GetString(0) + " says: " + m.GetString(1), false);					break;				case "PlayerLeft":					// remove characters from the scene when they leave					GameObject playerd = GameObject.Find(m.GetString(0));					Destroy(playerd);					break;				case "Toad":					// adds a toadstool to the scene					GameObject newtoad = GameObject.Instantiate(ToadPrefab) as GameObject;					newtoad.transform.position = new Vector3(m.GetFloat(1), 0.1f, m.GetFloat(2));					newtoad.name = "Toad" + m.GetInt(0);					break;				case "ToadCount":					// updates how many toads have been picked up by the player					toadspicked = m.GetInt(0);					break;			}		}		// clear message queue after it's been processed		msgList.Clear();	}	void OnMouseDown() {		// this function responds to mouse clicks on the ground		// it will send a move request to the server		// ignore user input if we're not inside a room		if(!joinedroom)			return;		Vector3 targetPosition = new Vector3(0, 0, 0);		var playerPlane = new Plane(Vector3.up, target.transform.position);		var ray = Camera.main.ScreenPointToRay(Input.mousePosition);		var hitdist = 0.0f;		if(playerPlane.Raycast(ray, out hitdist)) {			targetPosition = ray.GetPoint(hitdist);			pioconnection.Send("Move", targetPosition.x, targetPosition.z);		}	}	void OnGUI() {		window = GUI.Window(1, window, GlobalChatWindow, "Chat");		GUI.Label(new Rect(10, 160, 150, 20), "Toadstools picked: " + toadspicked);		if(infomsg != "") {			GUI.Label(new Rect(10, 180, Screen.width, 20), infomsg);		}	}	public void HarvestAt(float posx, float posz) {		pioconnection.Send("MoveHarvest", posx, posz);	}	public void TryPickup(string id) {		pioconnection.Send("Pickup", id);	}	void GlobalChatWindow(int id) {		if(!joinedroom)			return;		GUI.FocusControl("Chat input field");		// Begin a scroll view. All rects are calculated automatically - 		// it will use up any available screen space and make sure contents flow correctly.		// This is kept small with the last two parameters to force scrollbars to appear.		scrollPosition = GUILayout.BeginScrollView(scrollPosition);		foreach(ChatEntry entry in entries) {			GUILayout.BeginHorizontal();			if(!entry.mine) {				GUILayout.Label(entry.text);			} else {				GUI.contentColor = Color.yellow;				GUILayout.Label(entry.text);				GUI.contentColor = Color.white;			}			GUILayout.EndHorizontal();			GUILayout.Space(3);		}		// End the scrollview we began above.		GUILayout.EndScrollView();		if(Event.current.type == EventType.keyDown && Event.current.keyCode == KeyCode.Return && inputField.Length > 0) {			GameObject chatplayer = GameObject.Find(target.transform.name);			chatplayer.transform.Find("Chat").GetComponent<TextMesh>().text = inputField;			chatplayer.transform.Find("Chat").GetComponent<MeshRenderer>().material.color = Color.white;			chatplayer.transform.Find("Chat").GetComponent<chatclear>().lastupdate = Time.time;			ChatText(target.transform.name + " says: " + inputField, true);			pioconnection.Send("Chat", inputField);			inputField = "";		}		GUI.SetNextControlName("Chat input field");		inputField = GUILayout.TextField(inputField);		GUI.DragWindow();	}	void ChatText(string str, bool own) {		var entry = new ChatEntry();		entry.text = str;		entry.mine = own;		entries.Add(entry);		if(entries.Count > 50)			entries.RemoveAt(0);		scrollPosition.y = 1000000;	}}
using System;using System.Collections.Generic;using System.Text;using System.Collections;using PlayerIO.GameLibrary;using System.Drawing;namespace MushroomsUnity3DExample {	public class Player : BasePlayer {		public float posx = 0;		public float posz = 0;		public int toadspicked = 0;	}	public class Toad {		public int id = 0;		public float posx = 0;		public float posz = 0;	}	[RoomType("UnityMushrooms")]	public class GameCode : Game<Player> {		private int last_toad_id = 0;		private List<Toad> Toads = new List<Toad>(); 		// This method is called when an instance of your the game is created		public override void GameStarted() {			// anything you write to the Console will show up in the 			// output window of the development server			Console.WriteLine("Game is started: " + RoomId);			// spawn 10 toads at server start			System.Random random = new System.Random();			for(int x = 0; x < 10; x++) {				int px = random.Next(-9, 9);				int pz = random.Next(-9, 9);				Toad temp = new Toad();				temp.id = last_toad_id;				temp.posx = px;				temp.posz = pz;				Toads.Add(temp);				last_toad_id++;			}			// respawn new toads each 5 seconds			AddTimer(respawntoads, 5000);			// reset game every 2 minutes			AddTimer(resetgame, 120000);		}		private void resetgame() {			// scoring system			Player winner = new Player();			int maxscore = -1;			foreach(Player pl in Players) {				if(pl.toadspicked > maxscore) {					winner = pl;					maxscore = pl.toadspicked;				}			}			// broadcast who won the round			if(winner.toadspicked > 0) {				Broadcast("Chat", "Server", winner.ConnectUserId + " picked " + winner.toadspicked + " Toadstools and won this round.");			} else {				Broadcast("Chat", "Server", "No one won this round.");			}			// reset everyone's score			foreach(Player pl in Players) {				pl.toadspicked = 0;			}			Broadcast("ToadCount", 0);		}		private void respawntoads() {			if(Toads.Count == 10)				return;			System.Random random = new System.Random();			// create new toads if there are less than 10			for(int x = 0; x < 10 - Toads.Count; x++) {				int px = random.Next(-9, 9);				int pz = random.Next(-9, 9);				Toad temp = new Toad();				temp.id = last_toad_id;				temp.posx = px;				temp.posz = pz;				Toads.Add(temp);				last_toad_id++;				// broadcast new toad information to all players				Broadcast("Toad", temp.id, temp.posx, temp.posz);			}		}		// This method is called when the last player leaves the room, and it's closed down.		public override void GameClosed() {			Console.WriteLine("RoomId: " + RoomId);		}		// This method is called whenever a player joins the game		public override void UserJoined(Player player) {			foreach(Player pl in Players) {				if(pl.ConnectUserId != player.ConnectUserId) {					pl.Send("PlayerJoined", player.ConnectUserId, 0, 0);					player.Send("PlayerJoined", pl.ConnectUserId, pl.posx, pl.posz);				}			}			// send current toadstool info to the player			foreach(Toad t in Toads) {				player.Send("Toad", t.id, t.posx, t.posz);			}		}		// This method is called when a player leaves the game		public override void UserLeft(Player player) {			Broadcast("PlayerLeft", player.ConnectUserId);		}		// This method is called when a player sends a message into the server code		public override void GotMessage(Player player, Message message) {			switch(message.Type) {				// called when a player clicks on the ground				case "Move":					player.posx = message.GetFloat(0);					player.posz = message.GetFloat(1);					Broadcast("Move", player.ConnectUserId, player.posx, player.posz);					break;				case "MoveHarvest":					// called when a player clicks on a harvesting node					// sends back a harvesting command to the player, a move command to everyone else					player.posx = message.GetFloat(0);					player.posz = message.GetFloat(1);					foreach(Player pl in Players) {						if(pl.ConnectUserId != player.ConnectUserId) {							pl.Send("Move", player.ConnectUserId, player.posx, player.posz);						}					}					player.Send("Harvest", player.ConnectUserId, player.posx, player.posz);					break;				case "Pickup":					// called when the player is actually close to the harvesting node					int pickupid = int.Parse(message.GetString(0).Replace("Toad", ""));					// Find a toad by its id					Toad result = Toads.Find( delegate(Toad td) { return td.id == pickupid; } );					if(result != null) {						// sends everyone information that a toad as been picked up						// increases player toad count						Broadcast("Picked", result.id);						Toads.Remove(result);						player.toadspicked++;						player.Send("ToadCount", player.toadspicked);					} else {						// id of the toad doesn't exist, either the player						// is trying to cheat, or someone else already picked 						// that toadstool						Console.WriteLine("Not found: {0}", pickupid);					}					break;				case "Chat":					foreach(Player pl in Players) {						if(pl.ConnectUserId != player.ConnectUserId) {							pl.Send("Chat", player.ConnectUserId, message.GetString(0));						}					}					break;			}		}	}}
Ссылка на комментарий
Поделиться на другие сайты

Ухты! Очень интересно...

Думаю без атаки на сервак...сложно/нереально будет что-то сделать...всё-же спасибо MasterGH  :-D

 

Кстати тут такой прикол вышел у меня...заранее прошу прощения если что.

Играл в CS1.6_UCP_8.3 в окне 640x480...решил тупо открыть Cheat Engine и тут синий экран смерти...

Ладно! перезагрузил комп...открыл сначала Cheat Engine, а потом запустил контру и бах опять экран смерти.

Признаюсь! даже не пытался что то там хакнуть в контре, а тупо открыл скрипт от другой игры просто хотел

поправить скрипт который делал для Residen Evil: Revelation 2, а тут такое.

Походу UСP сделала такую защиту, что даже запустив прогу Cheat Engine...и приходит конец всему сразу.

Дааа-уж!!! Нет слов.

NullAlex: красный цвет может использовать только администрация.
Ссылка на комментарий
Поделиться на другие сайты

Ухты! Очень интересно...

Думаю без атаки на сервак...сложно/нереально будет что-то сделать...всё-же спасибо MasterGH  :-D

 

Кстати тут такой прикол вышел у меня...заранее прошу прощения если что.

Играл в CS1.6_UCP_8.3 в окне 640x480...решил тупо открыть Cheat Engine и тут синий экран смерти...

Ладно! перезагрузил комп...открыл сначала Cheat Engine, а потом запустил контру и бах опять экран смерти.

Признаюсь! даже не пытался что то там хакнуть в контре, а тупо открыл скрипт от другой игры просто хотел

поправить скрипт который делал для Residen Evil: Revelation 2, а тут такое.

Походу UСP сделала такую защиту, что даже запустив прогу Cheat Engine...и приходит конец всему сразу.

Дааа-уж!!! Нет слов.

1. Ddos решает :D

2. Бсодит? Ну незнаю... Мб проблема в той табличке, которую ты открывал?

Ссылка на комментарий
Поделиться на другие сайты

RockHamer Не совсем я тебя понял что ты имел ввиду.

По отдельности запускаешь всё нормально CE или контру, всё работает...

UCP походу видит процесс CE и сразу вылетает синий экран смерти "BSOD".

Ладно бы просто ошибку выдавал, но нет...сразу конец всему.

На другом компе проверил...тоже самое.

6-7 раз комп свой перезагружал для полной достоверности.

Даже старая версия CE 5.5_5.6, такой-же результат даёт "BSOD" и всё.

Ссылка на комментарий
Поделиться на другие сайты

RockHamer Не совсем я тебя понял что ты имел ввиду.

По отдельности запускаешь всё нормально CE или контру, всё работает...

UCP походу видит процесс CE и сразу вылетает синий экран смерти "BSOD".

Ладно бы просто ошибку выдавал, но нет...сразу конец всему.

На другом компе проверил...тоже самое.

6-7 раз комп свой перезагружал для полной достоверности.

Даже старая версия CE 5.5_5.6, такой-же результат даёт "BSOD" и всё.

Скорее всего критическая ошибка в UCP. Инфа соточка, т.к. СЕ со всеми дружит и не конфликтует. Надо бы разрабам этого "чуда" отрапортавать. 

Авторитарный сервер (или мастер сервер)

Я прочитал - тоталитарный )) Отличник по истории))

Изменено пользователем RockHamer
Ссылка на комментарий
Поделиться на другие сайты

Причём здесь настройки, если я просто запускаю/открываю CE невыбирая процесс игры даже...просто тупо открыть программу CE.

при этом у меня сходу экран смерти, если у меня запущена CS1.6_UCP 8.3 не важно где в меню или в самой игре.

Сбрасывал настройки и выбирал другой отладчик...всё ровно экран смерти выдаёт.

Видимо это защита от CE такая, типа экран смерти.

Ссылка на комментарий
Поделиться на другие сайты

Причём здесь настройки, если я просто запускаю/открываю CE невыбирая процесс игры даже...просто тупо открыть программу CE.

при этом у меня сходу экран смерти, если у меня запущена CS1.6_UCP 8.3 не важно где в меню или в самой игре.

Сбрасывал настройки и выбирал другой отладчик...всё ровно экран смерти выдаёт.

Видимо это защита от CE такая, типа экран смерти.

Попробуй снести СЕ и поставить заново, на другой диск. И в такой конфигурации (стартовой) попробуй еще раз.

Изменено пользователем RockHamer
Ссылка на комментарий
Поделиться на другие сайты

Уже пробовал...даже на другом компе проверял...результат тот-же. %)

Если неверите можете сами попробовать, если у вас есть контра с ucp v8.3.

Ладно...посути я не пытаюсь и не пытался взломать эту контру...просто с

такой фигнёй случайно столкнулся в первые, вот и решил расказать, если кому интересно. :sleep:

Ссылка на комментарий
Поделиться на другие сайты

Отставить панику, это просто один из криво реализованных отладочных приемов. Многие игры тем или иным способом отказываются работать, если находят запущенные сканеры памяти, отладчики, дизассемблеры и прочие подобные утилиты. Просто в этой, видимо, защита реализована в виде обращения к нулевому указателю (что вызывает гарантированный отказ ядра). От подобных штук существуют плагины, в том числе и для Cheat Engine. От большинства подобных штук хорошо помогает kernelmode-отладчик (тот самый, которому нужна DBVM), но он довольно плохо работает (не у всех).
Ссылка на комментарий
Поделиться на другие сайты

Ну так я и понял что это и происходит.

Походу UCP сканирует все запущенные процессы в винде и если обнаружевает сканер памяти,

ну или что-то подобное для взлома игр, даёт сразу экран смерти "BSOD"

Ладно...как говорится, не проверишь, не узнаешь.

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.