Other renames to ensure linux case-sensitivity compliance and casing format consistency.

This commit is contained in:
Areloch 2016-05-26 13:56:19 -05:00
parent 93e767f0c5
commit f5e86a83b5
33 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,434 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "T3D/components/game/stateMachine.h"
StateMachine::StateMachine()
{
mStateStartTime = -1;
mStateTime = 0;
mStartingState = "";
mCurCreateState = NULL;
}
StateMachine::~StateMachine()
{
}
void StateMachine::loadStateMachineFile()
{
if (!mXMLReader)
{
SimXMLDocument *xmlrdr = new SimXMLDocument();
xmlrdr->registerObject();
mXMLReader = xmlrdr;
}
bool hasStartState = false;
if (!dStrIsEmpty(mStateMachineFile))
{
//use our xml reader to parse the file!
SimXMLDocument *reader = mXMLReader.getObject();
if (!reader->loadFile(mStateMachineFile))
Con::errorf("Could not load state machine file: &s", mStateMachineFile);
if (!reader->pushFirstChildElement("StateMachine"))
return;
//find our starting state
if (reader->pushFirstChildElement("StartingState"))
{
mStartingState = reader->getData();
reader->popElement();
hasStartState = true;
}
readStates();
}
if (hasStartState)
mCurrentState = getStateByName(mStartingState);
mStateStartTime = -1;
mStateTime = 0;
}
void StateMachine::readStates()
{
SimXMLDocument *reader = mXMLReader.getObject();
//iterate through our states now!
if (reader->pushFirstChildElement("State"))
{
//get our first state
State firstState;
readStateName(&firstState, reader);
readStateScriptFunction(&firstState, reader);
readTransitions(firstState);
mStates.push_back(firstState);
//now, iterate the siblings
while (reader->nextSiblingElement("State"))
{
State newState;
readStateName(&newState, reader);
readStateScriptFunction(&newState, reader);
readTransitions(newState);
mStates.push_back(newState);
}
}
}
void StateMachine::readTransitions(State &currentState)
{
SimXMLDocument *reader = mXMLReader.getObject();
//iterate through our states now!
if (reader->pushFirstChildElement("Transition"))
{
//get our first state
StateTransition firstTransition;
readTransitonTarget(&firstTransition, reader);
readConditions(firstTransition);
currentState.mTransitions.push_back(firstTransition);
//now, iterate the siblings
while (reader->nextSiblingElement("Transition"))
{
StateTransition newTransition;
readTransitonTarget(&newTransition, reader);
readConditions(newTransition);
currentState.mTransitions.push_back(newTransition);
}
reader->popElement();
}
}
void StateMachine::readConditions(StateTransition &currentTransition)
{
SimXMLDocument *reader = mXMLReader.getObject();
//iterate through our states now!
if (reader->pushFirstChildElement("Rule"))
{
//get our first state
StateTransition::Condition firstCondition;
StateField firstField;
bool fieldRead = false;
readFieldName(&firstField, reader);
firstCondition.field = firstField;
readFieldComparitor(&firstCondition, reader);
readFieldValue(&firstCondition.field, reader);
currentTransition.mTransitionRules.push_back(firstCondition);
//now, iterate the siblings
while (reader->nextSiblingElement("Transition"))
{
StateTransition::Condition newCondition;
StateField newField;
readFieldName(&newField, reader);
newCondition.field = newField;
readFieldComparitor(&newCondition, reader);
readFieldValue(&newCondition.field, reader);
currentTransition.mTransitionRules.push_back(newCondition);
}
reader->popElement();
}
}
S32 StateMachine::parseComparitor(const char* comparitorName)
{
S32 targetType = -1;
if (!dStrcmp("GreaterThan", comparitorName))
targetType = StateMachine::StateTransition::Condition::GeaterThan;
else if (!dStrcmp("GreaterOrEqual", comparitorName))
targetType = StateMachine::StateTransition::Condition::GreaterOrEqual;
else if (!dStrcmp("LessThan", comparitorName))
targetType = StateMachine::StateTransition::Condition::LessThan;
else if (!dStrcmp("LessOrEqual", comparitorName))
targetType = StateMachine::StateTransition::Condition::LessOrEqual;
else if (!dStrcmp("Equals", comparitorName))
targetType = StateMachine::StateTransition::Condition::Equals;
else if (!dStrcmp("True", comparitorName))
targetType = StateMachine::StateTransition::Condition::True;
else if (!dStrcmp("False", comparitorName))
targetType = StateMachine::StateTransition::Condition::False;
else if (!dStrcmp("Negative", comparitorName))
targetType = StateMachine::StateTransition::Condition::Negative;
else if (!dStrcmp("Positive", comparitorName))
targetType = StateMachine::StateTransition::Condition::Positive;
else if (!dStrcmp("DoesNotEqual", comparitorName))
targetType = StateMachine::StateTransition::Condition::DoesNotEqual;
return targetType;
}
void StateMachine::update()
{
//we always check if there's a timout transition, as that's the most generic transition possible.
F32 curTime = Sim::getCurrentTime();
if (mStateStartTime == -1)
mStateStartTime = curTime;
mStateTime = curTime - mStateStartTime;
char buffer[64];
dSprintf(buffer, sizeof(buffer), "%g", mStateTime);
checkTransitions("stateTime", buffer);
}
void StateMachine::checkTransitions(const char* slotName, const char* newValue)
{
//because we use our current state's fields as dynamic fields on the instance
//we'll want to catch any fields being set so we can treat changes as transition triggers if
//any of the transitions on this state call for it
//One example would be in order to implement burst fire on a weapon state machine.
//The behavior instance has a dynamic variable set up like: GunStateMachine.burstShotCount = 0;
//We also have a transition in our fire state, as: GunStateMachine.addTransition("FireState", "burstShotCount", "DoneShooting", 3);
//What that does is for our fire state, we check the dynamicField burstShotCount if it's equal or greater than 3. If it is, we perform the transition.
//As state fields are handled as dynamicFields for the instance, regular dynamicFields are processed as well as state fields. So we can use the regular
//dynamic fields for our transitions, to act as 'global' variables that are state-agnostic. Alternately, we can use state-specific fields, such as a transition
//like this:
//GunStateMachine.addTransition("IdleState", "Fidget", "Timeout", ">=", 5000);
//That uses the the timeout field, which is reset each time the state changes, and so state-specific, to see if it's been 5 seconds. If it has been, we transition
//to our fidget state
//so, lets check our current transitions
//now that we have the type, check our transitions!
for (U32 t = 0; t < mCurrentState.mTransitions.size(); t++)
{
//if (!dStrcmp(mCurrentState.mTransitions[t]., slotName))
{
//found a transition looking for this variable, so do work
//first, figure out what data type thie field is
//S32 type = getVariableType(newValue);
bool fail = false;
bool match = false;
S32 ruleCount = mCurrentState.mTransitions[t].mTransitionRules.size();
for (U32 r = 0; r < ruleCount; r++)
{
const char* fieldName = mCurrentState.mTransitions[t].mTransitionRules[r].field.name;
if (!dStrcmp(fieldName, slotName))
{
match = true;
//now, check the value with the comparitor and see if we do the transition.
if (!passComparitorCheck(newValue, mCurrentState.mTransitions[t].mTransitionRules[r]))
{
fail = true;
break;
}
}
}
//If we do have a transition rule for this field, and we didn't fail on the condition, go ahead and switch states
if (match && !fail)
{
setState(mCurrentState.mTransitions[t].mStateTarget);
return;
}
}
}
}
bool StateMachine::passComparitorCheck(const char* var, StateTransition::Condition transitionRule)
{
F32 num = dAtof(var);
switch (transitionRule.field.fieldType)
{
case StateField::Type::VectorType:
switch (transitionRule.triggerComparitor)
{
case StateTransition::Condition::Equals:
case StateTransition::Condition::GeaterThan:
case StateTransition::Condition::GreaterOrEqual:
case StateTransition::Condition::LessThan:
case StateTransition::Condition::LessOrEqual:
case StateTransition::Condition::DoesNotEqual:
//do
break;
default:
return false;
};
case StateField::Type::StringType:
switch (transitionRule.triggerComparitor)
{
case StateTransition::Condition::Equals:
if (!dStrcmp(var, transitionRule.field.triggerStringVal))
return true;
else
return false;
case StateTransition::Condition::DoesNotEqual:
if (dStrcmp(var, transitionRule.field.triggerStringVal))
return true;
else
return false;
default:
return false;
};
case StateField::Type::BooleanType:
switch (transitionRule.triggerComparitor)
{
case StateTransition::Condition::TriggerValueTarget::True:
if (dAtob(var))
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::False:
if (dAtob(var))
return false;
else
return true;
default:
return false;
};
case StateField::Type::NumberType:
switch (transitionRule.triggerComparitor)
{
case StateTransition::Condition::TriggerValueTarget::Equals:
if (num == transitionRule.field.triggerNumVal)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::GeaterThan:
if (num > transitionRule.field.triggerNumVal)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::GreaterOrEqual:
if (num >= transitionRule.field.triggerNumVal)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::LessThan:
if (num < transitionRule.field.triggerNumVal)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::LessOrEqual:
if (num <= transitionRule.field.triggerNumVal)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::DoesNotEqual:
if (num != transitionRule.field.triggerNumVal)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::Positive:
if (num > 0)
return true;
else
return false;
case StateTransition::Condition::TriggerValueTarget::Negative:
if (num < 0)
return true;
else
return false;
default:
return false;
};
default:
return false;
};
}
void StateMachine::setState(const char* stateName, bool clearFields)
{
State oldState = mCurrentState;
StringTableEntry sName = StringTable->insert(stateName);
for (U32 i = 0; i < mStates.size(); i++)
{
//if(!dStrcmp(mStates[i]->stateName, stateName))
if (!dStrcmp(mStates[i].stateName,sName))
{
mCurrentState = mStates[i];
mStateStartTime = Sim::getCurrentTime();
onStateChanged.trigger(this, i);
return;
}
}
}
const char* StateMachine::getStateByIndex(S32 index)
{
if (index >= 0 && mStates.size() > index)
return mStates[index].stateName;
else
return "";
}
StateMachine::State& StateMachine::getStateByName(const char* name)
{
StringTableEntry stateName = StringTable->insert(name);
for (U32 i = 0; i < mStates.size(); i++)
{
if (!dStrcmp(stateName, mStates[i].stateName))
return mStates[i];
}
}
S32 StateMachine::findFieldByName(const char* name)
{
for (U32 i = 0; i < mFields.size(); i++)
{
if (!dStrcmp(mFields[i].name, name))
return i;
}
return -1;
}

View file

@ -0,0 +1,259 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _OBJECTTYPES_H_
#include "T3D/objectTypes.h"
#endif
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _XMLDOC_H_
#include "console/SimXMLDocument.h"
#endif
class StateMachine
{
public:
struct StateField
{
StringTableEntry name;
bool triggerBoolVal;
float triggerNumVal;
Point3F triggerVectorVal;
String triggerStringVal;
enum Type
{
BooleanType = 0,
NumberType,
VectorType,
StringType
}fieldType;
};
struct UniqueReference
{
SimObject* referenceObj;
const char* referenceVar;
const char* uniqueName;
};
struct StateTransition
{
struct Condition
{
enum TriggerValueTarget
{
Equals = 0,
GeaterThan,
LessThan,
GreaterOrEqual,
LessOrEqual,
True,
False,
Positive,
Negative,
DoesNotEqual
};
StateField field;
TriggerValueTarget triggerComparitor;
UniqueReference *valUniqueRef;
};
StringTableEntry mName;
StringTableEntry mStateTarget;
Vector<Condition> mTransitionRules;
};
struct State
{
Vector<StateTransition> mTransitions;
StringTableEntry stateName;
StringTableEntry callbackName;
};
StringTableEntry mStateMachineFile;
protected:
Vector<State> mStates;
Vector<StateField> mFields;
Vector<UniqueReference> mUniqueReferences;
State mCurrentState;
F32 mStateStartTime;
F32 mStateTime;
StringTableEntry mStartingState;
State *mCurCreateSuperState;
State *mCurCreateState;
SimObjectPtr<SimXMLDocument> mXMLReader;
public:
StateMachine();
virtual ~StateMachine();
void update();
void loadStateMachineFile();
void readStates();
void readTransitions(State &currentState);
void readConditions(StateTransition &newTransition);
void setState(const char* stateName, bool clearFields = true);
const char* getCurrentStateName() { return mCurrentState.stateName; }
State& getCurrentState() {
return mCurrentState;
}
S32 getStateCount() { return mStates.size(); }
const char* getStateByIndex(S32 index);
State& getStateByName(const char* name);
void checkTransitions(const char* slotName, const char* newValue);
bool passComparitorCheck(const char* var, StateTransition::Condition transitionRule);
S32 findFieldByName(const char* name);
S32 getFieldsCount() { return mFields.size(); }
StateField getField(U32 index)
{
if (index <= mFields.size())
return mFields[index];
}
Signal< void(StateMachine*, S32 stateIdx) > StateMachine::onStateChanged;
//
inline bool readStateName(State* state, SimXMLDocument* reader)
{
if (reader->pushFirstChildElement("Name"))
{
state->stateName = reader->getData();
reader->popElement();
return true;
}
return false;
}
inline bool readStateScriptFunction(State* state, SimXMLDocument* reader)
{
if (reader->pushFirstChildElement("ScriptFunction"))
{
state->callbackName = reader->getData();
reader->popElement();
return true;
}
return false;
}
inline bool readTransitonTarget(StateTransition* transition, SimXMLDocument* reader)
{
if (reader->pushFirstChildElement("StateTarget"))
{
transition->mStateTarget = reader->getData();
reader->popElement();
return true;
}
return false;
}
//
inline bool readFieldName(StateField* newField, SimXMLDocument* reader)
{
if (reader->pushFirstChildElement("FieldName"))
{
newField->name = reader->getData();
reader->popElement();
return true;
}
return false;
}
inline bool readFieldComparitor(StateTransition::Condition* condition, SimXMLDocument* reader)
{
if (reader->pushFirstChildElement("Comparitor"))
{
S32 compIdx = parseComparitor(reader->getData());
condition->triggerComparitor = static_cast<StateTransition::Condition::TriggerValueTarget>(compIdx);
reader->popElement();
return true;
}
return false;
}
inline bool readFieldValue(StateField* field, SimXMLDocument* reader)
{
if (reader->pushFirstChildElement("NumValue"))
{
field->fieldType = StateField::NumberType;
field->triggerNumVal = dAtof(reader->getData());
reader->popElement();
return true;
}
else if (reader->pushFirstChildElement("StringValue"))
{
field->fieldType = StateField::StringType;
field->triggerStringVal = reader->getData();
reader->popElement();
return true;
}
else if (reader->pushFirstChildElement("BoolValue"))
{
field->fieldType = StateField::BooleanType;
field->triggerBoolVal = dAtob(reader->getData());
reader->popElement();
return true;
}
return false;
}
private:
S32 parseComparitor(const char* comparitorName);
};
#endif

View file

@ -0,0 +1,215 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "T3D/components/game/StateMachinecomponent.h"
#include "platform/platform.h"
#include "console/consoleTypes.h"
#include "core/util/safeDelete.h"
#include "core/resourceManager.h"
#include "core/stream/fileStream.h"
#include "console/consoleTypes.h"
#include "console/consoleObject.h"
#include "ts/tsShapeInstance.h"
#include "core/stream/bitStream.h"
#include "gfx/gfxTransformSaver.h"
#include "console/engineAPI.h"
#include "lighting/lightQuery.h"
IMPLEMENT_CALLBACK( StateMachineComponent, onStateChange, void, (), (),
"@brief Called when we collide with another object.\n\n"
"@param obj The ShapeBase object\n"
"@param collObj The object we collided with\n"
"@param vec Collision impact vector\n"
"@param len Length of the impact vector\n" );
//////////////////////////////////////////////////////////////////////////
// Constructor/Destructor
//////////////////////////////////////////////////////////////////////////
StateMachineComponent::StateMachineComponent() : Component()
{
mFriendlyName = "State Machine";
mComponentType = "Game";
mDescription = getDescriptionText("A generic state machine.");
mStateMachineFile = "";
//doesn't need to be networked
mNetworked = false;
mNetFlags.clear();
}
StateMachineComponent::~StateMachineComponent()
{
for(S32 i = 0;i < mFields.size();++i)
{
ComponentField &field = mFields[i];
SAFE_DELETE_ARRAY(field.mFieldDescription);
}
SAFE_DELETE_ARRAY(mDescription);
}
IMPLEMENT_CO_NETOBJECT_V1(StateMachineComponent);
bool StateMachineComponent::onAdd()
{
if(! Parent::onAdd())
return false;
// Register for the resource change signal.
ResourceManager::get().getChangedSignal().notify(this, &StateMachineComponent::_onResourceChanged);
mStateMachine.onStateChanged.notify(this, &StateMachineComponent::onStateChanged);
return true;
}
void StateMachineComponent::onRemove()
{
Parent::onRemove();
}
U32 StateMachineComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
return retMask;
}
void StateMachineComponent::unpackUpdate(NetConnection *con, BitStream *stream)
{
Parent::unpackUpdate(con, stream);
}
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
void StateMachineComponent::onComponentAdd()
{
Parent::onComponentAdd();
}
void StateMachineComponent::onComponentRemove()
{
Parent::onComponentRemove();
}
void StateMachineComponent::initPersistFields()
{
Parent::initPersistFields();
addProtectedField("stateMachineFile", TypeFilename, Offset(mStateMachineFile, StateMachineComponent),
&_setSMFile, &defaultProtectedGetFn, "The sim time of when we started this state");
}
bool StateMachineComponent::_setSMFile(void *object, const char *index, const char *data)
{
StateMachineComponent* smComp = static_cast<StateMachineComponent*>(object);
if (smComp)
{
smComp->setStateMachineFile(data);
smComp->loadStateMachineFile();
return true;
}
return false;
}
void StateMachineComponent::_onResourceChanged(const Torque::Path &path)
{
if (path != Torque::Path(mStateMachineFile))
return;
loadStateMachineFile();
}
void StateMachineComponent::loadStateMachineFile()
{
if (!dStrIsEmpty(mStateMachineFile))
{
mStateMachine.mStateMachineFile = mStateMachineFile;
mStateMachine.loadStateMachineFile();
//now that it's loaded, we need to parse the SM's fields and set them as script vars on ourselves
S32 smFieldCount = mStateMachine.getFieldsCount();
for (U32 i = 0; i < smFieldCount; i++)
{
StateMachine::StateField field = mStateMachine.getField(i);
char buffer[128];
if (field.fieldType == StateMachine::StateField::BooleanType)
{
dSprintf(buffer, sizeof(buffer), "%b", field.triggerBoolVal);
setDataField(field.name, NULL, buffer);
}
else if (field.fieldType == StateMachine::StateField::NumberType)
{
dSprintf(buffer, sizeof(buffer), "%g", field.triggerNumVal);
setDataField(field.name, NULL, buffer);
}
else if (field.fieldType == StateMachine::StateField::StringType)
{
setDataField(field.name, NULL, field.triggerStringVal);
}
}
}
}
void StateMachineComponent::processTick()
{
if (!isServerObject() || !isActive())
return;
mStateMachine.update();
}
void StateMachineComponent::onDynamicModified( const char* slotName, const char* newValue )
{
Parent::onDynamicModified(slotName, newValue);
StringTableEntry fieldName = StringTable->insert(slotName);
mStateMachine.checkTransitions(fieldName, newValue);
}
void StateMachineComponent::onStaticModified( const char* slotName, const char* newValue )
{
Parent::onStaticModified(slotName, newValue);
StringTableEntry fieldName = StringTable->insert(slotName);
mStateMachine.checkTransitions(fieldName, newValue);
}
void StateMachineComponent::onStateChanged(StateMachine* sm, S32 stateIdx)
{
//do a script callback, if we have one
//check if we have a function for that, and then also check if our owner does
StringTableEntry callbackName = mStateMachine.getCurrentState().callbackName;
if (isMethod(callbackName))
Con::executef(this, callbackName);
if (mOwner->isMethod(callbackName))
Con::executef(mOwner, callbackName);
}

View file

@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef STATE_MACHINE_COMPONENT_H
#define STATE_MACHINE_COMPONENT_H
#ifndef COMPONENT_H
#include "T3D/components/component.h"
#endif
#ifndef STATE_MACHINE_H
#include "T3D/components/game/stateMachine.h"
#endif
//////////////////////////////////////////////////////////////////////////
///
///
//////////////////////////////////////////////////////////////////////////
class StateMachineComponent : public Component
{
typedef Component Parent;
public:
StateMachine mStateMachine;
protected:
StringTableEntry mStateMachineFile;
public:
StateMachineComponent();
virtual ~StateMachineComponent();
DECLARE_CONOBJECT(StateMachineComponent);
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void onComponentAdd();
virtual void onComponentRemove();
void _onResourceChanged(const Torque::Path &path);
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
virtual void processTick();
virtual void onDynamicModified(const char* slotName, const char* newValue);
virtual void onStaticModified(const char* slotName, const char* newValue);
virtual void loadStateMachineFile();
void setStateMachineFile(const char* fileName) { mStateMachineFile = StringTable->insert(fileName); }
static bool _setSMFile(void *object, const char *index, const char *data);
void onStateChanged(StateMachine* sm, S32 stateIdx);
//Callbacks
DECLARE_CALLBACK(void, onStateChange, ());
};
#endif

View file

@ -0,0 +1,358 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "T3D/components/game/Triggercomponent.h"
#include "core/util/safeDelete.h"
#include "console/consoleTypes.h"
#include "console/consoleObject.h"
#include "core/stream/bitStream.h"
#include "console/engineAPI.h"
#include "sim/netConnection.h"
#include "T3D/gameBase/gameConnection.h"
#include "T3D/components/coreInterfaces.h"
#include "math/mathUtils.h"
#include "collision/concretePolyList.h"
#include "collision/clippedPolyList.h"
#include "gfx/sim/debugDraw.h"
IMPLEMENT_CALLBACK( TriggerComponent, onEnterViewCmd, void,
( Entity* cameraEnt, bool firstTimeSeeing ), ( cameraEnt, firstTimeSeeing ),
"@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n"
"@param trigger the Trigger instance whose volume the object entered\n"
"@param obj the object that entered the volume of the Trigger instance\n" );
IMPLEMENT_CALLBACK( TriggerComponent, onExitViewCmd, void,
( Entity* cameraEnt ), ( cameraEnt ),
"@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n"
"@param trigger the Trigger instance whose volume the object entered\n"
"@param obj the object that entered the volume of the Trigger instance\n" );
IMPLEMENT_CALLBACK( TriggerComponent, onUpdateInViewCmd, void,
( Entity* cameraEnt ), ( cameraEnt ),
"@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n"
"@param trigger the Trigger instance whose volume the object entered\n"
"@param obj the object that entered the volume of the Trigger instance\n" );
IMPLEMENT_CALLBACK( TriggerComponent, onUpdateOutOfViewCmd, void,
( Entity* cameraEnt ), ( cameraEnt ),
"@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n"
"@param trigger the Trigger instance whose volume the object entered\n"
"@param obj the object that entered the volume of the Trigger instance\n" );
//////////////////////////////////////////////////////////////////////////
// Constructor/Destructor
//////////////////////////////////////////////////////////////////////////
TriggerComponent::TriggerComponent() : Component()
{
mObjectList.clear();
mVisible = false;
mFriendlyName = "Trigger";
mComponentType = "Trigger";
mDescription = getDescriptionText("Calls trigger events when a client starts and stops seeing it. Also ticks while visible to clients.");
}
TriggerComponent::~TriggerComponent()
{
for(S32 i = 0;i < mFields.size();++i)
{
ComponentField &field = mFields[i];
SAFE_DELETE_ARRAY(field.mFieldDescription);
}
SAFE_DELETE_ARRAY(mDescription);
}
IMPLEMENT_CO_NETOBJECT_V1(TriggerComponent);
bool TriggerComponent::onAdd()
{
if(! Parent::onAdd())
return false;
return true;
}
void TriggerComponent::onRemove()
{
Parent::onRemove();
}
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
void TriggerComponent::onComponentAdd()
{
Parent::onComponentAdd();
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
if(colInt)
{
colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
}
}
void TriggerComponent::onComponentRemove()
{
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
if(colInt)
{
colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
}
Parent::onComponentRemove();
}
void TriggerComponent::componentAddedToOwner(Component *comp)
{
if (comp->getId() == getId())
return;
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
if (colInt)
{
colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
}
}
void TriggerComponent::componentRemovedFromOwner(Component *comp)
{
if (comp->getId() == getId()) //?????????
return;
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
if (colInt)
{
colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
}
}
void TriggerComponent::initPersistFields()
{
Parent::initPersistFields();
addField("visibile", TypeBool, Offset( mVisible, TriggerComponent ), "" );
addField("onEnterViewCmd", TypeCommand, Offset(mEnterCommand, TriggerComponent), "");
addField("onExitViewCmd", TypeCommand, Offset(mOnExitCommand, TriggerComponent), "");
addField("onUpdateInViewCmd", TypeCommand, Offset(mOnUpdateInViewCmd, TriggerComponent), "");
}
U32 TriggerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
return retMask;
}
void TriggerComponent::unpackUpdate(NetConnection *con, BitStream *stream)
{
Parent::unpackUpdate(con, stream);
}
void TriggerComponent::potentialEnterObject(SceneObject *collider)
{
if(testObject(collider))
{
bool found = false;
for(U32 i=0; i < mObjectList.size(); i++)
{
if(mObjectList[i]->getId() == collider->getId())
{
found = true;
break;
}
}
if (!found)
{
mObjectList.push_back(collider);
if (!mEnterCommand.isEmpty())
{
String command = String("%obj = ") + collider->getIdString() + ";" +
String("%this = ") + getIdString() + ";" + mEnterCommand;
Con::evaluate(command.c_str());
}
//onEnterTrigger_callback(this, enter);
}
}
}
bool TriggerComponent::testObject(SceneObject* enter)
{
//First, test to early out
Box3F enterBox = enter->getWorldBox();
//if(!mOwner->getWorldBox().intersect(enterBox) || !)
// return false;
//We're still here, so we should do actual work
//We're going to be
ConcretePolyList mClippedList;
SphereF sphere;
sphere.center = (mOwner->getWorldBox().minExtents + mOwner->getWorldBox().maxExtents) * 0.5;
VectorF bv = mOwner->getWorldBox().maxExtents - sphere.center;
sphere.radius = bv.len();
Entity* enterEntity = dynamic_cast<Entity*>(enter);
if(enterEntity)
{
//quick early out. If the bounds don't overlap, it cannot be colliding or inside
if (!mOwner->getWorldBox().isOverlapped(enterBox))
return false;
//check if the entity has a collision shape
CollisionInterface *cI = enterEntity->getComponent<CollisionInterface>();
if (cI)
{
cI->buildPolyList(PLC_Collision, &mClippedList, mOwner->getWorldBox(), sphere);
if (!mClippedList.isEmpty())
{
//well, it's clipped with, or inside, our bounds
//now to test the clipped list against our own collision mesh
CollisionInterface *myCI = mOwner->getComponent<CollisionInterface>();
//wait, how would we NOT have this?
if (myCI)
{
//anywho, build our list and then we'll check intersections
ClippedPolyList myList;
myList.setTransform(&(mOwner->getTransform()), mOwner->getScale());
myList.setObject(mOwner);
myCI->buildPolyList(PLC_Collision, &myList, enterBox, sphere);
bool test = true;
}
}
}
}
return mClippedList.isEmpty() == false;
}
void TriggerComponent::processTick()
{
Parent::processTick();
if (!isActive())
return;
//get our list of active clients, and see if they have cameras, if they do, build a frustum and see if we exist inside that
mVisible = false;
if(isServerObject())
{
for(U32 i=0; i < mObjectList.size(); i++)
{
if(!testObject(mObjectList[i]))
{
if (!mOnExitCommand.isEmpty())
{
String command = String("%obj = ") + mObjectList[i]->getIdString() + ";" +
String("%this = ") + getIdString() + ";" + mOnExitCommand;
Con::evaluate(command.c_str());
}
mObjectList.erase(i);
//mDataBlock->onLeaveTrigger_callback( this, remove );
//onLeaveTrigger_callback(this, remove);
}
}
/*if (!mTickCommand.isEmpty())
Con::evaluate(mTickCommand.c_str());
if (mObjects.size() != 0)
onTickTrigger_callback(this);*/
}
}
void TriggerComponent::visualizeFrustums(F32 renderTimeMS)
{
}
GameConnection* TriggerComponent::getConnection(S32 connectionID)
{
for(NetConnection *conn = NetConnection::getConnectionList(); conn; conn = conn->getNext())
{
GameConnection* gameConn = dynamic_cast<GameConnection*>(conn);
if (!gameConn || (gameConn && gameConn->isAIControlled()))
continue;
if(connectionID == gameConn->getId())
return gameConn;
}
return NULL;
}
void TriggerComponent::addClient(S32 clientID)
{
}
void TriggerComponent::removeClient(S32 clientID)
{
}
DefineEngineMethod( TriggerComponent, addClient, void,
( S32 clientID ), ( -1 ),
"@brief Mount objB to this object at the desired slot with optional transform.\n\n"
"@param objB Object to mount onto us\n"
"@param slot Mount slot ID\n"
"@param txfm (optional) mount offset transform\n"
"@return true if successful, false if failed (objB is not valid)" )
{
if(clientID == -1)
return;
object->addClient( clientID );
}
DefineEngineMethod( TriggerComponent, removeClient, void,
( S32 clientID ), ( -1 ),
"@brief Mount objB to this object at the desired slot with optional transform.\n\n"
"@param objB Object to mount onto us\n"
"@param slot Mount slot ID\n"
"@param txfm (optional) mount offset transform\n"
"@return true if successful, false if failed (objB is not valid)" )
{
if(clientID == -1)
return;
object->removeClient( clientID );
}
DefineEngineMethod( TriggerComponent, visualizeFrustums, void,
(F32 renderTime), (1000),
"@brief Mount objB to this object at the desired slot with optional transform.\n\n"
"@param objB Object to mount onto us\n"
"@param slot Mount slot ID\n"
"@param txfm (optional) mount offset transform\n"
"@return true if successful, false if failed (objB is not valid)" )
{
object->visualizeFrustums(renderTime);
}

View file

@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _TRIGGER_COMPONENT_H_
#define _TRIGGER_COMPONENT_H_
#ifndef _COMPONENT_H_
#include "T3D/components/component.h"
#endif
#ifndef _ENTITY_H_
#include "T3D/entity.h"
#endif
#ifndef _COLLISION_INTERFACES_H_
#include "T3D/components/collision/collisionInterfaces.h"
#endif
//////////////////////////////////////////////////////////////////////////
///
///
//////////////////////////////////////////////////////////////////////////
class TriggerComponent : public Component
{
typedef Component Parent;
protected:
Vector<SceneObject*> mObjectList;
bool mVisible;
String mEnterCommand;
String mOnExitCommand;
String mOnUpdateInViewCmd;
public:
TriggerComponent();
virtual ~TriggerComponent();
DECLARE_CONOBJECT(TriggerComponent);
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void onComponentAdd();
virtual void onComponentRemove();
virtual void componentAddedToOwner(Component *comp);
virtual void componentRemovedFromOwner(Component *comp);
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
void potentialEnterObject(SceneObject *collider);
bool testObject(SceneObject* enter);
virtual void processTick();
GameConnection* getConnection(S32 connectionID);
void addClient(S32 clientID);
void removeClient(S32 clientID);
void visualizeFrustums(F32 renderTimeMS);
DECLARE_CALLBACK(void, onEnterViewCmd, (Entity* cameraEnt, bool firstTimeSeeing));
DECLARE_CALLBACK(void, onExitViewCmd, (Entity* cameraEnt));
DECLARE_CALLBACK(void, onUpdateInViewCmd, (Entity* cameraEnt));
DECLARE_CALLBACK(void, onUpdateOutOfViewCmd, (Entity* cameraEnt));
};
#endif // _EXAMPLEBEHAVIOR_H_