SmartFoxServer 2x
-
Setup
-
Connect GUI
-
Handling Information between Server and Client
-
Setup
- download the SmartFoxServer 2x here .
- install the server on your desktop.
- start the server
- open the admin tool with typing in your browser http://localhost:8080/admin/
- connect to server
- default Username/Password:
Username: sfsadmin Password: sfsadmin
- go to Administration modules → Server Configurator
- add a new socketaddress, same ip, port type = UDP
-
don’t forget to submit
-
I get the basics for the connect/login from the FPS Demo, which can be downloaded here
-
in the folder SFS2x you will find a new folder with the name extensions open the folder and put in it the folder from the FPS Demo called SFS2XFPSextension
-
you can give this folder a name you like
-
now open the project “SFS2XFPSTutorial” with unity3d
-
go to the NetworkManager.cs and change the name
public readonly static string ExtName = "tng";// <----this is the SFS2XFPSextension folder if you renamed it , then put the current name here
- thats all on the configuration part, you can start the server and login.
- Connect GUI
You can change the Connect/Login phase like you want i do it this way, because i do not like the "chatroom " in the demo:
LobbyGUI.cs
using System.Text;
using Sfs2X;
using Sfs2X.Core;
using Sfs2X.Entities;
using Sfs2X.Requests;
using Sfs2X.Logging;
public class LobbyGUI : MonoBehaviour {
private SmartFox smartFox;
private string zone = "SimpleChat";
public string serverName = "127.0.0.1";
public int serverPort = 9933;
private string username = "";
private string userpassword="";
private string loginErrorMessage = "";
public int areaHeight = 240;
public int areaWidth = 200;
public Texture2D background;
private ArrayList messages = new ArrayList();
private System.Object messagesLocker = new System.Object();
public GUISkin gSkin;
void Start()
{
bool debug = false;
if (SmartFoxConnection.IsInitialized)
{
smartFox = SmartFoxConnection.Connection;
}
else
{
smartFox = new SmartFox(debug);
}
smartFox.AddLogListener(LogLevel.INFO, OnDebugMessage);
}
void FixedUpdate() {
smartFox.ProcessEvents();
}
#region Callbacks
private void AddEventListeners() {
smartFox.RemoveAllEventListeners();
smartFox.AddEventListener(SFSEvent.CONNECTION, OnConnection);
smartFox.AddEventListener(SFSEvent.CONNECTION_LOST, OnConnectionLost);
smartFox.AddEventListener(SFSEvent.LOGIN, OnLogin);
smartFox.AddEventListener(SFSEvent.LOGIN_ERROR, OnLoginError);
smartFox.AddEventListener(SFSEvent.LOGOUT, OnLogout);
smartFox.AddEventListener(SFSEvent.ROOM_JOIN, OnJoinRoom);
smartFox.AddEventListener(SFSEvent.PUBLIC_MESSAGE, OnPublicMessage);
smartFox.AddEventListener(SFSEvent.ROOM_CREATION_ERROR, OnCreateRoomError);
smartFox.AddEventListener(SFSEvent.USER_ENTER_ROOM, OnUserEnterRoom);
smartFox.AddEventListener(SFSEvent.USER_EXIT_ROOM, OnUserLeaveRoom);
smartFox.AddEventListener(SFSEvent.ROOM_ADD, OnRoomAdded);
smartFox.AddEventListener(SFSEvent.ROOM_REMOVE, OnRoomDeleted);
smartFox.AddEventListener(SFSEvent.USER_COUNT_CHANGE, OnUserCountChange);
smartFox.AddEventListener(SFSEvent.UDP_INIT, OnUdpInit);
}
private void UnregisterSFSSceneCallbacks() {
smartFox.RemoveAllEventListeners();
}
public void OnConnection(BaseEvent evt) {
bool success = (bool)evt.Params["success"];
if (success) {
SmartFoxConnection.Connection = smartFox;
Debug.Log("Connected...");
isConnected=true;
smartFox.Send(new LoginRequest(username, "", zone));
}
}
public void OnConnectionLost(BaseEvent evt) {
UnregisterSFSSceneCallbacks();
}
public void OnLogin(BaseEvent evt) {
try {
if (evt.Params.ContainsKey("success") !(bool)evt.Params["success"]) {
loginErrorMessage = (string)evt.Params["errorMessage"];
Debug.Log("Login error: "+loginErrorMessage);
}
else {
Debug.Log("Logged in successfully");
// Startup up UDP
smartFox.InitUDP(serverName, serverPort);
}
}
catch (Exception ex) {
Debug.Log("Exception handling login request: "+ex.Message+" "+ex.StackTrace);
}
}
public void OnLoginError(BaseEvent evt) {
Debug.Log("Login error: "+(string)evt.Params["errorMessage"]);
}
public void OnUdpInit(BaseEvent evt) {
if (evt.Params.ContainsKey("success") !(bool)evt.Params["success"]) {
loginErrorMessage = (string)evt.Params["errorMessage"];
Debug.Log("UDP error: "+loginErrorMessage);
} else {
Debug.Log("UDP ok");
SetupRoom("Sunna");
}
}
void OnLogout(BaseEvent evt) {
smartFox.Disconnect();
}
public void OnDebugMessage(BaseEvent evt) {
string message = (string)evt.Params["message"];
Debug.Log("[SFS DEBUG] " + message);
}
public void OnJoinRoom(BaseEvent evt)
{
Room room = (Room)evt.Params["room"];
// If we joined a game room, then we either created it (and auto joined) or manually selected a game to join
if (room.IsGame) {
Debug.Log ("Joined game room " + room.Name);
UnregisterSFSSceneCallbacks();
Application.LoadLevel("game");
}
}
public void OnCreateRoomError(BaseEvent evt) {
string error = (string)evt.Params["errorMessage"];
Debug.Log("Room creation error; the following error occurred: " + error);
}
public void OnUserEnterRoom(BaseEvent evt) {
User user = (User)evt.Params["user"];
lock (messagesLocker) {
messages.Add(user.Name + " joined room");
}
}
private void OnUserLeaveRoom(BaseEvent evt) {
User user = (User)evt.Params["user"];
lock (messagesLocker) {
messages.Add(user.Name + " left room");
}
}
public void OnRoomAdded(BaseEvent evt) {
Room room = (Room)evt.Params["room"];
if ( room.IsGame ) {
smartFox.Send(new JoinRoomRequest("Sunna", null, smartFox.LastJoinedRoom.Id));
}
}
public void OnUserCountChange(BaseEvent evt) {
Room room = (Room)evt.Params["room"];
if (room.IsGame ) {
}
}
public void OnRoomDeleted(BaseEvent evt) {
}
void OnPublicMessage(BaseEvent evt) {
try {
string message = (string)evt.Params["message"];
User sender = (User)evt.Params["sender"];
lock (messagesLocker) {
messages.Add(sender.Name + " said " + message);
}
Debug.Log("User " + sender.Name + " said: " + message);
}
catch (Exception ex) {
Debug.Log("Exception handling public message: "+ex.Message+ex.StackTrace);
}
}
#endregion Callbacks
private bool isConnected;
void OnGUI()
{
if (smartFox == null){
return;
}
GUI.DrawTexture(new Rect(0,0,Screen.width,Screen.height), background);
GUI.skin = gSkin;
int ScreenX = ((int)(Screen.width / 2) - (areaWidth / 2));
int ScreenY = ((int)(Screen.height / 2) - (areaHeight / 2));
// Connect
if (!isConnected) {
GUILayout.BeginArea (new Rect (ScreenX, ScreenY, areaWidth, areaHeight),"Login","Window");
GUILayout.Label("Server: ");
serverName = GUILayout.TextField(serverName, 25);
GUILayout.Label("Port: ");
serverPort = int.Parse(GUILayout.TextField(serverPort.ToString(), 4));
GUILayout.Label( "Username: ");
username = GUILayout.TextField( username, 25);
GUILayout.Label("Password: ");
userpassword=GUILayout.PasswordField (userpassword, "*"[0], 25);
GUILayout.Space(4);
if (GUILayout.Button("Login") || (Event.current.type == EventType.keyDown Event.current.character == '\n'))
{
AddEventListeners();
smartFox.Connect(serverName, serverPort);
}
GUILayout.EndArea();
}
}
private void SetupRoom(string roomName){
if(smartFox.GetRoomByName(roomName)==null){
RoomSettings settings = new RoomSettings(roomName);
settings.GroupId = "game";
settings.IsGame = true;
settings.MaxSpectators = 0;
settings.Extension = new RoomExtension(NetworkManager.ExtName, NetworkManager.ExtClass);
smartFox.Send(new CreateRoomRequest(settings, true, smartFox.LastJoinedRoom));
}else{
smartFox.Send(new JoinRoomRequest(roomName));
}
}
void OnApplicationQuit() {
if (smartFox.IsConnected) {
smartFox.Disconnect();
}
}
}
It should look like this:
- Handling Information between Server and Client
I want to show this based on my InventorySystem(it is not completely done but i will Update this small tutorial)
In the NetworkManager.cs i have added this code for picking up an item.
/// <summary>
/// Request for collecting Items
/// </summary>
public void PickUpRequest(int id,string name){
Room room = smartFox.LastJoinedRoom;
ISFSObject data=new SFSObject();
data.PutInt("id",id);
data.PutUtfString("name",name);
ExtensionRequest request = new ExtensionRequest("pickUp", data, room);// *1
smartFox.Send(request);
}
1* //<— this message with some data will be sended to the server. I have put the id and the name of the item to the data, but you can put in it what you like. Later the item will be checked(is this item movable, is my cmdLevel high enough for picking it up, and get its data like damage or quality from a database…) based on this data.
Now i have created a new c# script called ItemController.cs and put this script on every GameObject which can be picked up. Read the code to know what it does.
using UnityEngine;
using System.Collections;
public class ItemController : MonoBehaviour {
public Texture2D inventoryIcon;
public int id; // the id should be generated, but for testing it is good enough
// Use this for initialization
void Awake () {
gameObject.name = gameObject.name.Replace("(Clone)",""); //The name of the gameobject will be replaced i delete the "Clone".
}
//If the player clicks on the gameobject we will send the request to pickup the item.
void OnMouseUp(){
NetworkManager.Instance.PickUpRequest(id ,gameObject.name);
}
}
Now we need something on the server, what can get this request, do the checks and send an “ok” to the client. I am using eclipse to write the server code.
You can download it here.
Maybe i have to explain first the setup eclipse with the example FPS Demo:
-
if You have installed eclipse, create a new workspace.
-
click with the right-mouse-button to import a new project.
-
now import an existing project
- click on next and brows the “SFS2XFPSextension” folder and the finish button
- it should look like this:
Now you have done the setup and can start with coding.
Add a new Requesthandler to your FPSExtension. I have renamed them so it looks diffrent.
@Override
public void init() {
world = new World(this); // Creating the world model
// Subscribing the request handlers
addRequestHandler("sendTransform", SendTransformHandler.class);
addRequestHandler("sendAnim", SendAnimHandler.class);
addRequestHandler("spawnMe", SpawnMeHandler.class);
addRequestHandler("getTime", GetTimeHandler.class);
addRequestHandler("pickUp",PickUpHandler.class);
addRequestHandler("getInventoryList",InventoryHandler.class);
addEventHandler(SFSEventType.USER_DISCONNECT, OnUserGoneHandler.class);
addEventHandler(SFSEventType.USER_LEAVE_ROOM, OnUserGoneHandler.class);
addEventHandler(SFSEventType.USER_LOGOUT, OnUserGoneHandler.class);
trace("FPS extension initialized");
}
- Create a new java class and call it “PickUpHandler”.
public class PickUpHandler extends BaseClientRequestHandler{
@Override
public void handleClientRequest(User user, ISFSObject data) {
World world = RoomHelper.getWorld(this);
SigCharacter player=world.getPlayer(user);
//Login to database and get item data
//---
SigItem item= new SigItem(data.getInt("id"),data.getUtfString("name"),new Transform(0,0,0,0,0,0),124);
//---
player.AddItem(item);
world.useItem(player, item);
}
}
Now you can get the information of the item you have sended. The information is in the ISFSObject data .
You can get the id :
data.getInt(“id”)
then log in to a database and pick the item and send the whole information of the item to the client.
(I am a hobby programmer so i do not know if this is the best method.)
- then you can add this item to a List and you have got your inventory List.
- now you can code a request to get the inventory List the same way.
Add a Request in the NetworkManager.cs
/// <summary>
/// Request for the InventoryList
/// </summary>
public void InventoryRequest(){
Room room = smartFox.LastJoinedRoom;
ExtensionRequest request = new ExtensionRequest("getInventoryList", new SFSObject(), room);
smartFox.Send(request);
}
Send Request to the server
using UnityEngine;
using System.Collections;
public class InputHandler : MonoBehaviour {
void Update () {
// I: Inventory
if (Input.GetKeyUp(KeyCode.I))
{
NetworkManager.Instance.InventoryRequest();
}
}
}