我实际上是在这里回答我自己的问题。
我一定是世界上唯一尝试这样做的人,但考虑到我花了大约一周的时间来解决这个问题 - 我想如果有其他人想要使用 XML(-RPC)在 Unity 中 - 我将为他们节省数周的麻烦。
我想做的是与我们的一个游戏服务器对话,以获取排行榜之类的东西。该服务器“对话”XML-RPC,我很快发现这在 Unity 中并不容易。
最佳答案
构建 XML 以发送到我们的服务器
我无法在 Unity 中找到一个标准函数来在不增加大量开销的情况下执行此操作。所以我改为构建以下过程。
public string buildXMLRPCRequest(Hashtable FieldArray,string MethodName)
{
string ReturnString = "";
ReturnString += "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>" +
"\n" + "<simpleRPC version=\"0.9\">" +
"\n" + "<methodCall>" +
"\n" + "<methodName>" + MethodName + "</methodName>" +
"\n" + "<vector type=\"struct\">";
ReturnString += buildNode(FieldArray);
ReturnString += "\n</vector>" +
"\n</methodCall>" +
"\n</simpleRPC>";
return ReturnString;
}
public string buildNode(Hashtable FieldArray)
{
string ReturnList = "";
foreach (DictionaryEntry Item in FieldArray) {
string TypeName = "int";
string NodeType = "scalar";
Type myType = Item.Value.GetType();
string fieldValue = "";
if (myType == typeof(string) ) {
TypeName = "string";
fieldValue = Item.Value.ToString();
}
if (myType == typeof(Hashtable) ) {
fieldValue = buildNode(Item.Value as Hashtable);
NodeType = "vector";
TypeName = "struct";
}
if (myType == typeof(int) ) {
fieldValue = Item.Value.ToString();
TypeName = "int";
}
var ThisNode = "\n<" + NodeType + " type=\"" + TypeName + "\" id=\"" + Item.Key + "\">" + fieldValue + "</" + NodeType + ">";
ReturnList += ThisNode;
}
return ReturnList;
}
buildXMLRPCRequest 用于构建 XML。您将一个 HashTable 交给它,其中包含您要编码的字段,其中可能包括以下类型的对象:int、string 或 Hashtable。它将返回一个格式精美(简单)的 XML-RPC 字符串,该字符串已准备好发送到我们的服务器。
发送
要将 XML 发送到我们的服务器,您需要发出一个 MIME 类型设置为 text/xml 的 POST 请求。 Unity 中不能使用任何标准 C# 方法,但将其与 buildXMLRPCRequest 逻辑的输出一起使用可以完美地工作。它的作用:
在 Unity 中发送
我使用了这段代码:
private void UnityPostXML( int Staging,
string WebServer,
string MethodName,
Hashtable FieldArray)
{
string WebServiceURL = "http://LIVESERVER/";
if (Staging == 1) {
WebServiceURL = "http://TESTSERVER";
}
// Encode the text to a UTF8 byte arrray
string XMLRequest = buildXMLRPCRequest(FieldArray,MethodName);
System.Text.Encoding enc = System.Text.Encoding.UTF8;
byte[] myByteArray = enc.GetBytes(XMLRequest);
// Get the Unity WWWForm object (a post version)
var form = new WWWForm();
var url = WebServiceURL;
// Add a custom header to the request.
// Change the content type to xml and set the character set
var headers = form.headers;
headers["Content-Type"]="text/xml;charset=UTF-8";
// Post a request to an URL with our rawXMLData and custom headers
var www = new WWW(WebServiceURL, myByteArray, headers);
// Start a co-routine which will wait until our servers comes back
StartCoroutine(WaitForRequest(www));
}
IEnumerator WaitForRequest(WWW www)
{
yield return www;
// check for errors
if (www.error == null)
{
Debug.Log("WWW Ok!: " + www.text);
} else {
Debug.Log("WWW Error: "+ www.error);
}
}
不使用 Unity 发送
我发现用 C# 开发一个库(我使用 MonoDevelop 的标准版本)比使用 Unity 简单得多,所以如果想做同样的事情,C# 中的等效发送逻辑如下。
private string NormalXMLCall(int Staging,
string WebServer,
string MethodName,
Hashtable Fields)
{
// Figure out who to call
string WebServiceURL = "http://LIVSERVER";
if (Staging == 1) {
WebServiceURL = "http://TESTSERVER";
}
WebServiceURL += WebServer;
// Build the request
XmlRpcParser parser = new XmlRpcParser();
string XMLRequest = parser.buildXMLRPCRequest(Fields,MethodName);
// Fire it off
HttpWebRequest httpRequest =(HttpWebRequest)WebRequest.Create(WebServiceURL);
httpRequest.Method = "POST";
//Defining the type of the posted data as XML
httpRequest.ContentType = "text/xml";
// string data = xmlDoc.InnerXml;
byte[] bytedata = Encoding.UTF8.GetBytes(XMLRequest);
// Get the request stream.
Stream requestStream = httpRequest.GetRequestStream();
// Write the data to the request stream.
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
//Get Response
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
// Get the stream associated with the response.
Stream receiveStream = httpResponse.GetResponseStream ();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader readStream = new StreamReader (receiveStream, Encoding.UTF8);
string ReceivedData = readStream.ReadToEnd ();
httpResponse.Close ();
readStream.Close ();
return ReceivedData;
}
}
从 XML 中提取数据
我写了一个简单的解析器。以下 findNode 函数的构造函数应提供原始 XML 数据和您要查找的子节点对象。如果可以在 XML 字符串的最高级别找到该节点,它将返回该节点的值(作为字符串),如果找不到,则返回 null。此解析器特定于“简单 XML-RPC”,需要一些工作来解码编码字符,但这应该很容易添加。
public string findNode(string Xml,string SearchForTag) {
int NestCounter = 0;
bool FoundTag = false;
int FoundTagLevel = 0;
string ReturnValue = null;
// Break it down by "<"
string [] TagArray = Xml.Split('<');
for (int i=0;i<TagArray.Length;i++) {
if (i>175 && i<180) {
int Hello=1;
}
string ThisLine = "<" + TagArray[i];
if (ThisLine.Length <= 1) continue;
if ((ThisLine.Length >= 2) && (ThisLine.Substring(0,2) == "<?")) continue;
if ((ThisLine.Length >= 3) && (ThisLine.Substring(0,3) == "<--")) continue;
// It can be a vector or a scalar - vectors are full of scalars so we'll
ThisLine = ThisLine.Replace(" "," ");
ThisLine = ThisLine.Replace("</","</");
string [] FieldArray = ThisLine.Split(' ');
bool AddLineToResult = FoundTag;
// Nest counter is the level we are operating on. We only check the first
// Level. When a vector is found we increase the NestCount and we won't
// search for the ID
if (NestCounter <= 1) { // Initial array we are looking on level 1
for (int a=0;a<FieldArray.Length;a++) {
string ThisTag = FieldArray[a];
string [] TagValue = ThisTag.Split("=\"".ToCharArray(),5);
// Every TagValue is xx=yy pair... we want "ID=\"xxx\"
if (TagValue.Length >= 3) {
string TagName = TagValue[2];
if (TagName == SearchForTag) {
FoundTag = true;
FoundTagLevel = NestCounter;
// This could be a vector or Scalar so find the ">" in this string
// and start adding from there
int TerminatePos = ThisLine.IndexOf(">");
if ((TerminatePos >= 0) && (TerminatePos < ThisLine.Length)) {
ReturnValue = ThisLine.Substring(TerminatePos+1);
}
break;
}
}
}
}
if (FieldArray.Length > 0) {
string ThisField = FieldArray[0].ToLower();
/*
* If we are in the loop where we have found the tag,
* we haven't changed level and this is the end of a scalar it must
* mean that the tag was a scalar so we can safely leave now.
*/
if ((FoundTag) && (FoundTagLevel == NestCounter) && (ThisField == "</scalar>")) {
break;
// return ReturnValue;
}
// If we end or leave a vector we change the NestCounter
if (ThisField.IndexOf("<vector") >= 0) {
NestCounter++;
}
else if (ThisField.IndexOf("</vector>") >= 0) {
NestCounter--;
}
}
// If we have found our tag and the nest counte goes below the level
// we where looking at - it's time to leave
if (FoundTag) {
if (NestCounter <= FoundTagLevel) {
break;
//return ReturnValue;
}
}
if (AddLineToResult) {
ReturnValue += ThisLine;
}
}
// You may wanna do some url decoding here....
return ReturnValue;
}
关于c# - Unity3D XML(-RPC) 和 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7158530/
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里编辑 3.解析依赖到项目中
Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume
我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用
什么是Linq聚合方法的ruby等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj