Added Compare function to String, which is optionally case-insensitive.

Added registration of allowed remote events.
This commit is contained in:
Lasse Öörni 2011-07-25 23:15:04 +00:00
parent fbf5bd4076
commit 40d04b377b
17 changed files with 220 additions and 130 deletions

View File

@ -221,6 +221,7 @@ Methods:<br>
- String ToUpper() const
- String ToLower() const
- String Trimmed() const
- int Compare(const String&, bool arg1 = true) const
- String[]@ Split(uint8) const
- bool ToBool() const
- float ToFloat() const
@ -1643,7 +1644,7 @@ Properties:<br>
- bool looped
- float weight
- float time
- int layer
- uint8 layer
- bool useNlerp
- Animation@ animation (readonly)
- bool enabled (readonly)
@ -1713,14 +1714,14 @@ Methods:<br>
- bool SetAttribute(const String&, const Variant&)
- Variant GetAttribute(const String&)
- void Remove()
- bool Play(const String&, int, bool, float arg3 = 0.0f)
- bool PlayExclusive(const String&, int, bool, float arg3 = 0.0f)
- bool Play(const String&, uint8, bool, float arg3 = 0.0f)
- bool PlayExclusive(const String&, uint8, bool, float arg3 = 0.0f)
- void Stop(const String&, float arg1 = 0.0f)
- void StopLayer(int, float arg1 = 0.0f)
- void StopLayer(uint8, float arg1 = 0.0f)
- void StopAll(float arg0 = 0.0f)
- bool Fade(const String&, float, float)
- bool FadeOthers(const String&, float, float)
- bool SetLayer(const String&, int)
- bool SetLayer(const String&, uint8)
- bool SetStartBone(const String&, const String&)
- bool SetTime(const String&, float)
- bool SetWeight(const String&, float)
@ -1730,7 +1731,7 @@ Methods:<br>
- bool IsPlaying(const String&) const
- bool IsFadingIn(const String&) const
- bool IsFadingOut(const String&) const
- int GetLayer(const String&) const
- uint8 GetLayer(const String&) const
- const String& GetStartBone(const String&) const
- float GetTime(const String&) const
- float GetWeight(const String&) const
@ -3468,6 +3469,10 @@ Methods:<br>
- void BroadcastRemoteEvent(const String&, bool, const VariantMap& arg2 = VariantMap ( ))
- void BroadcastRemoteEvent(Scene@, const String&, bool, const VariantMap& arg3 = VariantMap ( ))
- void BroadcastRemoteEvent(Node@, const String&, bool, const VariantMap& arg3 = VariantMap ( ))
- void RegisterRemoteEvent(const String&) const
- void UnregisterRemoteEvent(const String&) const
- void UnregisterAllRemoteEvents()
- bool CheckRemoteEvent(const String&) const
Properties:<br>
- ShortStringHash type (readonly)
@ -3587,14 +3592,14 @@ Properties:<br>
- uint id (readonly)
- Node@ node (readonly)
- float mass
- Vector3 linearVelocity
- Vector3& linearVelocity
- float linearRestThreshold
- Vector3 angularVelocity
- Vector3& angularVelocity
- float angularRestThreshold
- float angularMaxVelocity
- bool active
- Vector3 position
- Quaternion rotation
- Vector3& position
- Quaternion& rotation
- float linearDampingThreshold
- float linearDampingScale
- float angularDampingThreshold

View File

@ -296,7 +296,7 @@ public:
}
/// Return whether contains a pair with key
bool Contains(const T& key)
bool Contains(const T& key) const
{
return FindNode(key) != 0;
}

View File

@ -253,7 +253,7 @@ public:
}
/// Return whether contains a key
bool Contains(const T& key)
bool Contains(const T& key) const
{
return FindNode(key) != 0;
}

View File

@ -560,6 +560,40 @@ unsigned String::FindLast(const String& str, unsigned startPos) const
return NPOS;
}
int String::Compare(const String& str, bool caseSensitive) const
{
return Compare(str.CString(), caseSensitive);
}
int String::Compare(const char* str, bool caseSensitive) const
{
const char* lhs = CString();
const char* rhs = str;
if (caseSensitive)
return strcmp(lhs, rhs);
else
{
if (!lhs || !rhs)
return lhs ? 1 : (rhs ? -1 : 0);
for (;;)
{
char l = tolower(*lhs);
char r = tolower(*rhs);
if (!l || !r)
return l ? 1 : (r ? -1 : 0);
if (l < r)
return -1;
if (l > r)
return 1;
++lhs;
++rhs;
}
}
}
void String::Replace(unsigned pos, unsigned length, const char* srcStart, unsigned srcLength)
{
int delta = (int)srcLength - (int)length;

View File

@ -354,7 +354,10 @@ public:
unsigned Capacity() const { return capacity_; }
/// Return whether the string is empty
bool Empty() const { return length_ == 0; }
/// Return comparision result with a string
int Compare(const String& str, bool caseSensitive = true) const;
/// Return comparision result with a C string
int Compare(const char* str, bool caseSensitive = true) const;
/// Return hash value for HashSet & HashMap
unsigned ToHash() const
{

View File

@ -31,8 +31,10 @@
bool ToBool(const String& source)
{
String temp = source.ToLower();
if (temp.Find("true") != String::NPOS)
if (source.Empty())
return false;
char first = tolower(source[0]);
if (first == 't' || first == 'y' || first == '1')
return true;
else
return false;
@ -172,25 +174,11 @@ unsigned GetStringListIndex(const String& value, const String* strings, unsigned
{
unsigned i = 0;
if (caseSensitive)
while (!strings[i].Empty())
{
while (!strings[i].Empty())
{
if (value == strings[i])
return i;
++i;
}
}
else
{
String valueLower = value.ToLower();
while (!strings[i].Empty())
{
/// \todo Write an insensitive compare function instead of creating new strings
if (valueLower == strings[i].ToLower())
return i;
++i;
}
if (!value.Compare(strings[i], caseSensitive))
return i;
++i;
}
return defaultIndex;

View File

@ -123,21 +123,36 @@ static CScriptArray* NetworkGetClientConnections(Network* ptr)
return 0;
}
void BroadcastRemoteEvent(const String& eventType, bool inOrder, const VariantMap& eventData, Network* ptr)
static void NetworkBroadcastRemoteEvent(const String& eventType, bool inOrder, const VariantMap& eventData, Network* ptr)
{
ptr->BroadcastRemoteEvent(StringHash(eventType), inOrder, eventData);
}
void BroadcastRemoteSceneEvent(Scene* scene, const String& eventType, bool inOrder, const VariantMap& eventData, Network* ptr)
static void NetworkBroadcastRemoteSceneEvent(Scene* scene, const String& eventType, bool inOrder, const VariantMap& eventData, Network* ptr)
{
ptr->BroadcastRemoteEvent(scene, StringHash(eventType), inOrder, eventData);
}
void BroadcastRemoteNodeEvent(Node* node, const String& eventType, bool inOrder, const VariantMap& eventData, Network* ptr)
static void NetworkBroadcastRemoteNodeEvent(Node* node, const String& eventType, bool inOrder, const VariantMap& eventData, Network* ptr)
{
ptr->BroadcastRemoteEvent(node, StringHash(eventType), inOrder, eventData);
}
static void NetworkRegisterRemoteEvent(const String& eventType, Network* ptr)
{
ptr->RegisterRemoteEvent(StringHash(eventType));
}
static void NetworkUnregisterRemoteEvent(const String& eventType, Network* ptr)
{
ptr->UnregisterRemoteEvent(StringHash(eventType));
}
static bool NetworkCheckRemoteEvent(const String& eventType, Network* ptr)
{
return ptr->CheckRemoteEvent(StringHash(eventType));
}
void RegisterNetwork(asIScriptEngine* engine)
{
RegisterObject<Network>(engine, "Network");
@ -147,9 +162,13 @@ void RegisterNetwork(asIScriptEngine* engine)
engine->RegisterObjectMethod("Network", "void StopServer()", asMETHOD(Network, StopServer), asCALL_THISCALL);
engine->RegisterObjectMethod("Network", "void BroadcastMessage(int, bool, bool, const VectorBuffer&in)", asMETHODPR(Network, BroadcastMessage, (int, bool, bool, const VectorBuffer&), void), asCALL_THISCALL);
engine->RegisterObjectMethod("Network", "void BroadcastMessage(int, uint, bool, bool, const VectorBuffer&in)", asMETHODPR(Network, BroadcastMessage, (int, unsigned, bool, bool, const VectorBuffer&), void), asCALL_THISCALL);
engine->RegisterObjectMethod("Network", "void BroadcastRemoteEvent(const String&in, bool, const VariantMap&in eventData = VariantMap())", asFUNCTION(BroadcastRemoteEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void BroadcastRemoteEvent(Scene@+, const String&in, bool, const VariantMap&in eventData = VariantMap())", asFUNCTION(BroadcastRemoteSceneEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void BroadcastRemoteEvent(Node@+, const String&in, bool, const VariantMap&in eventData = VariantMap())", asFUNCTION(BroadcastRemoteNodeEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void BroadcastRemoteEvent(const String&in, bool, const VariantMap&in eventData = VariantMap())", asFUNCTION(NetworkBroadcastRemoteEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void BroadcastRemoteEvent(Scene@+, const String&in, bool, const VariantMap&in eventData = VariantMap())", asFUNCTION(NetworkBroadcastRemoteSceneEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void BroadcastRemoteEvent(Node@+, const String&in, bool, const VariantMap&in eventData = VariantMap())", asFUNCTION(NetworkBroadcastRemoteNodeEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void RegisterRemoteEvent(const String&in) const", asFUNCTION(NetworkRegisterRemoteEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void UnregisterRemoteEvent(const String&in) const", asFUNCTION(NetworkUnregisterRemoteEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void UnregisterAllRemoteEvents()", asMETHOD(Network, UnregisterAllRemoteEvents), asCALL_THISCALL);
engine->RegisterObjectMethod("Network", "bool CheckRemoteEvent(const String&in) const", asFUNCTION(NetworkCheckRemoteEvent), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Network", "void set_updateFps(int)", asMETHOD(Network, SetUpdateFps), asCALL_THISCALL);
engine->RegisterObjectMethod("Network", "int get_updateFps() const", asMETHOD(Network, GetUpdateFps), asCALL_THISCALL);
engine->RegisterObjectMethod("Network", "bool get_serverRunning() const", asMETHOD(Network, IsServerRunning), asCALL_THISCALL);

View File

@ -60,12 +60,12 @@ public:
bool Rename(const String& srcFileName, const String& destFileName);
/// Delete a file. Return true if successful
bool Delete(const String& fileName);
/// Register a path as being allowed to access
/// Register a path as allowed to access. If no paths are registered, all are allowed
void RegisterPath(const String& pathName);
/// Return the absolute current working directory
String GetCurrentDir();
/// Check if a path is allowed to be accessed. If no paths defined, all are allowed
/// Check if a path is allowed to be accessed. If no paths are registered, all are allowed
bool CheckAccess(const String& pathName);
/// Check if a file exists
bool FileExists(const String& fileName);

View File

@ -28,6 +28,7 @@
#include "FileSystem.h"
#include "Log.h"
#include "MemoryBuffer.h"
#include "Network.h"
#include "NetworkEvents.h"
#include "Profiler.h"
#include "Protocol.h"
@ -92,6 +93,12 @@ void Connection::SendMessage(int msgID, unsigned contentID, bool reliable, bool
void Connection::SendRemoteEvent(StringHash eventType, bool inOrder, const VariantMap& eventData)
{
if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
{
LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
return;
}
RemoteEvent queuedEvent;
queuedEvent.receiverID_ = 0;
queuedEvent.eventType_ = eventType;
@ -102,6 +109,12 @@ void Connection::SendRemoteEvent(StringHash eventType, bool inOrder, const Varia
void Connection::SendRemoteEvent(Node* receiver, StringHash eventType, bool inOrder, const VariantMap& eventData)
{
if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
{
LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
return;
}
if (!receiver)
{
LOGERROR("Null node for remote node event");
@ -649,10 +662,15 @@ void Connection::ProcessSceneLoaded(int msgID, MemoryBuffer& msg)
void Connection::ProcessRemoteEvent(int msgID, MemoryBuffer& msg)
{
/// \todo Check whether the remote event is allowed based on a black- or whitelist
if (msgID == MSG_REMOTEEVENT)
{
StringHash eventType = msg.ReadStringHash();
if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
{
LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
return;
}
VariantMap eventData = msg.ReadVariantMap();
SendEvent(eventType, eventData);
}
@ -663,8 +681,15 @@ void Connection::ProcessRemoteEvent(int msgID, MemoryBuffer& msg)
LOGERROR("Can not receive remote node event without an assigned scene");
return;
}
unsigned nodeID = msg.ReadVLE();
StringHash eventType = msg.ReadStringHash();
if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
{
LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
return;
}
VariantMap eventData = msg.ReadVariantMap();
Node* receiver = scene_->GetNodeByID(nodeID);
if (!receiver)

View File

@ -340,11 +340,52 @@ void Network::SetUpdateFps(int fps)
updateAcc_ = 0.0f;
}
void Network::RegisterRemoteEvent(StringHash eventType)
{
allowedRemoteEvents_.Insert(eventType);
}
void Network::UnregisterRemoteEvent(StringHash eventType)
{
allowedRemoteEvents_.Erase(eventType);
}
void Network::UnregisterAllRemoteEvents()
{
allowedRemoteEvents_.Clear();
}
Connection* Network::GetConnection(kNet::MessageConnection* connection) const
{
Map<kNet::MessageConnection*, SharedPtr<Connection> >::ConstIterator i = clientConnections_.Find(connection);
if (i != clientConnections_.End())
return i->second_;
else if (serverConnection_ && serverConnection_->GetMessageConnection() == connection)
return serverConnection_;
else
return 0;
}
Connection* Network::GetServerConnection() const
{
return serverConnection_;
}
bool Network::IsServerRunning() const
{
return network_->GetServer();
}
bool Network::CheckRemoteEvent(StringHash eventType) const
{
return allowedRemoteEvents_.Empty() || allowedRemoteEvents_.Contains(eventType);
}
void Network::Update(float timeStep)
{
PROFILE(UpdateNetwork);
// Check if periodic update should be made now
// Check if periodic update should happen now
updateAcc_ += timeStep;
bool updateNow = updateAcc_ >= updateInterval_;
@ -400,27 +441,6 @@ void Network::Update(float timeStep)
}
}
Connection* Network::GetConnection(kNet::MessageConnection* connection) const
{
Map<kNet::MessageConnection*, SharedPtr<Connection> >::ConstIterator i = clientConnections_.Find(connection);
if (i != clientConnections_.End())
return i->second_;
else if (serverConnection_ && serverConnection_->GetMessageConnection() == connection)
return serverConnection_;
else
return 0;
}
Connection* Network::GetServerConnection() const
{
return serverConnection_;
}
bool Network::IsServerRunning() const
{
return network_->GetServer();
}
void Network::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
{
using namespace BeginFrame;

View File

@ -77,8 +77,12 @@ public:
void BroadcastRemoteEvent(Node* receiver, StringHash eventType, bool inOrder, const VariantMap& eventData = VariantMap());
/// Set network update FPS
void SetUpdateFps(int fps);
/// Update connections. Called by HandleBeginFrame
void Update(float timeStep);
/// Register a remote event as allowed to be sent and received. If no events are registered, all are allowed
void RegisterRemoteEvent(StringHash eventType);
/// Unregister a remote event as allowed to be sent and received
void UnregisterRemoteEvent(StringHash eventType);
/// Unregister all remote events. This results in all being allowed
void UnregisterAllRemoteEvents();
/// Return network update FPS
int GetUpdateFps() const { return updateFps_; }
@ -90,6 +94,11 @@ public:
const Map<kNet::MessageConnection*, SharedPtr<Connection> > GetClientConnections() const { return clientConnections_; }
/// Return whether the server is running
bool IsServerRunning() const;
/// Return whether a remote event is allowed to be sent and received. If no events are registered, all are allowed
bool CheckRemoteEvent(StringHash eventType) const;
/// Update connections. Called by HandleBeginFrame
void Update(float timeStep);
private:
/// Handle begin frame event
@ -105,6 +114,8 @@ private:
SharedPtr<Connection> serverConnection_;
/// Server's client connections
Map<kNet::MessageConnection*, SharedPtr<Connection> > clientConnections_;
/// Allowed remote events
Set<StringHash> allowedRemoteEvents_;
/// Network update FPS
int updateFps_;
/// Network time interval

View File

@ -425,8 +425,7 @@ void RigidBody::PostStep(float t, HashSet<RigidBody*>& processedBodies)
processedBodies.Insert(this);
inPostStep_ = true;
// If the parent node has a rigid body, process it first
// For now, treat node parented to the Scene as unparented
// If the parent node has a rigid body, process it first. For now, treat node parented to the Scene as unparented
Node* parent = node_->GetParent();
bool hasParent = parent && parent != node_->GetScene();
if (hasParent)
@ -450,7 +449,6 @@ void RigidBody::PostStep(float t, HashSet<RigidBody*>& processedBodies)
else
{
// Transform rigid body's world coordinates back to parent's space
/// \todo Apply in the correct order (parent first)
if (!node_->IsSmoothed())
{
Matrix3x4 newTransform(parent->GetWorldTransform().Inverse() * Matrix3x4(previousPosition_.Lerp(currentPosition, t),

View File

@ -71,12 +71,11 @@ bool ResourceCache::AddResourcePath(const String& path)
}
String fixedPath = AddTrailingSlash(path);
String pathLower = fixedPath.ToLower();
// Check that the same path does not already exist
for (unsigned i = 0; i < resourcePaths_.Size(); ++i)
{
if (resourcePaths_[i].ToLower() == pathLower)
if (!resourcePaths_[i].Compare(fixedPath, false))
return true;
}
@ -135,10 +134,10 @@ bool ResourceCache::AddManualResource(Resource* resource)
void ResourceCache::RemoveResourcePath(const String& path)
{
String fixedPath = AddTrailingSlash(path).ToLower();
String fixedPath = AddTrailingSlash(path);
for (Vector<String>::Iterator i = resourcePaths_.Begin(); i != resourcePaths_.End(); ++i)
{
if (i->ToLower() == fixedPath)
if (!i->Compare(path, false))
{
resourcePaths_.Erase(i);
return;
@ -162,11 +161,9 @@ void ResourceCache::RemovePackageFile(PackageFile* package, bool ReleaseResource
void ResourceCache::RemovePackageFile(const String& fileName, bool ReleaseResources, bool forceRelease)
{
String fileNameLower = fileName.ToLower();
for (Vector<SharedPtr<PackageFile> >::Iterator i = packages_.Begin(); i != packages_.End(); ++i)
{
if ((*i)->GetName().ToLower() == fileNameLower)
if (!(*i)->GetName().Compare(fileName, false))
{
if (ReleaseResources)
ReleasePackageResources(*i, forceRelease);
@ -224,7 +221,6 @@ void ResourceCache::ReleaseResources(ShortStringHash type, bool force)
void ResourceCache::ReleaseResources(ShortStringHash type, const String& partialName, bool force)
{
String partialNameLower = partialName.ToLower();
bool released = false;
for (Map<ShortStringHash, ResourceGroup>::Iterator i = resourceGroups_.Begin();
@ -236,7 +232,7 @@ void ResourceCache::ReleaseResources(ShortStringHash type, const String& partial
j != i->second_.resources_.End();)
{
Map<StringHash, SharedPtr<Resource> >::Iterator current = j++;
if (current->second_->GetName().Find(partialNameLower) != String::NPOS)
if (current->second_->GetName().Find(partialName) != String::NPOS)
{
// If other references exist, do not release, unless forced
if (current->second_.Refs() == 1 || force)

View File

@ -262,46 +262,6 @@ void Scene::Clear()
checksum_ = 0;
}
void Scene::Update(float timeStep)
{
if (asyncLoading_)
{
UpdateAsyncLoading();
return;
}
PROFILE(UpdateScene);
using namespace SceneUpdate;
VariantMap eventData;
eventData[P_SCENE] = (void*)this;
eventData[P_TIMESTEP] = timeStep;
// Update variable timestep logic
SendEvent(E_SCENEUPDATE, eventData);
// Update scene subsystems. If a physics world is present, it will be updated, triggering fixed timestep logic updates
SendEvent(E_SCENESUBSYSTEMUPDATE, eventData);
// Post-update variable timestep logic
SendEvent(E_SCENEPOSTUPDATE, eventData);
// Update smoothing if enabled (network client scenes)
if (IsSmoothed())
{
PROFILE(UpdateSmoothing);
float constant = 1.0f - Clamp(powf(2.0f, -timeStep * smoothingConstant_), 0.0f, 1.0f);
float squaredSnapThreshold = snapThreshold_ * snapThreshold_;
for (Map<unsigned, Node*>::ConstIterator i = allNodes_.Begin(); i != allNodes_.End() && i->first_ < FIRST_LOCAL_ID; ++i)
i->second_->UpdateSmoothing(constant, squaredSnapThreshold);
}
}
void Scene::SetActive(bool enable)
{
active_ = enable;
@ -363,6 +323,44 @@ float Scene::GetAsyncProgress() const
return (float)asyncProgress_.loadedNodes_ / (float)asyncProgress_.totalNodes_;
}
void Scene::Update(float timeStep)
{
if (asyncLoading_)
{
UpdateAsyncLoading();
return;
}
PROFILE(UpdateScene);
using namespace SceneUpdate;
VariantMap eventData;
eventData[P_SCENE] = (void*)this;
eventData[P_TIMESTEP] = timeStep;
// Update variable timestep logic
SendEvent(E_SCENEUPDATE, eventData);
// Update scene subsystems. If a physics world is present, it will be updated, triggering fixed timestep logic updates
SendEvent(E_SCENESUBSYSTEMUPDATE, eventData);
// Post-update variable timestep logic
SendEvent(E_SCENEPOSTUPDATE, eventData);
// Update smoothing if enabled (network client scenes)
if (IsSmoothed())
{
PROFILE(UpdateSmoothing);
float constant = 1.0f - Clamp(powf(2.0f, -timeStep * smoothingConstant_), 0.0f, 1.0f);
float squaredSnapThreshold = snapThreshold_ * snapThreshold_;
for (Map<unsigned, Node*>::ConstIterator i = allNodes_.Begin(); i != allNodes_.End() && i->first_ < FIRST_LOCAL_ID; ++i)
i->second_->UpdateSmoothing(constant, squaredSnapThreshold);
}
}
unsigned Scene::GetFreeNodeID(CreateMode mode)
{
if (mode == REPLICATED)

View File

@ -87,8 +87,6 @@ public:
void StopAsyncLoading();
/// Clear scene completely of nodes and components
void Clear();
/// Update scene. Called by HandleUpdate
void Update(float timeStep);
/// Set active flag. Only active scenes will be updated automatically
void SetActive(bool enable);
/// Set motion smoothing constant
@ -127,6 +125,8 @@ public:
/// Return all components
const Map<unsigned, Component*>& GetAllComponents() const { return allComponents_; }
/// Update scene. Called by HandleUpdate
void Update(float timeStep);
/// Get free node ID, either non-local or local
unsigned GetFreeNodeID(CreateMode mode);
/// Get free component ID, either non-local or local

View File

@ -755,6 +755,7 @@ void RegisterString(asIScriptEngine *engine)
engine->RegisterObjectMethod("String", "String Trimmed() const", asMETHOD(String, Trimmed), asCALL_THISCALL);
engine->RegisterObjectMethod("String", "uint get_length() const", asMETHOD(String, Length), asCALL_THISCALL);
engine->RegisterObjectMethod("String", "bool get_empty() const", asMETHOD(String, Empty), asCALL_THISCALL);
engine->RegisterObjectMethod("String", "int Compare(const String&in, bool caseSensitive = true) const", asMETHODPR(String, Compare, (const String&, bool) const, int), asCALL_THISCALL);
// Register automatic conversion functions for convenience
engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(ConstructStringInt), asCALL_CDECL_OBJLAST);

View File

@ -1573,16 +1573,8 @@ aiNode* FindNode(const String& name, aiNode* rootNode, bool caseSensitive)
{
if (!rootNode)
return 0;
if (!caseSensitive)
{
if (FromAIString(rootNode->mName).ToLower() == name.ToLower())
return rootNode;
}
else
{
if (name == rootNode->mName.data)
return rootNode;
}
if (!name.Compare(rootNode->mName.data, caseSensitive))
return rootNode;
for (unsigned i = 0; i < rootNode->mNumChildren; ++i)
{
aiNode* found = FindNode(name, rootNode->mChildren[i], caseSensitive);