/* Crystal Space Entity Layer Copyright (C) 2005 by Jorrit Tyberghein This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "cssysdef.h" #include "csutil/scanstr.h" #include "csutil/xmltiny.h" #include "iutil/objreg.h" #include "iutil/document.h" #include "iutil/object.h" #include "iutil/vfs.h" #include "ivaria/reporter.h" #include "imap/services.h" #include "iengine/mesh.h" #include "physicallayer/pl.h" #include "physicallayer/propclas.h" #include "physicallayer/entitytpl.h" #include "behaviourlayer/bl.h" #include "propclass/mesh.h" #include "celtool/stdparams.h" #include "celentitytpl.h" //--------------------------------------------------------------------------- CS_IMPLEMENT_PLUGIN SCF_IMPLEMENT_FACTORY (celAddOnCelEntityTemplate) SCF_IMPLEMENT_IBASE (celAddOnCelEntityTemplate) SCF_IMPLEMENTS_INTERFACE (iLoaderPlugin) SCF_IMPLEMENTS_INTERFACE (iEntityTemplateLoader) SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent) SCF_IMPLEMENT_IBASE_END SCF_IMPLEMENT_EMBEDDED_IBASE (celAddOnCelEntityTemplate::Component) SCF_IMPLEMENTS_INTERFACE (iComponent) SCF_IMPLEMENT_EMBEDDED_IBASE_END enum { XMLTOKEN_BEHAVIOUR, XMLTOKEN_PROPCLASS, XMLTOKEN_PROPERTY, XMLTOKEN_ACTION, XMLTOKEN_CALL, XMLTOKEN_CLASS, XMLTOKEN_PAR, XMLTOKEN_FLOAT, XMLTOKEN_BOOL, XMLTOKEN_STRING, XMLTOKEN_LONG, XMLTOKEN_VECTOR, XMLTOKEN_VECTOR2, XMLTOKEN_VECTOR3, XMLTOKEN_COLOR }; celAddOnCelEntityTemplate::celAddOnCelEntityTemplate (iBase* parent) { SCF_CONSTRUCT_IBASE (parent); SCF_CONSTRUCT_EMBEDDED_IBASE (scfiComponent); object_reg = 0; } celAddOnCelEntityTemplate::~celAddOnCelEntityTemplate () { SCF_DESTRUCT_EMBEDDED_IBASE (scfiComponent); SCF_DESTRUCT_IBASE (); } bool celAddOnCelEntityTemplate::Initialize (iObjectRegistry* object_reg) { celAddOnCelEntityTemplate::object_reg = object_reg; synldr = CS_QUERY_REGISTRY (object_reg, iSyntaxService); if (!synldr) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR, "cel.addons.celentitytpl", "Can't find syntax services!"); return false; } pl = CS_QUERY_REGISTRY (object_reg, iCelPlLayer); if (!pl) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR, "cel.addons.celentitytpl", "Can't find physical layer!"); return false; } xmltokens.Register ("behaviour", XMLTOKEN_BEHAVIOUR); xmltokens.Register ("propclass", XMLTOKEN_PROPCLASS); xmltokens.Register ("property", XMLTOKEN_PROPERTY); xmltokens.Register ("action", XMLTOKEN_ACTION); xmltokens.Register ("call", XMLTOKEN_CALL); xmltokens.Register ("class", XMLTOKEN_CLASS); xmltokens.Register ("par", XMLTOKEN_PAR); xmltokens.Register ("float", XMLTOKEN_FLOAT); xmltokens.Register ("bool", XMLTOKEN_BOOL); xmltokens.Register ("string", XMLTOKEN_STRING); xmltokens.Register ("long", XMLTOKEN_LONG); xmltokens.Register ("vector", XMLTOKEN_VECTOR); xmltokens.Register ("vector2", XMLTOKEN_VECTOR2); xmltokens.Register ("vector3", XMLTOKEN_VECTOR3); xmltokens.Register ("color", XMLTOKEN_COLOR); return true; } const char* celAddOnCelEntityTemplate::GetAttributeValue (iDocumentNode* child, const char* propname) { const char* rc = child->GetAttributeValue (propname); if (!rc) { synldr->ReportError ( "cel.addons.celentitytpl", child, "Can't find attribute '%s'!", propname); return 0; } return rc; } csStringID celAddOnCelEntityTemplate::GetAttributeID (iDocumentNode* child, const char* prefix, const char* propname) { const char* rc = child->GetAttributeValue (propname); if (!rc) { synldr->ReportError ( "cel.addons.celentitytpl", child, "Can't find attribute '%s'!", propname); return csInvalidStringID; } csString p (prefix); p += rc; return pl->FetchStringID ((const char*)p); } csRef celAddOnCelEntityTemplate::ParseParameterBlock (iDocumentNode* child) { csRef params; params.AttachNew (new celVariableParameterBlock ()); csRef par_it = child->GetNodes (); size_t par_idx = 0; while (par_it->HasNext ()) { csRef par_child = par_it->Next (); if (par_child->GetType () != CS_NODE_ELEMENT) continue; const char* par_value = par_child->GetValue (); csStringID par_id = xmltokens.Request (par_value); if (par_id == XMLTOKEN_PAR) { csStringID parid = GetAttributeID (par_child, "cel.parameter.", "name"); if (parid == csInvalidStringID) return 0; params->SetParameterDef (par_idx, parid, par_child->GetAttributeValue ("name")); par_idx++; const char* str_value = par_child->GetAttributeValue ("string"); if (str_value) { if (*str_value == '$') params->GetParameter (par_idx-1).SetParameter (str_value+1, CEL_DATA_STRING); else params->GetParameter (par_idx-1).Set (str_value); continue; } const char* vec_value = par_child->GetAttributeValue ("vector"); if (vec_value) { if (*vec_value == '$') params->GetParameter (par_idx-1).SetParameter (vec_value+1, CEL_DATA_VECTOR3); else { csVector3 v; int rc = csScanStr (vec_value, "%f,%f,%f", &v.x, &v.y, &v.z); if (rc == 3) params->GetParameter (par_idx-1).Set (v); else { csVector2 v2; csScanStr (vec_value, "%f,%f", &v2.x, &v2.y); params->GetParameter (par_idx-1).Set (v2); } } continue; } const char* vec2_value = par_child->GetAttributeValue ("vector2"); if (vec2_value) { if (*vec2_value == '$') params->GetParameter (par_idx-1).SetParameter (vec2_value+1, CEL_DATA_VECTOR2); else { csVector2 v; csScanStr (vec2_value, "%f,%f", &v.x, &v.y); params->GetParameter (par_idx-1).Set (v); } continue; } const char* vec3_value = par_child->GetAttributeValue ("vector3"); if (vec3_value) { if (*vec3_value == '$') params->GetParameter (par_idx-1).SetParameter (vec3_value+1, CEL_DATA_VECTOR3); else { csVector3 v; csScanStr (vec3_value, "%f,%f,%f", &v.x, &v.y, &v.z); params->GetParameter (par_idx-1).Set (v); } continue; } const char* float_value = par_child->GetAttributeValue ("float"); if (float_value) { if (*float_value == '$') params->GetParameter (par_idx-1).SetParameter (float_value+1, CEL_DATA_FLOAT); else { float f; csScanStr (float_value, "%f", &f); params->GetParameter (par_idx-1).Set (f); } continue; } const char* bool_value = par_child->GetAttributeValue ("bool"); if (bool_value) { if (*bool_value == '$') params->GetParameter (par_idx-1).SetParameter (bool_value+1, CEL_DATA_BOOL); else { bool b; csScanStr (bool_value, "%b", &b); params->GetParameter (par_idx-1).Set (b); } continue; } const char* long_value = par_child->GetAttributeValue ("long"); if (long_value) { if (*long_value == '$') params->GetParameter (par_idx-1).SetParameter (long_value+1, CEL_DATA_LONG); else { int l; csScanStr (long_value, "%d", &l); params->GetParameter (par_idx-1).Set ((int32)l); } continue; } synldr->ReportError ( "cel.addons.celentitytpl", par_child, "Type for parameter not yet supported!"); return 0; } else { synldr->ReportBadToken (par_child); return 0; } } return params; } bool celAddOnCelEntityTemplate::ParseProperties (iCelPropertyClassTemplate* pc, iDocumentNode* node) { csRef it = node->GetNodes (); while (it->HasNext ()) { csRef child = it->Next (); if (child->GetType () != CS_NODE_ELEMENT) continue; const char* value = child->GetValue (); csStringID id = xmltokens.Request (value); switch (id) { case XMLTOKEN_PROPERTY: { csStringID propid = GetAttributeID (child, "cel.property.", "name"); if (propid == csInvalidStringID) return false; csRef attr_it = child->GetAttributes (); while (attr_it->HasNext ()) { csRef attr = attr_it->Next (); const char* attr_name = attr->GetName (); csStringID attr_id = xmltokens.Request (attr_name); const char* attr_value = attr->GetValue (); bool do_par = (attr_value && *attr_value == '$'); switch (attr_id) { case XMLTOKEN_FLOAT: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_FLOAT, attr_value+1); else pc->SetProperty (propid, attr->GetValueAsFloat ()); break; case XMLTOKEN_STRING: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_STRING, attr_value+1); else pc->SetProperty (propid, attr->GetValue ()); break; case XMLTOKEN_BOOL: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_BOOL, attr_value+1); else { const char* v = attr->GetValue (); bool b; csScanStr (v, "%b", &b); pc->SetProperty (propid, b); } break; case XMLTOKEN_LONG: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_LONG, attr_value+1); else pc->SetProperty (propid, (long)attr->GetValueAsInt ()); break; case XMLTOKEN_VECTOR: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_VECTOR3, attr_value+1); else { csVector3 v; int rc = csScanStr (attr->GetValue (), "%f,%f,%f", &v.x, &v.y, &v.z); if (rc == 3) pc->SetProperty (propid, v); else { csVector2 v2; csScanStr (attr->GetValue (), "%f,%f", &v2.x, &v2.y); pc->SetProperty (propid, v2); } } break; case XMLTOKEN_VECTOR2: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_VECTOR2, attr_value+1); else { csVector2 v; csScanStr (attr->GetValue (), "%f,%f", &v.x, &v.y); pc->SetProperty (propid, v); } break; case XMLTOKEN_VECTOR3: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_VECTOR3, attr_value+1); else { csVector3 v; csScanStr (attr->GetValue (), "%f,%f,%f", &v.x, &v.y, &v.z); pc->SetProperty (propid, v); } break; case XMLTOKEN_COLOR: if (do_par) pc->SetPropertyVariable (propid, CEL_DATA_COLOR, attr_value+1); else { csColor v; csScanStr (attr->GetValue (), "%f,%f,%f", &v.red, &v.green, &v.blue); pc->SetProperty (propid, v); } break; } } } break; case XMLTOKEN_ACTION: { csStringID propid = GetAttributeID (child, "cel.action.", "name"); if (propid == csInvalidStringID) return false; csRef params = ParseParameterBlock (child); if (!params) return false; pc->PerformAction (propid, params); } break; default: synldr->ReportBadToken (child); break; } } return true; } csPtr celAddOnCelEntityTemplate::Parse (iDocumentNode* node, iStreamSource*, iLoaderContext* ldr_context, iBase*) { iCelEntityTemplate* ent = Load (node); csRef ent_return = (iBase*)ent; return csPtr (ent_return); } iCelEntityTemplate* celAddOnCelEntityTemplate::Load (const char* path, const char* file) { csRef vfs = csQueryRegistry (object_reg); if (path) { vfs->PushDir (); vfs->ChDir (path); } csRef buf = vfs->Open (file, VFS_FILE_READ); if (!buf) { if (path) csReport (object_reg, CS_REPORTER_SEVERITY_ERROR, "cel.addons.celentitytpl", "Can't load file '%s' from '%s'!", file, path); else csReport (object_reg, CS_REPORTER_SEVERITY_ERROR, "cel.addons.celentitytpl", "Can't load file '%s'!", file); return 0; } csRef docsys = csQueryRegistry (object_reg); if (!docsys) docsys = csPtr (new csTinyDocumentSystem ()); csRef doc = docsys->CreateDocument (); const char* error = doc->Parse (buf, true); if (error != 0) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR, "cell.addons.celentitytpl", "Document system error for file '%s': %s!", file, error); return 0; } iCelEntityTemplate* tpl = Load (doc->GetRoot ()->GetNode ("addon")); if (path) { vfs->PopDir (); } return tpl; } iCelEntityTemplate* celAddOnCelEntityTemplate::Load (iDocumentNode* node) { const char* entityname = node->GetAttributeValue ("entityname"); if (!entityname) { synldr->ReportError ( "cel.addons.celentitytpl", node, "'entityname' is missing for this entity template!"); } csRef ent = pl->CreateEntityTemplate (entityname); csRef it = node->GetNodes (); while (it->HasNext ()) { csRef child = it->Next (); if (child->GetType () != CS_NODE_ELEMENT) continue; const char* value = child->GetValue (); csStringID id = xmltokens.Request (value); switch (id) { case XMLTOKEN_BEHAVIOUR: { const char* blname = child->GetAttributeValue ("layer"); const char* behavename = child->GetAttributeValue ("name"); if (!behavename) { synldr->ReportError ( "cel.addons.celentitytpl", child, "Name of the behaviour is missing!"); return 0; } ent->SetBehaviour (blname, behavename); } break; case XMLTOKEN_PROPCLASS: { iCelPropertyClassTemplate* pc; const char* name = child->GetAttributeValue ("name"); if (!name) { synldr->ReportError ( "cel.addons.celentitytpl", child, "Name of the property class is missing!"); return 0; } pc = ent->CreatePropertyClassTemplate (); pc->SetName (name); if (!ParseProperties (pc, child)) return 0; const char* tag = child->GetAttributeValue ("tag"); if (tag) pc->SetTag (tag); } break; case XMLTOKEN_CALL: { csRef params = ParseParameterBlock (child); if (!params) return 0; const char* msgid = child->GetAttributeValue ("event"); if (!msgid) { synldr->ReportError ( "cel.addons.celentitytpl", child, "'event' name is missing for call!"); return 0; } ent->AddMessage (msgid, params); } break; case XMLTOKEN_CLASS: { csStringID cls = pl->FetchStringID (child->GetContentsValue ()); ent->AddClass (cls); } break; default: synldr->ReportBadToken (child); break; } } return ent; }