开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

蛮牛译馆

关注:481

当前位置:游戏蛮牛 技术专区 蛮牛译馆

查看: 646|回复: 12

[Unity教程] 多人在线游戏开源框架Foundation

[复制链接]  [移动端链接]
7日久生情
2945/5000
排名
1204
昨日变化
5

31

主题

523

帖子

2945

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
133683
好友
41
蛮牛币
5939
威望
0
注册时间
2016-1-6
在线时间
579 小时
最后登录
2017-1-20

专栏作家蛮牛译员活力之星锦衣玉食

QQ
发表于 2016-12-14 15:33:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 CloudHu 于 2016-12-14 15:55 编辑
[size=10.5000pt]

封面

封面

Foundation Wiki


Htc Vive开发者联盟 胡良云(CloudHu)特别翻译



原文:http:·//mmofoundation.com/Wiki


关于Foundation
CloudHu:这是我在研究多人在线游戏时在Github上发现的MMO解决方案,于是我决定将其开发文档翻译成中文以供有需要的童鞋学习;在研究源码的过程中,我又对服务器这一块产生了兴趣,于是在完成这份开发文档后先后研究了UNet和PUN,最终选择了PUN进行深入学习,当然也翻译了五百多页的教程和开发文档,我会在后面陆续分享给大家;另外就是关于论坛搞了一个“2016年度游戏蛮牛最受欢迎专栏作家评选”的活动,希望大家可以投我一票,这应该是对我创作的一种认可,谢谢!最后在说下我即将出版的关于VR游戏开发书籍,大概是2017年一月份出版,还是出版后再说吧。
这里提供Foundation的源码下载百度云盘链接:        http://pan.baidu.com/s/1o7DvQFg
附件再带一个我明年想要发起的一个开源项目,基于PUN和Foundation的MMO,这个项目主旨在于提供一个对多人在线游戏有兴趣的开发者之间可以相互学习的项目。该项目是非盈利项目,想要了解的朋友可以下载PDF!
下面开始Foundation正文内容:

Foundation是由Nicholas Ventimiglia2015年将其做为一个加速游戏开发的工具集创造的。这个启动工具包被设计来做一个多人在线游戏(MMO,Massively Multiplayer Online)要做的一切,除了游戏玩法本身。在这个项目中作者沁入了一年多的心血,如果你需要帮助,可以尽管在http://mmofoundation.com/Feedback联系我。
网页播放器演示
多人游戏大厅:http://mmofoundation.com/Wiki/Player
如图1.0.0所示,点击链接就可以试玩多人游戏大厅的样本!
MMO大厅.png

1.0.0 多人在线游戏大厅演示
下载
MvvM(即Model-View-ViewModel 架构设计模式)工具包和多人在线游戏大厅:        http://u3d.as/content/avarice-online/foundation/6Nd
Unity官方资源商店的插件包含除了Cloud(云储存)之外的一切! 其中不仅仅有客户端,还有一个Asp.net MVC架构的服务器专业作为数据服务器。
客户文档
终端http://mmofoundation.com/Wiki/Doc/Terminal
Terminal是一个用来调试应用的基于UGUI的控制台窗口。

异步任务http://mmofoundation.com/Wiki/Doc/Tasks
Async Tasks是一个受任务并行库启发而特意为Unity3d制作的一个工具库。

多语言http://mmofoundation.com/Wiki/Doc/Localization
Localization本地化服务提供UI元素和字符串的翻译需求。

数据绑定http://mmofoundation.com/Wiki/Doc/Databinding
Databinding(数据绑定)是一种来连接你的UI小部件(按钮、输入文本、列表)视图模型机制。

信使http://mmofoundation.com/Wiki/Doc/Messenger
Messenger是一个用来传送事件(消息)静态应用程序服务。

注射器http://mmofoundation.com/Wiki/Doc/Injector
Injector是一个类似于GameObject.Find的用来解决依赖关系静态应用程序服务。

大厅:http://mmofoundation.com/Wiki/Doc/Lobby
即网页播放器所演示的多人在线游戏大厅,这个Lobby(大厅)系统相当于是一个快速的多人游戏原型,只需要稍加改造就可以使用。

云客户端http://mmofoundation.com/Wiki/Doc/CloudClient
Cloud Client是一个易用的负责和Foundation服务器通信的API(应用程序界面/接口 Application Program Interface的首字母缩写) 。

云服务器http://mmofoundation.com/Wiki/Doc/CloudServer
Cloud Server一个Asp.net MVC架构的服务器专业作为Unity3d数据服务器。



命令行窗口 | Terminal
Foundation Terminal (v4.0)
Nicholas Ventimiglia | AvariceOnline.com
游戏内置调试命令行窗口这个库的目的是提供一个测试低级库和游戏时调试的UI界面(如图1.0.1所示)。它是通过使用UGUI创建的,并且适用于Unity3d 5.x版本!
Terminal.gif

1.0.1 命令行窗口UI界面
[size=10.5000pt]ü [size=10.5000pt]它可以打印许多类型的带颜色编码的日志
ü 挂钩到Debug.Log
ü 一个用来测试方法的命令按钮栏
ü 一个可选的输入处理(文本处理器)文本输入
ü `(键盘第二行的一个按键)快捷键来隐藏和关闭

设置        直接把Terminal预设拖拽到你的场景中即可。
使用案例// Write写入
    Terminal.Log("blag blah");
    Terminal.LogError("blag blah");
    Terminal.LogSuccess("blag blah");
    Terminal.LogWarning("blag blah");
    Terminal.LogImportant("blag blah");
    // Wired to Application Log 连接到应用程序日志
    Debug.Log("blah");
// Register button commands. (Do this in Awake)
// 注册按钮命令。(在Awake方法里面做)
    Terminal.Add(new TerminalCommand
        {
            Label = "Main",
            Method = MainTest
        });

    void MainTest()
    {
       // Run When Clicked 当被点击时运行
    }

// Register new Text Processors (invoked when text is submitted)
// 注册新的文本处理器(当文本被提交时调用)
    Terminal.Add(new TerminalInterpreter
        {
            Label = "Chat",
            Method = ChatExample
        });

    void ChatExample(string text)
    {
       // Run When inputted        当输入时运行
    }


异步任务 | Async Tasks
Foundation Tasks (v4.0) 3/6/2015
Nicholas Ventimiglia | AvariceOnline.com
异步任务库 | Unity3d Async Task LibraryAsync Tasks是一个受任务并行库启发而特意为Unity3d制作的一个工具库。支持运行和等待动作在后台线程中运行。支持在协程(协同程序 | coroutines)运行和等待。支持协程返回结果和异常消息。
[size=10.5000pt]ü [size=10.5000pt]支持任务在主线程、后台线程或者作为协程运行。
[size=10.5000pt]ü [size=10.5000pt]任务支持返回结果。
[size=10.5000pt]ü [size=10.5000pt]等待你的任务在协程中完成或者作为一个线程阻塞调用。
[size=10.5000pt]ü [size=10.5000pt]优雅的异常处理(有缺点吗?)
[size=10.5000pt]ü [size=10.5000pt]适用于Windows, Mac, Ios, 系统平台
ü WebGL上可能会有问题,因为WebGL不支持线程(但是协程应该会顺利运行)
[size=10.5000pt]
动态链接库(Dll,Dynamic Link Library的首字母缩写)的用途 | Dll's forDesktop, , iOS, Android, Windows Store

结构 | Structure· "Foundation Tasks"文件夹包含一个非常基础的案例
· "Foundation.Tasks"文件夹包含该插件的源代码
[size=10.5000pt]
设置 | SetupFoundation.Tasks.dll拖拽到你的插件文件夹下即可。

用法 | Usev 运行 | Run任务里面有一个静态的工厂“Run”方法,这个方法会创建一个新的在开始状态的任务。该方法重写了每一种正常情况。你也可以自己构造一个任务并自行启动它。
v 策略 | Strategy任务有很多你可以选择的策略:
-在后台线程运行
-通过任务管理器在协程中运行
-在当前线程运行
-在主线程运行
-运行一个自定义策略
如果你想要手动设置任务的状态、结果和异常,这些策略会非常有用。
v ContinueWithContinueWith是一个允许你在任务完成后执行一段代码的扩展方法。这种扩展方法配合协程策略作为一种填充结果属性的方式是很有用的。你可以链接多个ContinueWith
v 等待 | Wait[size=10.0000pt]· [size=10.5000pt]Wait会停止线程直到任务完成。仅在后台线程中调用它。不要在主线程中调用它!
[size=10.0000pt]· [size=10.5000pt]WaitRoutine是一个你可能启动的协程。该程序会继续直到任务完成。在主线程中使用它。
v 任务管理器 | TaskManager任务管理器是一个Monobehaviours,将任务和Unity对接。它负责在主线程上执行和运行协程。你不需要把这个对象添加到你的场景里,它会被自动地添加。
v 异常 | Exceptions简单地抛出一个异常就可以把任务设置成错误状态。异常会被保存在Task.Exception属性中。对于协程你会需要手动设置任务状态和异常(由于协程中的异常处理被限制了)。
//Pass in an action, function, method or coroutine
//传入一个动作,函数,方法或协程
var task = UnityTask.Run(() =>
{
    throw new Exception("I am failure");
});
[size=10.5000pt]
调试 | Debugging我有一个静态标志用来禁用后台线程。这会造成Unity变得有趣(暂停主线程),但是,你会获得一个完整的堆栈跟踪。
    /// <summary>
/// Forces use of a single thread for debugging
/// 强制使用单线程来调试,即禁用多线程
    /// </summary>
    public static bool DisableMultiThread = false;

    /// <summary>
    /// Logs Exceptions 记录异常
    /// </summary>
    public static bool LogErrors = false;
场景示例 | Scenario Example任务是长时间运行的进程,所以你应该在你的代码中的协程中使用任务。就像WWW类一样。
例如,我们来看一个登录任务:
public class AccountMenu : Monobehaviour    {
    // run on instance startup         在实例启动时运行
    IEnumerator Start(){
        // returns a UnityTask<bool> 返回一个UnityTask<bool>
        var task = AccountService.Login();

        // wait for the task to finish        等待任务完成
        yield return StartCoroutine(task.WaitRoutine());
        // 通过task.IsFaulted来判断任务执行状态(true=任务执行发生错误)
        if(task.IsFaulted)
            // handle fault         处理错误
        else
            // handle success        处理成功

    }
}

上面的案例中,AccountService会返回一个任务UnityTask<bool>在内部它可以是一个在后台线程中运行的动作或一个在Unity线程上的协程。
public class AccountService     {
    public UnityTask<bool> Login(){
        // run in background thread | 在后台线程中运行
        return UnityTask.Run(LoginInternal);
        // or run in unity thread as a coroutine
        //或在Unity线程中作为一个协程运行
        return UnityTask<.RunCoroutine<bool>(LoginInternal2);
    }

    bool LoginInternal(){
        // do work | 在后台线程中进行登录
    }

    IEnumerator LoginInternal2(UnityTask<bool> task){
        // do work | 在Unity线程中作为协程登录
        // manually set result / state | 手中设置结果/状态
    }
}

自定义策略案例 | Custom Strategy Example当你想要返回一个没有包装一个动作或协程的任务时自定义策略就可以派上用场了。下面是两个例子:
完整性检查失败 | Failed Sanity Check例如,如果该方法在进行完整性检查时失败了,我会返回一个自定义失败状态的任务,并手动设置异常消息。我认为这比旋转一个后台线程并抛出要开销低。
void Login(string username){
    return new UnityTask(TaskStrategy.Custom) {
        Status = TaskStatus.Faulted,
        Exception = new Exception("Invalid Username")
    };

    //or extension method | 或者扩展方法
    return Task.FailedTask("Invalid Username");
}

返回一个没有包装方法的任务 | Returning a Task without wrapping a method当我需要返回一个任务,但是内部方法使用一个任意回调函数(例如在使用UnityNetworking的情况)时,我也会使用自定义策略。
UnityTask<bool> ConnectTask;
void Awake(){
    ConnectTask = new UnityTask<bool>(TaskStrategy.Custom);
}
UnityTask<bool> ConnectToServer(HostData username){
        ConnectTask.State = TaskState.Running;
    // Do Unity Connect Logic here | 在这里写Unity 网络连接的逻辑
// Consumer will 'wait' untill this server fails/successes the task
//用户会‘等待’直到服务器 失败/成功 执行该任务
    return ConnectTask;
}
        //成功 执行该任务
void OnConnectedToServer(){
    ConnectTask.Result = true;
    ConnectTask.State = TaskState.Success;
}
// todo fail and timeout for the connect task
//待办:联网任务失败并连接超时

厨房水槽案例 | Kitchen Sink Examples// Assume running from a coroutine | 假设从一个协程运行
//Turn an action into a waitable background task
//把一个动作变成一个可等待的后台任务
var task = UnityTask.Run(() =>
{
    //Debug.Log does not work in | Debug.Log在这里无效
    Debug.Log("Sleeping...");
    UnityTask.Delay(2000);
    Debug.Log("Slept");
});
//wait for it | 等待
yield return StartCoroutine(task.WaitRoutine());
// check exceptions | 检查异常
if(task.IsFaulted)
    Debug.LogException(task.Exception)
//Valid if this method returned something | 如果这个方法返回什么则有效
//var result = task.Result;
// Run a Task on the main thread (great for networking!)
//在主线程上运行一个任务(对网络来说很好)
UnityTask.RunOnMain(() =>
{
    Debug.Log("Sleeping...");
    UnityTask.Delay(2000);
    Debug.Log("Slept");
});
// Run a coroutine as a tasks | 运行一个协程作为任务
UnityTask.RunCoroutine(RoutineFunction());

IEnumerator RoutineFunction(){
    Debug.LogOutput("Sleeping...");
    yield return new WaitForSeconds(2);
    Debug.LogOutput("Slept");
}
// Run a background task that then runs a task on the main thread
//运行一个后台任务,这个任务再在主线程上运行一个任务
UnityTask.Run(() =>
{
    Debug.Log("Thread A Sleep");
    UnityTask.Delay(2000);
    Debug.Log("Thread A Awake");
    UnityTask.RunOnMain(() =>
    {
        Debug.Log("Thread B Sleeping...");
        UnityTask.Delay(2000);
        Debug.Log("Thread B Slept");
    });

    Debug.Log("Thread A Done");
});     
// Run a coroutine with a result   | 运行一个带结果的协程
UnityTask.RunCoroutine<string>(RoutineFunction());

IEnumerator RoutineFunction(UnityTask<string> task){
//manually set State / Exception / Result
//手动设置 状态/异常/结果
}



多语言 | Localization
Foundation Localization (v4.0) 3/8/2015
Nicholas Ventimiglia | AvariceOnline.com
Localization本地化服务提供UI元素和字符串的翻译需求。
l 它支持csv格式
l 它通过文件夹的方式来划分语言:例如,Resources/Localization/English
l 它支持多文件:例如,Resources/Localization/English/LobbyStrings.txt
l 通过询问关键字来翻译字符串。LocalizationService.Instance.Get("key");
l 使用[Localized]注解来自动更新字符串
l 内建Yandex翻译器(就像谷歌翻译一样,Yandex是俄罗斯第一大搜索引擎)
l TextBinder文本绑定支持UGUI
l 支持Unity3d 5.x版本  
设置 | Setup· FullSerializer串化器是必备的。它位于插件文件夹。
(https://github.com/jacobdufault/fullserializer)
· LocalizationService可编写脚本的对象位于:/Resources/
· CSV格式的语言文件放进:
/Resources/Localization/{LanguageName}/{filename}.txt
Csv文件案例 | Example Csv FileEamples.ExampleString1, Hello Friend
Eamples.ExampleString2, "Hello, Will you End Me ?"
Eamples.ExampleString3, My Cat is pretty lol.

Yandex翻译器 | Yandex Translator编辑器窗口位于Tools/Foundation/Yandex Translator之下。添加你的API关键字(免费)https://api.yandex.com/key/form.xml?service=trnsl选择你想要支持的语言并按下那个神奇的按钮。
使用 | UseUgui文本 | uGUI Text只需文本字段中点击LocalizedText monobehaviour选择你想要的文件并选择你想要的关键字。你的UI文本元素将会立即被翻译。
代码绑定 | Code Behind    /// <summary>
    /// Example of how to localize your code behind
        ///如何本地化你的代码绑定的案例        
    /// </summary>
    [Localized("Eamples.ExampleString1")]
    public static string ExampleString = "Hello Friend";

    public void Awake()
    {
        //Localizes the example string | 本地化案例字符串
        LocalizationService.Instance.Localize(this);

       //alt way of getting strings | 获取字符串的另一种方法
        var s = LocalizationService.Instance.Get("Eamples.ExampleString1");

        // auto magical string updates | 自动更新字符串
        var s2 = ExampleString;
    }

改变语言 | Changing the language    /// <summary>
    /// Example of how to change the language | 如何改变语言的案例
    /// </summary>
    public void RandomLanguage()
    {
        var languages = LocalizationService.Instance.Languages;

        LocalizationService.Instance.Language = Random(languages);
    }

语言改变事件 | Language Change Events        private void Awake()
        {
            LocalizationService.OnLanguageChanged += OnLocalization;
        }

        private void OnDestroy()
        {
            LocalizationService.OnLanguageChanged -= OnLocalization;
        }

        public void OnLocalization(LocalizationService localization)
        {
            GetComponent<Text>().text = localization.GetFromFile(File, Key, label.text);
        }


数据绑定 | Databinding
Foundation Databinding (v4.0) 3/8/2015
Nicholas Ventimiglia | AvariceOnline.com
Databinding(数据绑定)是一种来连接你的UI小部件(按钮、输入文本、列表)‘视图脚本’的机制。这个策略对于Model-View-ViewModel架构(模型-视图-视图模型,即MVVM设计模式,在C#世界中是非常流行的)来说是必要的。在MVVM中你的视图层的属性、字段和方法可以被UI元素观察到,并且任何对你的视图层的改变都被通知到UI元素,这样它们才能自动更新。
u 支持继承、接口、结构体和使用动态链接库DLL
u 绑定到Monobehaviours和普通的CLR(Common Language Runtime公共语言运行时,不会有改变通知)对象
u Foundation.Databinding.Model是一个动态链接库DLL,所以你可以把你的游戏模型放在一个类库里面。
u 绑定到方法、字段、属性或协同程序
u 使用IObservableModel可观察模型接口来取代IPropertyNotifyChangeIObservableModel包含改变的值(就在改变了属性名旁边),从而防止额外的反射调用。
支持平台 | PlatformsDesktop, Webplayer, Android, iOS, Windows Store
桌面,网页播放器,安卓,IOS,Windows应用商店

依赖 | Dependencies· FullSerializer Json Library
https://github.com/jacobdufault/fullserializer
· Foundation.Tasks Async Library
https://github.com/NVentimiglia/Unity3d-Async-Task
· Foundation.Localization Translation Library
https://github.com/NVentimiglia/Unity3d-Localization
· Localization本地化可以通过使用NoLocalization指令来被省略
· Foundation.Injector 在注释中被提到过。它不是必需的,但是我个人使用它来避免在编辑器中引用我的其他组件。
https://github.com/NVentimiglia/Unity3d-Service-Injector
模型逻辑 | Model Logic建议从ObservableBehaviour可观察行为类中继承Monobehaviours、从ObservableObject可观察对象类中继承你的公共语言运行时对象。这些类实现了IObservableModel可观察模型接口,并包含了许多辅助方法来快速发布你的视图改变。
案例模型 | Example Model下面是一个仅有一个可观察属性的案例模型。当这个属性改变视图(或任何别的监听)将会收到改变事件并有机会自己更新。
public class MyModel : ObservableObject {
        private int _myProperty;
        public int MyProperty
        {
            get { return _myProperty; }
            set
            {
                // Prevent Stack Overflow in two way binding scenarios
               //在双向绑定场景中防止堆栈溢出
                if (_myProperty == value)
                    return;

                _myProperty = value;

                // Notify Listeners | 通知监听器
                NotifyProperty("MyProperty", value);
            }
        }
}

模型vs 视图模型 | Models vs ViewModelsObservableBehaviour扩展派生出来的类必须要在场景中创建一个你的视图实例(因为它是一个MonoBehaviour)。 这有利于在你的场景视图中设置属性字段。
ObservableScriptableObject派生必须要在你的编辑器中创建一个实例(因为它是一个ScriptableObject)。这有利于让你在你的编辑器中设置属性。
ObservableObject类中扩展是我对大多数数据对象的个人选择(高分段,个人信息,等等)。它是一个轻量级的不依赖于UnityEngine的公共语言运行时对象。
视图逻辑 | View Logic一旦你完成了你的模型定义,并使用Unity的Ugui的UI框架来搭建好你的视图模型,就是将它们连接在一起的时候了。
绑定语境 | Binding Context绑定语境是为了将你的模型粘合到你的视图元素上。一旦设置了子绑定,就会更新一系列属性来绑定。
这个脚本位于你的UI根部并用三种模式中的一种操作。
        - 行为绑定 | MonoBinding
        视图模型是一个MonoBehaviour(或可观察行为)。拖拽该行为到你的编辑器字段中去绑定它。
        - 模拟绑定 | MockBinding
        视图模型是一个晚绑定。当你想要设置子绑定的数据类型,同时又并不是设置模型实例时,使用这个选项。示例使用包括列表控件,这里你可能知道列表项的类型但实际项目实例在运行时设置。
        - 属性绑定(层级绑定) | Property Binding (Hierarchy Binding)
        这允许你将一个模型索引到另一个模型内。举例来说MyModel.MyUser.MyNameMyModel是一个父类视图模型,MyUser是一个子模型,MyName是多数子模型的一个属性。
绑定器 | Binders绑定器位于一个绑定语境之下并挨着与之相关的UI元素。当绑定语境被设置绑定器会从模型中更新一系列的有效属性和方法。
有许多种绑定器,包括InputFieldBinderButtonBinderListBinderImageBinders我相信我有大多数主要的控制组件了。如果你需要自定义绑定器,可以从BinderBase继承。如果你觉得我忽略一个非专用的绑定器,请告诉我,我会创造它。
使用绑定器是直接了当的。只需拖拽该脚本到你需要绑定的控制组件上。举例来讲,如果你想要数据绑定一个输入字段也需要把包含InputFieldBinder

音频管理器 | AudioManager我在这个库里面包含了一个音频管理器。音频管理器用音频层扩展了Unity的音频系统。这允许玩家通过音频层来调整音频音量(音乐、声音,等等)。
· 音频2D监听器 | Audio2DListener : 依附在主摄像机上用来为UI元素孵化声源(Audio Source组件)。
· 音频2D源 | Audio2DSource : 为全局(UI)声音,和使用AudioSource组件一样的用法。
· 音频调节器 | AudioRegulator : 附属于AudioSources上通过音频层(音乐、声音,等等)来调节音量。
· 音频管理器 | AudioManager : 一个公共语言运行时管理器,用来调停音频层音量的变化。


信使 | Messenger
Foundation Messenger (v4.0) 3/6/2015
Nicholas Ventimiglia | AvariceOnline.com
Messenger信使是一个以松散耦合的方式传送事件(消息)静态应用程序服务任何对象可以通过信使被发布并通过应用被方法(或协程)处理。
² 支持对象、结构体、枚举和接口。
² 支持缓存。这允许以发布之后订阅再然后接收的顺序来收发消息。这对于那些像身份验证一样的一次性消息来说是有用的。
² IMessengerObject接口来添加一个Publish()扩展方法到你的消息。
² 支持[Subscribe]注解。使用这个注解解锁Subscribe(object)辅助方法。这个辅助方法允许自动地订阅所有修饰过的方法。
² 支持协程处理事件。
[size=10.0000pt]·
设置 | Setup确保对应的文件在你的项目中存在即可。
使用 | Use订阅 | Subscribing订阅是信使的布线方法。该方法需要一个它正在处理的消息类型作为参数。当一个合适类型的消息被发布该方法会被调用。
public class MyHandler: MonoBehaviour
{
    void Awake()
    {
       // Subscribe using the [Subscribe] annotation
        //使用[Subscribe]注解来订阅
        Messenger.Subscribe(this);

        // Subscribe manually | 手动订阅
        Messenger<MessageType>.Subscribe(MyHandler);

        // Subscribe manually | 手动订阅
        Messenger<MessageType>.SubscribeCortoutine(MyCoroutineHandler);
    }

    void OnDestroy()
    {
        // Unsubscribe using the [Subscribe] annotation
        //使用[Subscribe]注解来退订
        Messenger.Unsubscribe(this);

       // Unsubscribe manually | 手动退订
        Messenger<MessageType>.Unsubscribe(MyHandler);

        // Unsubscribe manually | 手动退订
        Messenger<MessageType>.UnsubscribeCortoutine(MyCoroutineHandler);
    }

    [Subscribe]
    public void MyHandler(MessageType arg);

    [Subscribe]
    public IEnumerator MyCoroutineHandler(MessageType arg);
}
发布 | Publishing发布就是发送一个消息到订阅成员。
public class MyPublisher: MonoBehaviour
{
    void Awake()
    {
        var message = new MessageType();

        // publish using the IMessengerObject Extension Method
        //使用IMessengerObject扩展方法来发布
        message.Publish();

        // publish Manually | 手动发布
        Messenger.Publish(message);
    }
}
缓存 | Caching消息可以被缓存。当缓存时消息会被保存并晚发给用户。
// Cache the message | 缓存消息
[CachedMessage]

// or

// Cache the message and clear the cache of old messages of the same type
//缓存消息并清除同类型的旧消息
[CachedMessage(OnePerType=true)]

public class MessageType : IMessengerObject
{

}


注射器 | Injector
Foundation Injector (v4.0) 3/6/2015
Nicholas Ventimiglia | AvariceOnline.com
注射器是一个用于解决依赖的静态应用服务,类似于GameObject.Find对象可以作为“输出”被添加到注射器中,然后这些输出可以被自动“输入”到用户那里。注射器支持集合、抽象类型、惰性延迟加载和[Import]注解。
u 支持继承一个接口或基类来解决依赖。
u 支持字符串关键字。用一个神奇的字符串来解决依赖。
u 支持GetFirstGetAll获取所有输出的依赖类型。
u 支持[Import]注解。使用这个注解来解锁Import(object)辅助方法。这个辅助方法允许自动进口所有被修饰的成员。
u 用户可以订阅。一旦订阅进口的成员就会在从注射器添加或移除物品时被更新。这允许一劳永逸地在Awake方法中完成所有设置。
u 在单例或ScriptableObjects中使用[InjectorService]注解,并且它们会在你需要的时候被加载。
[size=10.0000pt]·
使用 | Use输出 | Exporting输出是添加实例到注射器的过程,从而来别的地方被输入使用。//可选,添加一个关键字符串[Export("MagicString")]
// This export may also resolved by asking for MyExport, MonoBehaviour or IMyExport in the GetAll or GetFirst method.
//这个输出也可以通过请求MyExport、MonoBehaviour或IMyExport中的GetAll或GetFirst方法来解决
    public class MyExport: MonoBehaviour, IMyExport
    {
        void Awake()
        {
            // add this to the injector | 添加这个到注射器
            Injector.AddExport(this);
        }
        void OnDestroy()
        {
            // Remove this from the injector | 从注射器移除
            Injector.RemoveExport(this);
        }
}

输出可编辑对象 | Exporting Scriptable ObjectsInjectorInitialized注解自动初始化应用程序服务。你可以使用它来确保注射器服务被加载。仅仅被用来修饰你的服务。公共语言运行时服务和可编辑对象都被支持。尽管是可选的,仍然建议你创建一个如下所示的静态的存取器属性(单例)。
// Initialized at runtime by the injector [InjectorInitialized("ResourceName")]
//通过注射器[InjectorInitialized("ResourceName")]在运行时初始化
public class MyScriptableObject : ScriptableObject{
       // optionally | 可选地
        private static MyScriptableObject _instance;
        public static MyScriptableObject Instance
        {
            get { return _instance ?? (_instance = Create()); }
        }

        static MyScriptableObject Create()
        {
            return Resources.Load<MyScriptableObject>("ResourceName");
        }
}

输出单例 | Exporting Singletons // Initialized at runtime by the injector | 通过注射器在运行时初始化
[InjectorInitialized]
public class MyService {
    public static readonly MyService = new MyService();
}

输入 | Importing输入是消耗输出的过程。
    public class MyConsumer: MonoBehaviour
    {
        // Import using the Key | 使用关键字输入
        [Import("MagicString")]
        public IMyExport Import1 { get; set; }

       // Import many using the Key | 使用关键字输入多个
        [Import("MagicString")]
        public IEnumerable<IMyExport> Import2 { get; set; }

        // Import first by type | 输入该类型的第一个
        [Import]
        public IMyExport Import3 { get; set; }

       // Import all by type | 输入所有的该类型
        [Import]
        public IEnumerable<IMyExport> Import4 { get; set; }

        void Awake()
        {
            // Asks the Injector to resolve dependencies now
           //要求注射器立即解决依赖
            Injector.Import(this);

            // or
            // Asks the Injector to resolve dependencies now and later
            // Members will be updated if items are added / removed from export
        //要求注射器立即解决依赖,之后如果从输出中添加或移除物品成员会被更新
            Injector.Subscribe(this);
        }

        void Start()
        {   
            // Get import manually | 手动输入
            var manualImport = Injector.GetFirst<IMyExport>();
            // Get imports manually | 手动输入
            var manualImports = Injector.GetAll<IMyExport>();
        }

        void OnDestroy()
        {   
             // Removes subscription | 退订
              Injector.Unsubscribe(this);
        }
    }



游戏大厅 | Lobby
Foundation Lobby (4.0 3/15/2015)
Nicholas Ventimiglia | http://unity3dfoundation.com
Lobby(大厅)系统有你需要制作一个快速的多人游戏原型的一切。
l 基于、Ugui和Foundation.Databinding的平滑UI构建
l 地图选择、可选菜单、高分榜菜单和多玩家(大厅)视图
l 可重用的对话包括确认、输入、选择和通知
l 内置的多玩家大厅支持UnityNetworkPUN(即Photon Unity3d Networking的首字母缩写,是流行的网络服务器框架)
l 丰富的玩家信息包含小头像和积分数据
l 可选的账户服务包括登录、注册和密码恢复
l 可选云服务支持:Foundation Cloud C# Http Web Server (Asp.net MVC)
依赖 | Dependencies大厅依赖许多其他包。这些包都是开源的,包括:
· FullSerializer Json
https://github.com/jacobdufault/fullserializer
· Foundation.Tasks 异步库
https://github.com/NVentimiglia/Unity3d-Async-Task
· Foundation.Localization 翻译库
https://github.com/NVentimiglia/Unity3d-Localization
· Foundation.Injector 反向控制元件容器:
https://github.com/NVentimiglia/Unity3d-Service-Injector
· Foundation.Messenger 事件发布者:
https://github.com/NVentimiglia/Unity3d-Event-Messenger
· Foundation.Databinding 数据绑定和MVVM工具包:
https://github.com/NVentimiglia/Unity3d-Databinding-Mvvm-Mvc
可选 | [Optional]
· Foundation.Cloud 可选的Unity3d兼容数据库和网页服务器(Asp.net MVC c#)
http://unity3dfoundation.com/
· Photon Cloud 基于多玩家网络的photon云:http://exitgames.com/
项目结构 | Project Structure· 插件 | Plugins
· 基地 | Foundation
o 大厅 | Lobby
o 脚本 | Scripts
§ 模型 | Models : 大厅系统的核心逻辑。包含对象、消息接口和管理器。
§ 提供器 | Providers : 包含可插入的服务(网络和库的接口实现)
§ 视图 | Views : 菜单脚本和其他和表现层相关的东西
o 资源 | Resources
§ 动画 | s
§ 本地化 | Localization : Csv本地化文本
§ 头像 | Portraits :头像服务所使用的图片。自由添加/移除贴图。
§ 预设 | Prefabs
§ 特效 | Sfx
§ 精灵 | Sprites
设置和配置 | Setup and Configuration一旦这个包被解压,你需要做一些轻松的配置
· 在主菜单上运行 Tools/Foundation/Instantiate ScriptableObjects
o 这会确保静态可编程对象服务被初始化
· /Assets/Resources/MapService 路径下配置地图可编程对象
o 地图 | Maps : 在地图选择view.ed中展示的场景数组
· 打开/Assets/Lobby/Lobby.unity路径下的场景文件,选择和配置_LobbySystem游戏对象
o 多客户端模式 | MultiClientMode会在每一次加载时强制刷新用户。游戏数据将不会被保存。我在开发阶段使用这个模式,因为它让我可以运行多个客户端实例,同时每一个客户端都有自己的账户
o 大厅场景 | LobyScene 主大厅关卡的名称。当回到大厅时加载。
o 分大厅场景 | LobyScenePartial 分大厅关卡名称。如果大厅是部分的时候使用,并在其他关卡后台加载。
o 根节点 | Roots Canvas, Services和其他应该被LobbyController激活的游戏对象。这些对象在编辑器时应该是闲置的,因为如果它们是激活状态在场景加载时可能会出问题。
· 可选的Photon云配置
o Unity打包安装Photon
o 在主菜单打开Edit/Project Settings/Player 并聚焦到Inspector窗口。
o Scripting Define Symbols 里添加标签Foundation_Pun这将会显示 Pun Network Provider
o 打开LobbyScene扩展_LobbySystem 游戏对象
o 移除 uNet 游戏对象(LobbyController的子对象)
o 添加一个新的游戏子对象 pNet 并添加PhotonNetworkProvider脚本
o 用新增的pNet 对象更新LobbyController.Roots属性(取代uNet 对象)
[size=10.5000pt]
[size=10.0000pt]· 可选的[size=10.5000pt]配置基地云
o 安装 Foundation Cloud Package
o 在主菜单打开Edit/Project Settings/Player 并聚焦到Inspector
o Scripting Define Symbols 里面添加标签Foundation_Cloud.
o 新的选项会出现在 LobbyController
o 启用云 | EnableCloud 会激活云。在开发测试时可以把这个关掉。
o 启用离线模式 | EnableOfflineMode 将会在连接云服务器失败时启用离线游戏如果客户端必须连接服务器且本地缓存备份的玩家信息/帐号不可用,把这个打开。
这个包是非常不错的。只需将任何游戏代码放在对应的场景即可。
脚本指南 | Scripting GuideFoundation很大且吓人。我已经尝试使用一个质量架构来最小化代码量。即监听模式和model-view-viewmodel设计。
MVVM设计模式允许将业务逻辑(模型)从视觉展示(视图)中分离。换句话讲你很可能完全不需要编辑代码。推荐你只需修改展示层,也就是你只需修改场景视图中的游戏对象和UI元素。
有一个例外是PlayerInfo对象,该对象使用一个局部类来方便自定义属性。
最后,在我们开始之前请阅读其他模型(收录的)的文档。特别需要熟悉的是异步任务、数据绑定和信使模型,因为它们是大厅最为依赖的模型。
大厅控制器 | LobbyController大厅控制器是场景启动对象。下面是它的工作流:
· 觉醒 | Awake
o 确保它是唯一实例,如果不是,自杀。
o 确保注射器Injector和任务管理器TaskManager被初始化。
o 初始化玩家信息库PlayerInfoRepository和帐号服务AccountService
o 订阅信使Messenger和注射器Injector
o 展示SplashUnity程序启动时的那个一闪,激活Root子对象
o 开始异步准备 'ReadyAsync'
· 异步准备(协程) | ReadyAsync (Coroutine)
o 展示闪屏Splash
o 准备帐号服务AccountService
o 如果没有帐号缓存展示注册视图
o 准备玩家库PlayerRepository
o 如果没有玩家数据缓存,展示名称和头像选择视图
o 如果你有自定义服务可以放在这个位置
o 发起场景开始SceneStarting消息 (通知监听:场景已被加载)
o 如果是主大厅场景就展示主菜单MainMenu
o 隐藏闪屏Splash
· 关卡已被加载 | OnLevelWasLoaded
o 发起场景开始SceneStarting消息 (通知监听:场景已被加载)
o 如果是主大厅场景就展示主菜单MainMenu
· 应用程序暂停 | OnApplicationPause
o 如果暂停并已联网,断开联网并返回大厅场景。
o 如果在断开联网后取消暂停,调用准备Ready
o 发起暂停消息PauseMessage (通知监听器:应用程序暂停)
帐号 | Accounts帐号系统的逻辑位于Lobby/_Scripts/Models/LobbyAccount.cs之下。不推荐你修改它,除非你一个非常高级的开发者。
· 大厅帐号LobbyAccount对象记述用户的身份验证。它包含三个属性:
o Id 随机生成的唯一id
o Email 用户提交的邮箱地址
o Current 当前使用的大厅帐号LobbyAccount存取器
o Service 当前使用的帐号服务AccountService供应者存取器
帐号服务AccountService使用一个供应者模式。简单地说它是被设计来支持IAccountService的多种实现。特别是有一个MockAccountService用来存储帐号数据到PlayerPrefs (本地的) CloudAccountService使用WWW类来存储帐户数据到网络服务器
如果你愿意写你自己的自定义IAccountService, 很棒!只需从IAccountService继承并实现这个接口,就像其他两个实现一样。记住在LobbyController (awake方法中)设置LobbyAccount.Service静态存取器
玩家 | Players和帐号系统AccountSystem一样玩家系统也追随Model-Provider模式。玩家信息PlayerInfo是玩家的分享信息并且包含他的名称、得分和头像信息。不像Account对象, PlayerInfo被设计来通过使用PlayerInfo局部来自定义。
位于Lobby/_Scripts/MyPlayerInfo.cs 是一个局部类,目的是让你使用自定义字段来为玩家定制化玩家信息。因为该服务在后台使用Json序列化,大多数新的字段或属性会被自动保存。如果你添加一个可观察属性(非自动化属性)请使用[fsProperty]注解。
· 玩家信息PlayerInfo对象描述用户的分享信息
· 静态属性 | Static
o | Repository : 获取和保存玩家信息PlayerInfo的服务。
o 管理器 | Manager : 缓存本地玩家和通过网络分享本地玩家的服务。
o 本地玩家 | LocalPlayer : 本地玩家存取器。
· 身份 | Identity
o 帐号Id | AccountId: 玩家的唯一id。从身份验证获得。
o IsLocalPlayer : 本地玩家LocalPlayer的标志。
· 网络 | Network
o NetworkId : 网络连接NetworkConnection Id (来自PunUnityNetwork)
o IsNetworkLocal : 如果这个玩家源自本地客户端则为True(自己或本地AI)
o IsNetworkAuthority : 如果网络断线、主机或主客户端则为True
o 客户信息 | Profile
o IsAI : 如果是AI玩家则添加到PlayerManager
o Name : 用户名
o Score : 主分值,被用来在排行榜Leaderboard排序。
· 头像 | Portrait
o 头像类型 | PortraitType : 描述头像的数据源 (ResourceWeb)
o PortraitParamater : 数据源参数 (贴图名或Url链接)
o Portrait : Texture2d图片。
o 定制化服务 | Customization
o 随意添加属性到MyPlayerInfo
o 添加[fsProperty]注解到非自动化属性
o PartialCopyTo 方法更新新的属性。
玩家库PlayerRepository使用供应者模式。简单说是被设计来支持 IPlayerRepository多实现。特别是有一个MockPlayerRepository 类用来保存帐户数据到PlayerPrefs (l本地) CloudPlayerRepository 使用WWW类来保存帐户数据到一个网络服务器
如果你愿意写你自己的自定义IAccountService, 很棒!只需从IAccountService继承并实现这个接口,就像其他两个实现一样。记住在LobbyController (awake方法中)设置LobbyAccount.Service静态存取器
玩家定制化服务案例 | Player Customization Examplenamespace Foundation.Lobby.Models
{
// Partial PlayerInfo ready for Customization !
//局部类PlayerInfo随时准备好定制化服务!
    public partial class  PlayerInfo
    {
     // Example Observable Property | 可观察属性案例
     // Note that [fsProperty] is required for observable properties
        //注意这里的可观察属性需要[fsProperty]注解
        private int _teamId = -1;
        [fsProperty("TeamId")]
        public int TeamId
        {
            get { return _networkId; }
            set
            {
                if (_teamId == value)
                    return;
                _teamId = value;
                NotifyProperty("TeamId", value);
            }
        }


    //secondary score | 第二得分
        public int Games { get; set; }        //游戏场次
        public int Wins { get; set; }        //获胜场次
        public int Losses { get; set; }        //失败场次
        public int Kills { get; set; }                //击杀数量

        // CopyTo for partial properties | 复制到部分属性
        public void PartialCopyTo(PlayerInfo info)
        {
            info.Games = Games;
            info.Kills = Kills;
            info.Wins = Wins;
            info.Losses = Losses;
        }

        // Mock Partial Properties | 模拟部分属性
        public void MakeMock()
        {
            Games = UnityEngine.Random.Range(100, 1000);
            Wins = UnityEngine.Random.Range(10, 1000);
            Losses = UnityEngine.Random.Range(10, 1000);
            Kills = UnityEngine.Random.Range(1, 100);
        }
    }
}
网络 | Networking网络服务NetworkService使用一个供应者模式。简单地讲就是被设计来支持对IPlayerRepository接口的多种实现。特别是有一个UnityNetworkService 使用Unity引擎默认的网络堆栈和PhotonNetworkService 使用Photon云。
如果你想要写你自己的自定义INetworkService,很棒!只需从INetworkService派生并实现该接口,就像前两种实现方式那样。记住在LobbyController (awake方法中)设置NetworkContext.Service静态存取器
INetworkService将网络供应者都包装在一起并实现了大多数情况下的逻辑。举例来说,主机和主客户端的概念仅在大厅网络时考虑授权。INetworkService不是要在你制作游戏时被使用,而是作为一个大厅内部组件的接口。



云客户端 | Cloud Client
# Foundation Cloud Client (4.0 3/15/2015)
Nicholas Ventimiglia | http://unity3dfoundation.com
一个云端可做主机的Asp.Net MVC架构特别为Unity3d打造的解决方案
v Asp.Net MVC是一个世界级的C# 4.0开源网络服务器
[size=10.5000pt]v [size=10.5000pt]图示的(Html)开发者和管理员门户
[size=10.5000pt]v [size=10.5000pt]多租户预备,一次安装托管多个游戏
[size=10.5000pt]v [size=10.5000pt]所有服务器的API都有一个Unity3d服务客户端蓄势待发!
[size=10.5000pt]v [size=10.5000pt]账户API有登录、注册、帐号恢复和游客模式
[size=10.5000pt]v [size=10.5000pt]支持知名邮箱来进行帐号恢复和新用户注册(欢迎邮件)
[size=10.5000pt]v [size=10.5000pt]库存API支持动态(无类型)对象
[size=10.5000pt]v [size=10.5000pt]实时Realtime[size=10.5000pt]API集成了实时云消息服务:https://realtime.co/
[size=10.5000pt]v [size=10.5000pt]通过自定义ApiControllers很容易地扩展解决方案
[size=10.5000pt]v [size=10.5000pt]使用Entity Framework实体框架来托管SQL数据库
[size=10.5000pt]v [size=10.5000pt]数据表平滑且规范化使得和Redis、MongoDB或RavenDB可以快速对话!
设置和配置 | Setup and Configuration一旦这个包被解压,你需要做一些轻松的配置
· 在主菜单运行Tools/Foundation/Cloud Settings
o 应用密匙 | Application Key 会在你在服务器上创建应用后出现
o Service URL那里放置你的云端实例链接
o 如果你没有私人实例http://unity3dfoundation 可供测试。
依赖 | Dependencies大厅依赖许多其他包。这些包都是开源的,包括:
· FullSerializer Json
https://github.com/jacobdufault/fullserializer
· Foundation.Tasks 异步库
https://github.com/NVentimiglia/Unity3d-Async-Task
推荐你在继续之前看一下异步任务readme 异步任务Async tasks是一个在后来运行作业的模式并且等待它。任务在基地云端中被重用。
案例 | Example有一个案例场景位于 Foundation/Cloud/Example路径之下,可以参考一下这个场景,因为它在脚本文件中演示了所有可能的操作。
指南 | GuideFoundation云端的代码最好不要被修改。下面,我将会描述包里的主要组件和如何使用它们。
云端会话 | CloudSession云端会话是一个装载用户身份和保持会话的缓存持续是通过使用PlayerPrefs来保持的。CloudSession被内部的所有服务使用(特别是账户服务)并且不能被直接使用。这就是说,可能有必要时不时地读取你的账户。
云端账号 | CloudAccountAccounts / Authentication Service通信的静态服务
/// <summary>
/// Static instance | 静态实例
/// </summary>
public static readonly CloudAccount Instance;

/// <summary>
/// SignIn from cache (remember me) | 缓存登录(记住我)
/// </summary>
/// <returns>true if authenticated | 如果通过验证返回true</returns>
public bool SignIn();

/// <summary>
/// Sign out and clear cache | 登出并清除缓存
/// </summary>
public void SignOut();

/// <summary>
/// Requests a new guest account. Use for 'Skip Sign In' option.
///请求一个新的游客帐号。用在“跳过登录”选项。
/// </summary>
/// <returns>任务</returns>
public Task Guest();

/// <summary>
/// New account created in memory | 在内存中创建新账户
/// </summary>
/// <returns>任务</returns>
public Task SignUp(string email, string password);

/// <summary>
/// Sign in request | 登录请求
/// </summary>
/// <param name="email">邮箱</param>
/// <param name="password">密码</param>
/// <returns>任务</returns>
public Task SignIn(string email, string password);

/// <summary>
/// Update account details | 更新帐号信息
/// </summary>
/// <param name="email">邮箱</param>
/// <param name="password">密码</param>
/// <returns>任务</returns>
public Task Update(string email, string password);

/// <summary>
/// Tells the server to send out an recovery email. This email will contain a reset token. | 告诉服务器发送一封恢复邮件。这封邮件将包含一个重置令牌
/// </summary>
/// <param name="email">邮箱</param>
/// <returns>任务</returns>
public Task Recovery(string email);

/// <summary>
/// Updates the account with a new password. Token from Recovery Email.
///更新帐号密码,令牌来自恢复邮件
/// </summary>
/// <param name="token">令牌</param>
/// <param name="password">密码</param>
/// <returns>任务</returns>
public Task Reset(string token, string password);

/// <summary>
/// Deletes the current account | 删除当前帐号
/// </summary>
/// <param name="email">邮箱</param>
/// <param name="password">密码</param>
/// <returns>任务</returns>
public Task Delete(string email, string password);
云端实时消息 | CloudRealtime实时验证消息服务。Foundation Cloud Server基地云端服务器支持即时通讯服务器验证。这允许你保持你的客户的私人密匙,如果你选择这样的话详情http://realtime.co
/// <summary>
/// Static Instance. | 静态实例
/// </summary>
public static readonly CloudRealtime Instance;

/// <summary>
/// New account created in memory | 在内存中创建新帐号
/// </summary>
/// <returns>Realtime Authentication Token to use | 即时验证口令</returns>
public Task<RealtimeToken> SignIn(Dictionary<string, string[] >channels);
云端查询 | CloudQueryCloudQuery是一个用来构造类似linq方式的数据查询的对象。这允许你很容易地过滤、排序和截断查询的对象集合
使用案例 :
var query = new CloudQuery().WhereGreaterThan("Id", 5).OrderBy("String").Take(5);
///<summary>
/// Where the property contains | 搜索包含某某属性的地方
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereContains(string key, object value);

///<summary>
/// Where the property string value starts with | 搜索以某字符串开头的地方
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereStartsWith(string key, object value);

///<summary>
/// Where the property string value ends with | 搜索以某字符串结尾的地方
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereEndsWiths(string key, object value);

///<summary>
/// Where the property value equals | 搜索与属性值相等的地方
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereEquals(string key, object value);

///<summary>
/// Where the property value does not equal | 搜索不等的
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereNotEquals(string key, object value);

///<summary>
/// Where the (numeric) property value is greater than | 搜索大于的
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereGreaterThan(string key, object value);

///<summary>
/// Where the (numeric) property value is less than | 搜索小于的
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereLessThan(string key, object value);

///<summary>
/// Where the (numeric) property value is greater than or equal to | >=
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereGreaterThanOrEqualTo(string key, object value);

///<summary>
/// Where the (numeric) property value is less than or equal to | <=
/// </summary>
/// <param name="key">property name | 属性名</param>
/// <param name="value">String, Number | 字符串、数字</param>
public CloudQuery<T> WhereLessThanOrEqualTo(string key, object value);

///<summary>
/// Sorts with the highest value first | 从大到小排序,即降序排列
/// Orders the selection by the property | 通过属性排序
/// </summary>
/// <param name="key">property name | 属性名</param>
public CloudQuery<T> OrderByDescending(string key);

/// <summary>
/// Sorts with the lowest value first | 升序排列
/// </summary>
/// <param name="key">property name | 属性名</param>
public CloudQuery<T> OrderBy(string key);

/// <summary>
/// Skip, For paging. | 跳页
/// </summary>
/// <param name="count">数量</param>
public CloudQuery<T> Skip(int count);

/// <summary>
/// Truncate, For paging. | 截取
/// </summary>
/// <param name="count">数量</param>
public CloudQuery<T> Take(int count);
云储存 | CloudStorage云储存是创建、读取、更新和删除对象的服务。你可以对你可能创的所有类型的对象使用这个服务,诸如保存的游戏、高分榜、玩家信息、或者所有这三种。在使用前你需要先使用三种存储注解中的两种修饰你的数据对象
存储表 | [StorageTable]这个注解是必需的!存储表被放置在那些将会被云储存使用的对象类上。它包括实体表的名称。
存储身份 | [StorageIdentity]这个注解是必需的!存储身份标志对象的唯一身份字段。强烈建议把这个字段设为字符串属性。当为一个新的对象实例创建一个身份时请使用GUID全局唯一标识符,Global Unique Identity)。
存储分数 | [StorageScore]可选注解。 标志一个字段作为默认排序值。当一个对象查询被请求默认的排序会被存储分数值定义。这个注解被引入来简单过渡到一个高速的Redis数据库服务器。
存储对象案例 | StorageObject Example[StorageTable("DemoObject")]
class DemoObject
{
[StorageIdentity]
public string Id { get; set; }
[StorageScore]
public int Score { get; set; }
}
云储存接口 | CloudStorage Interface/// <summary>
/// Static Instance | 静态实例
/// </summary>
public static readonly CloudStorage Instance;

/// <summary
/// Reads a collection of objects which match a cloud query.
///读取一个匹配云查询的对象集合
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="query">查询</param>
/// <returns>Http任务</returns>
public HttpTask<T[]> Get<T>(CloudQuery<T> query);

/// <summary>
/// Reads a single of object from the server. | 从服务器读取单个对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="id">身份字符串</param>
/// <returns>Http任务</returns>
public HttpTask<T> Get<T>(string id) ;

/// <summary>
/// Reads a set of objects from the server. | 从服务器读取一系列对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="ids">身份字符串数组</param>
/// <returns>Http任务</returns>
public HttpTask<T[]> GetSet<T>(string[] ids);

/// <summary>
/// Saves a new object serverside. | 保存一个新的对象到服务器
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="entity">实体</param>
/// <returns>Http任务</returns>
public HttpTask Create<T>(T entity);

/// <summary>
/// Saves a new object serverside. Includes write protection (AVL).
///保存一个新的对象到服务器,包括读取保护。
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="entity">实体</param>
/// <param name="acl">protection group | 保护组</param>
/// <param name="param">User name | 用户名</param>
/// <returns>Http任务</returns>
public HttpTask Create<T>(T entity, StorageACL acl, string param) ;

/// <summary>
/// Saves an existing object serverside | 保存一个存在的对象到服务器
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="entity">实体</param>
/// <returns>Http任务</returns>
public HttpTask Update<T>(T entity);

/// <summary>
/// Saves an existing object set serverside | 保存存在的对象集到服务器
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="entities">实例</param>
/// <returns>Http任务</returns>
public HttpTask UpdateSet<T>(T[] entities);

/// <summary>
/// Updates a single property on an existing object | 更新一个属性到存在对象上
/// </summary>
/// <param name="id">ObjectId | 对象id</param>
/// <param name="propertyName">属性名</param>
/// <param name="propertyValue">属性值</param>
/// <returns>Http任务</returns>
public HttpTask UpdateProperty(string id, string propertyName, string propertyValue) ;

/// <summary>
/// Increments / Decrements a single property. | 增加/减少单个属性
/// </summary>
/// <param name="id">ObjectId</param>
/// <param name="propertyName">属性名</param>
/// <param name="delta">change | 改变的数值,浮点型</param>
/// <returns>Http任务</returns>
public HttpTask UpdateDelta(string id, string propertyName, float delta = 1) ;

/// <summary>
/// Increments / Decrements a single property.
/// </summary>
/// <param name="id">ObjectId</param>
/// <param name="propertyName"></param>
/// <param name="delta">change | 整型</param>
/// <returns></returns>
public HttpTask UpdateDelta(string id,  string propertyName, int delta = 1) ;

/// <summary>
/// Deletes the entity serverside | 删除服务器上的实体
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="entity">实体</param>
/// <returns>Http任务</returns>
public HttpTask Delete<T>(T entity);
云服务 | CloudService云服务包装服务器通讯并包括常见错误处理和序列化。它被CloudAccount, CloudStorageCloudRealtime服务内部使用。
云服务是一个创建自定义API的高级类。特别是,如果你在服务器上写一个新的ApiController(例如一个强类型的云储存控制器) 你可以使用云服务来和这个新的服务通信
自定义服务案例 | Example Custom Service/// <summary>
/// Service for communicating with the serverside ApiCatController
///和服务器端的ApiCatController通讯服务
/// </summary>
public class CatService
{
  public static readonly CatService Instance = new CatService();

  public CloudConfig Config
  {
          get { return CloudConfig.Instance; }
  }

  public CloudSession Session
  {
          get { return CloudSession.Instance; }
  }

  // Include name of controller in the constructor | 在构造方法中包含控制器名
  public readonly CloudService Service = new CloudService("Cat");

  /// <summary>
  /// Calls the LickSelf ActionMethod on the controller.
  ///在控制器上调用LickSelf动作方法
  /// </summary>
  public Task<RealtimeToken> LickSelf()
  {
      return Service.Post("LickSelf");
  }
}



云服务器 | Cloud Server
# Foundation Cloud Server (3/15/2015)
Nicholas Ventimiglia | http://unity3dfoundation.com
一个云端可托管的专为Unity3d设计的Asp.Net MVC架构解决方案。
v Asp.Net MVC是一个世界级的C# 4.0开源网络服务器
[size=10.5000pt]v [size=10.5000pt]图示的(Html)开发者和管理员门户
[size=10.5000pt]v [size=10.5000pt]多租户预备,一次安装托管多个游戏
[size=10.5000pt]v [size=10.5000pt]所有服务器的API都有一个Unity3d服务客户端蓄势待发!
[size=10.5000pt]v [size=10.5000pt]账户API有登录、注册、帐号恢复和游客模式
[size=10.5000pt]v [size=10.5000pt]支持知名邮箱来进行帐号恢复和新用户注册(欢迎邮件)
[size=10.5000pt]v [size=10.5000pt]库存API支持动态(无类型)对象
[size=10.5000pt]v [size=10.5000pt]实时Realtime[size=10.5000pt]API集成了实时云消息服务:https://realtime.co/
[size=10.5000pt]v [size=10.5000pt]通过自定义ApiControllers很容易地扩展解决方案
[size=10.5000pt]v [size=10.5000pt]使用Entity Framework实体框架来托管SQL数据库
[size=10.5000pt]v [size=10.5000pt]数据表平滑且规范化使得和Redis、MongoDB或RavenDB可以快速对话!
前奏 | Prelude服务器是一个asp.net mvc解决方案。MVC是一个由微软开发的世界级开源网络框架。我选择它是因为它速度快、可扩展和使用C#编程。在你开始之前你应该有一个基本的理解如何使用这项技术:http://www.asp.net/mvc/overview 。我也推荐你使用至少是Visual Studio 2013 作为你的IDE.集成开发环境,即Integrated Development Environment首字母缩写):
· https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx
你也将需要一个网络主机来在世界范围网络上托管这个解决方案。大多数支持Windows和mssql(微软sql数据库)的主机都可以。我在便宜的2美金每月的服务器主机和Azure比较好的服务器托管主机品牌上都测试过。
最后,MVC的下一个迭代(vNext)将会支持在Linux网络服务器上托管。我将会在该迭代发布后更新插件包。
Nuget包还原 | Nuget package restore网络服务器有许多依赖。这些依赖必须使用Nuget加载。右键在方案视图里的解决方案文件上单击并选择Manage Nuget Packages For This Solution你会被提示还原丢失的包。一旦你完成重新构建包,任何丢失的相关异常会被修正。
安装数据库 | Install the database在根里面有两个sql生成脚本 : Cloud.sql Account.sql 运行这两个脚本就会生成sql表。如果你想使用单个的数据库的话,你可以一起同时运行这两个脚本。
网络配置 | Web.Config有许多设置必须在web.config里进行配置。
连接字符串 | Connection String有两个连接字符串AccountContext CloudContext你必须设置连接字符串来引用新创建的数据库。这些字符串应该在你设置数据库时被你的主机服务器提供。在下面的注释里有两个连接字符串的案例。
应用设置 | AppSettings有许多的应用设置,大多数是可以被忽略的。我会指出重要的地方。
· 重置期限|ResetExpiration : 用户恢复令牌的有效时间。
· 启用开发者 | EnableDevelopers : 启用新的开发者来注册。在发布产品的时候把它关掉。
· 加密关键字 | AesKey : 用来加密用户密码的关键字(AED 256)
o http://{url}/Home/Aes
· 管理员密码 | AdminPassword : 管理员的默认密码 (安装时创建).
· 管理员邮箱 | AdminEmail : 默认的管理员用户名 /邮箱 (安装时创建).
· 邮箱 | Mail : 为邮件服务做的设置。
邮件设置 | System.Net.MailSettings.Smtp登入你的主机发出到简单传输协议邮箱服务器的所需信息。对于托管在Azure上的服务器我推荐使用http://sendgrid.com作为一个简单传输协议提供者。
运行 | Running现在应用程序设置好了,并且你可以运行和/或部署应用。
邮件模版 | Email Templates邮箱系统允许在用户注册、请求令牌和更新帐号信息时给用户发送邮件。这允许双重认证和激活用户来管理他们自己的帐号而无需你做什么。
系统有三种可供发送的邮件:当用户首次注册时发送欢迎邮件;当用想要更改帐号邮箱或密码时发送一个带验证令牌的令牌邮件;用户帐号信息发生任何改变时会收到更新通知。
你可以通过上传邮件模版来定制化这些邮件。这些模版支持RAZOR语法。该语法是一种支持注入'Model Values'HTMLesq标记语言
下载 | Download下载模版 | Download Templates         http://unity3dfoundation/wiki/EmailDownload
一旦你完成了包的下载并扩展了你的模版,请使用Dashboard/Files子菜单将其上传到你的应用程序。
结束语:很多开发者朋友看玩文档后觉得受益匪浅,也有的提出一些改进意见,他们纷纷给我的邮箱(604746493@qq.com )发了邮件,我也逐一回复了,非常感谢开发者朋友们的热情来信!这里还要特别感谢向我支付宝(15386585129)转账(说是请我吃饭或喝咖啡)的开发者朋友们,盛情难却,你们愿意请我喝咖啡我感到很荣幸,谢谢!
大家的支持和热情是我不断翻译开发文档的动力,接下来我还会翻译更多的开发文档或教程,也会着手写一些我的实际开发心得,大家如果想第一时间获取到PDF文档可以把邮箱地址发给我,我可以群发邮件给需要的开发者朋友!当然,也欢迎大家加入开发者联盟,我也会在联盟文件中第一时间上传各种资料。

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wpsBE53.tmp.png

Foundation Wiki.pdf

1.96 MB, 下载次数: 49

本文高清无码版本

Htc Vive 开发者联盟觉醒计划.pdf

1.44 MB, 下载次数: 27

开源计划初稿

评分

参与人数 1蛮牛币 +20 鲜花 +16 收起 理由
z7232124 + 20 + 16 很给力!

查看全部评分


装B如风,常伴吾身!
回复

使用道具 举报

7日久生情
2945/5000
排名
1204
昨日变化
5

31

主题

523

帖子

2945

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
133683
好友
41
蛮牛币
5939
威望
0
注册时间
2016-1-6
在线时间
579 小时
最后登录
2017-1-20

专栏作家蛮牛译员活力之星锦衣玉食

QQ
 楼主| 发表于 2016-12-14 15:36:09 | 显示全部楼层
由于字数太多,编辑起来很困难,页面直接就崩溃了!大家可以下载PDF!

回复 支持 反对

使用道具 举报

排名
32039
昨日变化
17

0

主题

34

帖子

44

积分

Rank: 1

UID
128419
好友
0
蛮牛币
3
威望
0
注册时间
2015-11-9
在线时间
6 小时
最后登录
2016-12-14
发表于 2016-12-14 17:21:21 | 显示全部楼层
觉得很好啊6666

回复

使用道具 举报

4四处流浪
337/500
排名
4803
昨日变化
5

0

主题

47

帖子

337

积分

Rank: 4

UID
399
好友
1
蛮牛币
194
威望
20
注册时间
2013-6-20
在线时间
109 小时
最后登录
2017-1-13

专栏作家

发表于 2016-12-14 17:50:33 | 显示全部楼层
文章很不错,不过蝴蝶背景是怎么个意思……而且不知道蛮牛 有没有代码编辑器……为啥都是文本纯粘贴的

回复 支持 反对

使用道具 举报

5熟悉之中
529/1000
排名
23484
昨日变化
17

6

主题

324

帖子

529

积分

Rank: 5Rank: 5

UID
158776
好友
0
蛮牛币
59
威望
0
注册时间
2016-7-26
在线时间
193 小时
最后登录
2017-1-12
发表于 2016-12-14 18:51:50 | 显示全部楼层
谢谢楼主分享,讲解的很清楚。

回复 支持 反对

使用道具 举报

3偶尔光临
201/300
排名
7121
昨日变化
6

0

主题

36

帖子

201

积分

Rank: 3Rank: 3Rank: 3

UID
42016
好友
0
蛮牛币
157
威望
0
注册时间
2014-8-26
在线时间
62 小时
最后登录
2017-1-19
发表于 2016-12-14 19:27:31 | 显示全部楼层
QQ群在哪里

回复

使用道具 举报

3偶尔光临
201/300
排名
7121
昨日变化
6

0

主题

36

帖子

201

积分

Rank: 3Rank: 3Rank: 3

UID
42016
好友
0
蛮牛币
157
威望
0
注册时间
2014-8-26
在线时间
62 小时
最后登录
2017-1-19
发表于 2016-12-14 19:28:57 | 显示全部楼层
QQ群在哪里

回复

使用道具 举报

5熟悉之中
735/1000
排名
6948
昨日变化
83

2

主题

442

帖子

735

积分

Rank: 5Rank: 5

UID
92518
好友
1
蛮牛币
1513
威望
0
注册时间
2015-4-15
在线时间
167 小时
最后登录
2017-1-20

迈向小康

发表于 2016-12-14 20:41:05 | 显示全部楼层
由于字数太多,编辑起来很困难,页面直接就崩溃了!大家可以下载PDF!

回复 支持 反对

使用道具 举报

7日久生情
2945/5000
排名
1204
昨日变化
5

31

主题

523

帖子

2945

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
133683
好友
41
蛮牛币
5939
威望
0
注册时间
2016-1-6
在线时间
579 小时
最后登录
2017-1-20

专栏作家蛮牛译员活力之星锦衣玉食

QQ
 楼主| 发表于 2016-12-15 09:15:38 | 显示全部楼层
phoenixlhs 发表于 2016-12-14 17:50
文章很不错,不过蝴蝶背景是怎么个意思……而且不知道蛮牛 有没有代码编辑器……为啥都是文本纯粘贴的 ...

嗯,字数太多了,就没有使用代码编辑器,不过不影响阅读!

装B如风,常伴吾身!
回复 支持 反对

使用道具 举报

5熟悉之中
681/1000
排名
3708
昨日变化
29

0

主题

199

帖子

681

积分

Rank: 5Rank: 5

UID
151586
好友
0
蛮牛币
436
威望
0
注册时间
2016-6-11
在线时间
230 小时
最后登录
2017-1-20
QQ
发表于 2016-12-15 11:17:14 | 显示全部楼层
6666666666666666

回复 支持 反对

使用道具 举报

排名
6165
昨日变化
9

28

主题

190

帖子

963

积分

Rank: 9Rank: 9Rank: 9

UID
32616
好友
7
蛮牛币
812
威望
0
注册时间
2014-7-5
在线时间
126 小时
最后登录
2017-1-19

专栏作家

发表于 2016-12-19 17:45:33 | 显示全部楼层
太牛逼的,收藏学习

回复 支持 反对

使用道具 举报

2初来乍到
108/150
排名
11912
昨日变化
6

0

主题

42

帖子

108

积分

Rank: 2Rank: 2

UID
132638
好友
0
蛮牛币
20
威望
0
注册时间
2015-12-25
在线时间
28 小时
最后登录
2017-1-20
发表于 4 天前 | 显示全部楼层
支持支持支持

回复

使用道具 举报

2初来乍到
117/150
排名
26649
昨日变化
19

0

主题

90

帖子

117

积分

Rank: 2Rank: 2

UID
185807
好友
0
蛮牛币
65
威望
0
注册时间
2016-11-22
在线时间
21 小时
最后登录
2017-1-19
发表于 前天 17:47 | 显示全部楼层
支持支持。很不错的样子

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表