Skip to content

levserk/v6-game-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

V6-Game-Server

Сервер на node.js для пошаговых игр.

Установка

npm install v6-game-server

Запуск

		var Server = require('v6-game-server',
			// настройки
			conf = {},
			// игровой движок
			engine = {},
			// сервер
			server = new Server(conf, engine);
		
		server.start();

Настройки

Настройки сервера с параметрами по умолчанию
	{
		game: 'default',        	// обязательный парамерт, алиас игры и бд
		port: 8080,             	// порт подключения веб сокета
		pingTimeout:100000,     	// таймаут клиента в мс
		pingInterval:10000,     	// интервал пинга клиента в мс
		closeOldConnection: true, 	// закрывать старое соединение клиента, при открытии нового  
		loseOnLeave: false,     	// засчитывать поражение при разрыве соединения с клиентом
		reconnectOldGame: true, 	// загружать игру клинета, в которой произошел разрыв
		spectateEnable: true,   	// разрешить просмотр игр
		logLevel:3,             	// уровень подробности лога, 0 - без лога, 1 - только ошибки
		turnTime: 100,              // время на ход игрока в секундах
		timeMode: 'reset_every_switch', // режимы таймера:
										// 'reset_every_turn' сбрасывать после каждого хода
										// 'reset_every_switch' сбрасывать после перехода хода
										// 'dont_reset' не сбрасывать таймер, время на всю партию
										// 'common' у игроков общее время на ход
		timeStartMode: 'after_switch',  // когда запускать таймер
										// 'after_turn' после первого хода
										// 'after_switch' после первого перехода хода
										// 'after_round_start' сразу после начала раунда
        addTime: 0,                 // сколько милисекунд добавлять к времени на ход игрока после каждого его хода
		maxTimeouts: 1,         	// разрешенное число пропусков хода игрока подряд до поражения
		clearTimeouts: true,		// обнулять число пропусков игрока после его хода
		maxOfflineTimeouts: 1,  	// число пропусков отключенного игрока подряд до поражения
		minTurns: 0,            	// минимальное число число ходов (переходов хода) для сохранения игры
		takeBacks: 0,           	// число разрешенных игроку ходов назад
		loadRanksInRating: false,   // загружать актуальные ранги при открытии таблицы рейтинга
		ratingUpdateInterval: 1000, // интервал обновления рангов в списке игроков
		penalties: false,       	// загружать штарфы игроков
		mode: 'debug',          	// значение 'develop' уставновит режим без использования бд
		gameModes: ['default'], 	// игровые режимы, со своим рейтингом и историей, имена без пробелов
		modesAlias:{default:'default'}, // отображаемые клиенту алиасы режимов
		enableIpGames: false,       // разрешает игры с одного ip
        minUnfocusedTurns: 0,       // минимальное число ходов с потерей фокуса для засчитывания победы как читерской
        							// 0 - не считать
        minPerUnfocusedTurns: 0.9,  // соотношение числа ходов с потерей фокуса для засчитывания победы как читерской
		adminList: [],				// список userId админов
		adminPass: '',				// пароль для функций администратора
		mongo:{                 	// настройки подключения mongodb
			host: '127.0.0.1',
			port: '27017'
		},
		redis:{                 	// настройки подключения redis
        	host: '127.0.0.1',
        	port: '6379'
        },
		https: true,				// настройки https
		httpsKey: '/path../serv.key',
		httpsCert: '/path../serv.crt',
		httpsCa: ['/path../sub.class1.server.ca.pem', '/path../ca.pem'],
	}
Примеры настроек:
- 	обычная игра, время на ход 30 секунд, разрешен один пропуск хода,
	время игрока обнуляется после каждого хода, таймер стартует после первого хода
	{
		turnTime: 30,
		maxTimeouts: 2,
		timeMode: 'reset_every_turn',
		timeStartMode: 'after_turn',
	}
-	блиц, время на партию 60 секунд, время игрока не обнуляется,
	после каждого его хода к его времени на ход добавляется 1 секунда,
	таймер стартует после перехода хода к другому игроку,
	после первого пропуска хода ему засчитывается поражение
	{
		turnTime: 60,
		maxTimeouts: 1,
		timeMode: 'dont_reset',
		timeStartMode: 'after_switch',
		addTime: 1000
	}
-	игра с общим временем на ход, по типу "кто быстрее",
	таймер страртует сразу после начала раунда,
	по истечении часа срабатывает таймаут и необходимо решить результат игры
	{
		turnTime: 3600,
		maxTimeouts: 2,
		timeMode: 'common',
		timeStartMode: 'after_round_start',
	}

Игровой движок

Методы игрового движка
	{
		/**
		 * вызывается после соединения нового пользователя в первый раз
		 * устанавливает значения нового пользователя по умолчанию
		 * рейтинги, очки, и т.д.
		 */
		initUserData: function(mode, modeData){
			return modeData;
		},
		
		/**
		 * вызывается перед началом игрового раунда
		 * возвращаемый объект будет передан всем игрокам в начале раунда
		 * по умолчанию возвращает объект переданный игроком в приглашении
		 */
		initGame: function (room) {
			return {
				inviteData: room.inviteData
			}
		},

		/**
		 * вызывается в начале раунда
		 * возвращает игрока, который будет ходить первым
		 * по умолчанию первым ходит создатель комнаты, 
		 * в следующем раунде ход переходит к другому игроку
		 */
		setFirst: function (room) {
			if (!room.game.first) return room.owner;
			return room.getOpponent(room.game.first)
		},

		/**
		 * вызывается каждый ход или пропуск хода игрока
		 * возвращаемый объект будет передан всем игрокам и записан в историю
		 * если вернуть false || null || undefined ход будет признан некорректным
		 * в случае пропуска хода, turn = {action: 'timeout'}
		 * если вернуть объект с полем action = 'timeout'
		 * он будет принят как событие пропуск хода, иначе как обычный ход
		 * type {'turn'|'timeout'} - ход игрока или таймаут
 		 */
		doTurn: function(room, user, turn, type){
		    if (type == 'timeout'){
                // this is user timeout
            }
			return turn;
		},

		/**
		 * вызывается каждый ход игрока или после события пропуска хода
		 * возвращаемый игрок будет ходить следующим
		 * если вернуть того же игрока, чей был ход, ход останется за ним
		 * type {'turn'|'timeout'} - ход игрока или таймаут
		 */
		switchPlayer: function(room, user, turn, type){
			if (type == 'timeout'){
                // this is user timeout
            }
			return room.getOpponent(user);
		},

		/**
		 * вызывается после отправке игроком события
		 * возвращаемый объект будет передан заданным игрокам, и должен быть следующего вида:
		 * { event, target, user } || [Array], где
		 * event - объект с обязательным полем type
		 * target - цель для отправки события null || Room || User
		 * может быть массивом с разными объектами событий и целями
		 */
		userEvent: function(room, user, event){
			return {
				event: event,
				target: room,
				user: user.userId
			}
		},

		/**
		 * вызывается в начале раунда и после каждого хода игрока
		 * возвращаемый объект будет передан заданным игрокам, и должен быть следующего вида:
		 * { event, target, user } || [Array], где
		 * event - объект с обязательным полем type
		 * target - цель для отправки события null || Room || User
		 * может быть массивом с разными объектами событий и целями
		 */
		gameEvent: function(room, user, turn, roundStart){
		   return null;
		},

		/**
		 * вызывается каждый ход и событие, определяет окончание раунда
		 * возвращаемый объект будет передан всем игрокам 
		 * и должен быть вида {winner : user}, где
		 * user - User (игрок победитель ) || null (ничья)
		 * если вернуть false - раунд еще не окончен
		 * дополнительное поле 'action' указывает на действие,
		 * по которому завершилась игра, по умолчанию 'game_over'
		 * если пользователь не подключен, то игра завешится по
		 * максимальному числу офлайн таймаутов
		 * если не подключены оба, завершится поражением пропустившего
		 * если не обрабатывать пропускать ход можно бесконечно
		 * type {'turn'|'event','timeout'} - ход, событие или таймаут
		 */
    	getGameResult: function(room, user, turn, type){
    	    switch (type){
    	        case 'timeout':
    	            if (type == 'timeout'){
    	                // if user have max timeouts, other win
    	                if (room.data[user.userId].timeouts == room.maxTimeouts){
    	                    return {
    	                        winner: room.getOpponent(user),
    	                        action: 'timeout'
    	                    };
    	                } else return false;
    	            }
    	            break;
    	        case 'event':
    	            if (turn.type){
    	                return false;
    	            }
    	            break;
    	        case 'turn':
    	            switch (turn.result){
    	                case 0: // win other player
    	                    return {
    	                        winner: room.getOpponent(user)
    	                    };
    	                    break;
    	                case 1: // win current player
    	                    return {
    	                        winner: user
    	                    };
    	                    break;
    	                case 2: // draw
    	                    return {
    	                        winner: null
    	                    };
    	                    break;
    	                default: // game isn't end
    	                    return false;
    	            }
    	            break;
    	    }
    	},

		/**
		 * вызывается по окончанию раунда
		 * возвращаемый объект утсанавливает значение очков игроков 
		 * room.players[0][room.mode].['score'] = new_score
		 */
		getUsersScores: function(room, result){
			// например
			for (var i = 0; i < room.players.length; i++){
            if (room.players[i] == result.winner)
                room.players[i][room.mode].score += 10;
            else room.players[i][room.mode].score -= 10;
        }
        return result;
		},

		/**
		 * вызывается после авторизации пользователя
		 * проверяет подлинноть подписи
		 */
		checkSign: function(user){
			return (user.userId && user.userName && user.sign);
		}

		/**
         * действие по вызову администратора
         * @param admin
         * @param type
         * @param data
         */
        adminAction: function(admin, type, data){

        }
	};

Игровые сущности

Room
	{
		owner: User, 		// создатель
		players: Array,		// массив с игроками
		spectators: Array,	// массив зрителей
		inviteData: Object	// объект приглашения
		mode: String		// режим
		games: Int;			// сыграно раундов
		turnTime: Int;		// время на ход
		game: {
			state: String 	// состояние игры:  waiting,  playing, end
			current: User,	// текущий игрок
			first: User,	// игрок, чей ход первый, установленный функцией engine.setFirst
			history: Array,	// массив с иторией ходов и событий
			shistory: String// массив с историей, преобразованный в строку
			turnStartTime: UTC 	// дата начала хода игрока
		},
		data: Object,		// массив ключ значение, где ключи - userId
							// для хранения временной информации для каждого игрока
		getOpponent: Function(user: User)  	// возвращает соперника игрока
		setUserTurnTime: Function(time: ms) // устанавливает время на следующий ход
	}
User
	{
		userId: String, 	// идетификатор игрока
		userName: String	// имя	
		sign: String		// подпись
		currentRoom: Room	// текущая комната (играет или зритель)
	}

About

nodejs game server

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published