#include "JsonExpression.h" #include "Chunk.h" #include "Game.h" JExpressionMemory::JExpressionMemory() : ReferenceCounter(), currentChunk(0) {} JExpressionMemory::~JExpressionMemory() { if (currentChunk) currentChunk->release(); } void JExpressionMemory::lock() { cs.lock(); } void JExpressionMemory::unlock() { cs.unlock(); } Noise* JExpressionMemory::zNoiseP(Framework::Text name) { return noises.z(name, name.getLength()); } void JExpressionMemory::setNoise(Framework::Text name, Noise* noise) { noises.set(name, name.getLength(), noise); } void JExpressionMemory::setCurrentChunk(Chunk* chunk) { if (currentChunk) currentChunk->release(); currentChunk = chunk; } float* JExpressionMemory::getFloatVariableP(const Framework::Text& name) { if (!floatVariables.contains(name, name.getLength())) { floatVariables.set(name, name.getLength(), 0.f); } return floatVariables.getP(name, name.getLength()); } bool* JExpressionMemory::getBoolVariableP(const Framework::Text& name) { if (!boolVariables.contains(name, name.getLength())) { boolVariables.set(name, name.getLength(), 0); } return boolVariables.getP(name, name.getLength()); } Chunk** JExpressionMemory::zzCurrentChunk() { return ¤tChunk; } JFloatExpression::JFloatExpression() : ReferenceCounter(), compiled(0) {} float JFloatExpression::getValue() { return compiled(); } FloatFunc JFloatExpression::compile(JExpressionMemory* zMemory) { if (compiled) { if (zMemory != memory) { throw "Cannot compile the same expression for different memories"; } return compiled; } memory = zMemory; return compiled = buildAssembly(zMemory).compileToFunction(); } JBoolExpression::JBoolExpression() : ReferenceCounter(), compiled(0) {} bool JBoolExpression::getValue() { return compiled(); } BoolFunc JBoolExpression::compile(JExpressionMemory* zMemory) { if (compiled) { if (zMemory != memory) { throw "Cannot compile the same expression for different " "memories"; } return compiled; } memory = zMemory; return compiled = buildAssembly(zMemory).compileToFunction(); } JVariableFloatExpression::JVariableFloatExpression() : JFloatExpression() {} Framework::Assembly::AssemblyBlock& JVariableFloatExpression::buildAssembly( JExpressionMemory* zMemory) { codeBlock.addLoadValue( zMemory->getFloatVariableP(name), Framework::Assembly::MM0); return codeBlock; } void JVariableFloatExpression::setName(Framework::Text name) { this->name = name; } Framework::Text JVariableFloatExpression::getName() const { return name; } JVariableFloatExpressionFactory::JVariableFloatExpressionFactory() : SubTypeFactory() {} JVariableFloatExpression* JVariableFloatExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JVariableFloatExpression* result = new JVariableFloatExpression(); result->setName(zJson->zValue("name")->asString()->getString()); return result; } Framework::JSON::JSONObject* JVariableFloatExpressionFactory::toJsonObject( JVariableFloatExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "name", new Framework::JSON::JSONString(zObject->getName())); return result; } JSONObjectValidationBuilder* JVariableFloatExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("name")->finishString(); } const char* JVariableFloatExpressionFactory::getTypeToken() const { return "variable"; } JVariableBoolExpression::JVariableBoolExpression() : JBoolExpression() {} Framework::Assembly::AssemblyBlock& JVariableBoolExpression::buildAssembly( JExpressionMemory* zMemory) { codeBlock.addLoadValue( (char*)zMemory->getBoolVariableP(name), Framework::Assembly::RAX); return codeBlock; } void JVariableBoolExpression::setName(Framework::Text name) { this->name = name; } Framework::Text JVariableBoolExpression::getName() const { return name; } JVariableBoolExpressionFactory::JVariableBoolExpressionFactory() : SubTypeFactory() {} JVariableBoolExpression* JVariableBoolExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JVariableBoolExpression* result = new JVariableBoolExpression(); result->setName(zJson->zValue("name")->asString()->getString()); return result; } Framework::JSON::JSONObject* JVariableBoolExpressionFactory::toJsonObject( JVariableBoolExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "name", new Framework::JSON::JSONString(zObject->getName())); return result; } JSONObjectValidationBuilder* JVariableBoolExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("name")->finishString(); } const char* JVariableBoolExpressionFactory::getTypeToken() const { return "variable"; } JConstantFloatExpression::JConstantFloatExpression() : JFloatExpression(), value(0) {} Framework::Assembly::AssemblyBlock& JConstantFloatExpression::buildAssembly( JExpressionMemory* zMemory) { codeBlock.addLoadValue(&value, Framework::Assembly::MM0); return codeBlock; } void JConstantFloatExpression::setValue(float value) { this->value = value; } float JConstantFloatExpression::getValue() const { return value; } JConstantFloatExpressionFactory::JConstantFloatExpressionFactory() : SubTypeFactory() {} JConstantFloatExpression* JConstantFloatExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JConstantFloatExpression* result = new JConstantFloatExpression(); result->setValue((float)zJson->zValue("value")->asNumber()->getNumber()); return result; } Framework::JSON::JSONObject* JConstantFloatExpressionFactory::toJsonObject( JConstantFloatExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "value", new Framework::JSON::JSONNumber(zObject->getValue())); return result; } JSONObjectValidationBuilder* JConstantFloatExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredNumber("value")->finishNumber(); } const char* JConstantFloatExpressionFactory::getTypeToken() const { return "constant"; } JConstantBoolExpression::JConstantBoolExpression() : JBoolExpression() {} Framework::Assembly::AssemblyBlock& JConstantBoolExpression::buildAssembly( JExpressionMemory* zMemory) { codeBlock.addMoveValue(Framework::Assembly::RAX, (char)(value ? 1 : 0)); return codeBlock; } void JConstantBoolExpression::setValue(bool value) { this->value = value; } bool JConstantBoolExpression::getValue() const { return value; } JConstantBoolExpressionFactory::JConstantBoolExpressionFactory() : SubTypeFactory() {} JConstantBoolExpression* JConstantBoolExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JConstantBoolExpression* result = new JConstantBoolExpression(); result->setValue(zJson->zValue("value")->asBool()->getBool()); return result; } Framework::JSON::JSONObject* JConstantBoolExpressionFactory::toJsonObject( JConstantBoolExpression* zObject) const { Framework::JSON::JSONObject* zResult = new Framework::JSON::JSONObject(); zResult->addValue( "value", new Framework::JSON::JSONBool(zObject->getValue())); return zResult; } JSONObjectValidationBuilder* JConstantBoolExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredBool("value")->finishBool(); } const char* JConstantBoolExpressionFactory::getTypeToken() const { return "constant"; } JNoiseFloatExpression::JNoiseFloatExpression() : JFloatExpression(), x(0), y(0), z(0) {} JNoiseFloatExpression::~JNoiseFloatExpression() { if (x) x->release(); if (y) y->release(); if (z) z->release(); } Framework::Assembly::AssemblyBlock& JNoiseFloatExpression::buildAssembly( JExpressionMemory* zMemory) { Noise* noise = zMemory->zNoiseP(name); if (!noise) { Framework::Logging::error() << "no noise with name '" << name.getText() << "' found, behavior is undefined\n"; return codeBlock; } Framework::Assembly::AssemblyBlock& xBlock = x->buildAssembly(zMemory); Framework::Assembly::AssemblyBlock& yBlock = y->buildAssembly(zMemory); Framework::Assembly::AssemblyBlock& zBlock = z->buildAssembly(zMemory); Framework::Assembly::FPRegister xTarget = Framework::Assembly::MM0; if (xBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM1)) { xBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM1); xTarget = Framework::Assembly::MM1; } Framework::Assembly::FPRegister yTarget = Framework::Assembly::MM0; if (yBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM2)) { yBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM2); yTarget = Framework::Assembly::MM2; } Framework::Assembly::FPRegister zTarget = Framework::Assembly::MM0; if (zBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM3)) { zBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM3); zTarget = Framework::Assembly::MM3; } codeBlock.addBlock(&zBlock, {}, {}, {}, 0, &zTarget); if (zTarget != Framework::Assembly::MM3) { codeBlock.addMoveValue(Framework::Assembly::MM3, zTarget, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } codeBlock.addBlock(&yBlock, {}, {Framework::Assembly::MM3}, {Framework::Assembly::SINGLE_FLOAT}, 0, &yTarget); if (yTarget != Framework::Assembly::MM2) { codeBlock.addMoveValue(Framework::Assembly::MM2, yTarget, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } codeBlock.addBlock(&xBlock, {}, {Framework::Assembly::MM2, Framework::Assembly::MM3}, {Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::SINGLE_FLOAT}, 0, &xTarget); if (xTarget != Framework::Assembly::MM1) { codeBlock.addMoveValue(Framework::Assembly::MM1, xTarget, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } codeBlock.addLoadAddress(noise, Framework::Assembly::RCX); codeBlock.addMemberCall( &Noise::getNoise, Framework::Assembly::FLOAT_VALUE, {Framework::Assembly::RCX}, {Framework::Assembly::MM1, Framework::Assembly::MM2, Framework::Assembly::MM3}); return codeBlock; } void JNoiseFloatExpression::setName(Framework::Text name) { this->name = name; } Framework::Text JNoiseFloatExpression::getName() const { return name; } void JNoiseFloatExpression::setX(JFloatExpression* x) { if (this->x) this->x->release(); this->x = x; } JFloatExpression* JNoiseFloatExpression::zX() const { return x; } void JNoiseFloatExpression::setY(JFloatExpression* y) { if (this->y) this->y->release(); this->y = y; } JFloatExpression* JNoiseFloatExpression::zY() const { return y; } void JNoiseFloatExpression::setZ(JFloatExpression* z) { if (this->z) this->z->release(); this->z = z; } JFloatExpression* JNoiseFloatExpression::zZ() const { return z; } JNoiseFloatExpressionFactory::JNoiseFloatExpressionFactory() : SubTypeFactory() {} JNoiseFloatExpression* JNoiseFloatExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JNoiseFloatExpression* result = new JNoiseFloatExpression(); result->setName(zJson->zValue("name")->asString()->getString()); result->setX(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("x"))); result->setY(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("y"))); result->setZ(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("z"))); return result; } Framework::JSON::JSONObject* JNoiseFloatExpressionFactory::toJsonObject( JNoiseFloatExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "name", new Framework::JSON::JSONString(zObject->getName())); result->addValue( "x", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zX())); result->addValue( "y", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zY())); result->addValue( "z", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zZ())); return result; } JSONObjectValidationBuilder* JNoiseFloatExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("name") ->finishString() ->withRequiredAttribute("x", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("y", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("z", Game::INSTANCE->zTypeRegistry()->getValidator()); } const char* JNoiseFloatExpressionFactory::getTypeToken() const { return "noise"; } JOperatorFloatExpression::JOperatorFloatExpression() : JFloatExpression() {} Framework::Assembly::AssemblyBlock& JOperatorFloatExpression::buildAssembly( JExpressionMemory* zMemory) { bool first = 1; if (!values.getEintragAnzahl()) { codeBlock.addMoveValue(Framework::Assembly::MM0, 0.f); } for (JFloatExpression* expression : values) { if (first) { first = 0; codeBlock.addBlock( &expression->buildAssembly(zMemory), {}, {}, {}, 0, 0); } else { Framework::Assembly::AssemblyBlock& exprBlock = expression->buildAssembly(zMemory); if (exprBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM1)) { exprBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM1); } else { exprBlock.addMoveValue(Framework::Assembly::MM1, Framework::Assembly::MM0, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } codeBlock.addBlock(&exprBlock, {}, {Framework::Assembly::MM0}, {Framework::Assembly::SINGLE_FLOAT}, 0, 0); if (op.istGleich("+")) { codeBlock.addAddition(Framework::Assembly::MM0, Framework::Assembly::MM1, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } else if (op.istGleich("-")) { codeBlock.addSubtraction(Framework::Assembly::MM0, Framework::Assembly::MM1, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } else if (op.istGleich("*")) { codeBlock.addMultiplication(Framework::Assembly::MM0, Framework::Assembly::MM1, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } else if (op.istGleich("/")) { codeBlock.addDivision(Framework::Assembly::MM0, Framework::Assembly::MM1, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } } } return codeBlock; } void JOperatorFloatExpression::setOperator(Framework::Text op) { this->op = op; } Framework::Text JOperatorFloatExpression::getOperator() { return op; } void JOperatorFloatExpression::addValue(JFloatExpression* value) { values.add(value); } const Framework::RCArray& JOperatorFloatExpression::getValues() const { return values; } JOperatorFloatExpressionFactory::JOperatorFloatExpressionFactory() : SubTypeFactory() {} JOperatorFloatExpression* JOperatorFloatExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JOperatorFloatExpression* result = new JOperatorFloatExpression(); result->setOperator(zJson->zValue("operator")->asString()->getString()); for (Framework::JSON::JSONValue* value : *zJson->zValue("values")->asArray()) { result->addValue( Game::INSTANCE->zTypeRegistry()->fromJson(value)); } return result; } Framework::JSON::JSONObject* JOperatorFloatExpressionFactory::toJsonObject( JOperatorFloatExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "operator", new Framework::JSON::JSONString(zObject->getOperator())); Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray(); for (JFloatExpression* expression : zObject->getValues()) { values->addValue( Game::INSTANCE->zTypeRegistry()->toJson( expression)); } result->addValue("values", values); return result; } JSONObjectValidationBuilder* JOperatorFloatExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("operator") ->whichIsOneOf({"+", "-", "*", "/"}) ->finishString() ->withRequiredArray("values") ->addAcceptedTypeInArray( Game::INSTANCE->zTypeRegistry()->getValidator()) ->finishArray(); } const char* JOperatorFloatExpressionFactory::getTypeToken() const { return "operator"; } JBoolOperatorBoolExpression::JBoolOperatorBoolExpression() : JBoolExpression() {} Framework::Assembly::AssemblyBlock& JBoolOperatorBoolExpression::buildAssembly( JExpressionMemory* zMemory) { bool first = 1; if (!values.getEintragAnzahl()) { codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0); } for (JBoolExpression* expression : values) { if (first) { first = 0; codeBlock.addBlock( &expression->buildAssembly(zMemory), {}, {}, {}, 0, 0); } else { Framework::Assembly::AssemblyBlock& exprBlock = expression->buildAssembly(zMemory); if (exprBlock.isReplacementPossible( Framework::Assembly::RAX, Framework::Assembly::RCX)) { exprBlock.replaceRegister( Framework::Assembly::RAX, Framework::Assembly::RCX); } else { exprBlock.addMoveValue(Framework::Assembly::RCX, Framework::Assembly::RAX, Framework::Assembly::LOWER8); } codeBlock.addBlock( &exprBlock, {Framework::Assembly::RAX}, {}, {}, 0, 0); if (op.istGleich("&&")) { codeBlock.addAnd(Framework::Assembly::RAX, Framework::Assembly::RCX, Framework::Assembly::LOWER8); } else if (op.istGleich("||")) { codeBlock.addOr(Framework::Assembly::RAX, Framework::Assembly::RCX, Framework::Assembly::LOWER8); } } } return codeBlock; } void JBoolOperatorBoolExpression::setOperator(Framework::Text op) { this->op = op; } Framework::Text JBoolOperatorBoolExpression::getOperator() { return op; } void JBoolOperatorBoolExpression::addValue(JBoolExpression* value) { values.add(value); } const Framework::RCArray& JBoolOperatorBoolExpression::getValues() const { return values; } JBoolOperatorBoolExpressionFactory::JBoolOperatorBoolExpressionFactory() : SubTypeFactory() {} JBoolOperatorBoolExpression* JBoolOperatorBoolExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JBoolOperatorBoolExpression* result = new JBoolOperatorBoolExpression(); for (Framework::JSON::JSONValue* value : *zJson->zValue("values")->asArray()) { result->addValue( Game::INSTANCE->zTypeRegistry()->fromJson(value)); } result->setOperator(zJson->zValue("operator")->asString()->getString()); return result; } Framework::JSON::JSONObject* JBoolOperatorBoolExpressionFactory::toJsonObject( JBoolOperatorBoolExpression* zObject) const { Framework::JSON::JSONObject* zResult = new Framework::JSON::JSONObject(); Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray(); for (JBoolExpression* expression : zObject->getValues()) { values->addValue( Game::INSTANCE->zTypeRegistry()->toJson( expression)); } zResult->addValue("values", values); zResult->addValue( "operator", new Framework::JSON::JSONString(zObject->getOperator())); return zResult; } JSONObjectValidationBuilder* JBoolOperatorBoolExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("operator") ->whichIsOneOf({"&&", "||"}) ->finishString() ->withRequiredArray("values") ->addAcceptedTypeInArray( Game::INSTANCE->zTypeRegistry()->getValidator()) ->finishArray(); } const char* JBoolOperatorBoolExpressionFactory::getTypeToken() const { return "operator"; } JFloatOperatorBoolExpression::JFloatOperatorBoolExpression() : JBoolExpression() {} Framework::Assembly::AssemblyBlock& JFloatOperatorBoolExpression::buildAssembly( JExpressionMemory* zMemory) { bool first = 1; Framework::Assembly::FPRegister lastResultSorage = Framework::Assembly::MM0; for (JFloatExpression* expression : values) { if (first) { first = 0; codeBlock.addBlock( &expression->buildAssembly(zMemory), {}, {}, {}, 0, 0); } else { Framework::Assembly::FPRegister currentResultSorage = lastResultSorage == Framework::Assembly::MM0 ? Framework::Assembly::MM1 : Framework::Assembly::MM0; Framework::Assembly::AssemblyBlock& exprBlock = expression->buildAssembly(zMemory); if (currentResultSorage != Framework::Assembly::MM0) { if (exprBlock.isReplacementPossible( Framework::Assembly::MM0, currentResultSorage)) { exprBlock.replaceRegister( Framework::Assembly::MM0, currentResultSorage); } else { exprBlock.addMoveValue(currentResultSorage, Framework::Assembly::MM0, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::X); } } codeBlock.addBlock(&exprBlock, {}, {lastResultSorage}, {Framework::Assembly::SINGLE_FLOAT}, 0, 0); Framework::Assembly::Operation jumpOp = Framework::Assembly::NOP; bool needConversion = false; if (op.istGleich(">")) { jumpOp = Framework::Assembly::JBE; // jump if below or equal } else if (op.istGleich("<")) { jumpOp = Framework::Assembly::JNB; // jump if not below } else if (op.istGleich(">=")) { jumpOp = Framework::Assembly::JB; // jump if below } else if (op.istGleich("<=")) { jumpOp = Framework::Assembly::JA; // jump if above } else if (op.istGleich("==")) { jumpOp = Framework::Assembly::JNE; // jump if not equal } else if (op.istGleich("!=")) { jumpOp = Framework::Assembly::JE; // jump if equal } else { needConversion = true; if (op.istGleich(">i")) { jumpOp = Framework::Assembly::JLE; // jump if less or equal } else if (op.istGleich("=i")) { jumpOp = Framework::Assembly::JL; // jump if less } else if (op.istGleich("<=i")) { jumpOp = Framework::Assembly::JG; // jump if greater } else if (op.istGleich("==i")) { jumpOp = Framework::Assembly::JNE; // jump if not equal } else if (op.istGleich("!=i")) { jumpOp = Framework::Assembly::JE; // jump if equal } } if (needConversion) { codeBlock.addConversion(Framework::Assembly::RAX, lastResultSorage, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32); codeBlock.addConversion(Framework::Assembly::RCX, currentResultSorage, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32); codeBlock.addCompare(Framework::Assembly::RAX, Framework::Assembly::RCX, Framework::Assembly::LOWER32); } else { codeBlock.addCompare(lastResultSorage, currentResultSorage, Framework::Assembly::SINGLE_FLOAT); } codeBlock.addJump(jumpOp, "end_false"); lastResultSorage = currentResultSorage; } } codeBlock.addMoveValue(Framework::Assembly::RAX, (char)1); codeBlock.addJump(Framework::Assembly::JMP, "end"); codeBlock.defineJumpTarget("end_false"); codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0); codeBlock.defineJumpTarget("end"); return codeBlock; } void JFloatOperatorBoolExpression::setOperator(Framework::Text op) { this->op = op; } Framework::Text JFloatOperatorBoolExpression::getOperator() { return op; } void JFloatOperatorBoolExpression::addValue(JFloatExpression* value) { values.add(value); } const Framework::RCArray& JFloatOperatorBoolExpression::getValues() const { return values; } JFloatOperatorBoolExpressionFactory::JFloatOperatorBoolExpressionFactory() : SubTypeFactory() {} JFloatOperatorBoolExpression* JFloatOperatorBoolExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JFloatOperatorBoolExpression* result = new JFloatOperatorBoolExpression(); result->setOperator(zJson->zValue("operator")->asString()->getString()); for (Framework::JSON::JSONValue* value : *zJson->zValue("values")->asArray()) { result->addValue( Game::INSTANCE->zTypeRegistry()->fromJson(value)); } return result; } Framework::JSON::JSONObject* JFloatOperatorBoolExpressionFactory::toJsonObject( JFloatOperatorBoolExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "operator", new Framework::JSON::JSONString(zObject->getOperator())); Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray(); for (JFloatExpression* expression : zObject->getValues()) { values->addValue( Game::INSTANCE->zTypeRegistry()->toJson( expression)); } result->addValue("values", values); return result; } JSONObjectValidationBuilder* JFloatOperatorBoolExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder->withRequiredString("operator") ->whichIsOneOf({">", "<", ">=", "<=", "==", "!=", "i", ">=i", "<=i", "==i", "!=i"}) ->finishString() ->withRequiredArray("values") ->addAcceptedTypeInArray( Game::INSTANCE->zTypeRegistry()->getValidator()) ->finishArray(); } const char* JFloatOperatorBoolExpressionFactory::getTypeToken() const { return "comparsion"; } JSpecificBlockBoolExpression::JSpecificBlockBoolExpression() : JBoolExpression(), filter(0), x(0), y(0), z(0) {} JSpecificBlockBoolExpression::~JSpecificBlockBoolExpression() { if (filter) filter->release(); if (x) x->release(); if (y) y->release(); if (z) z->release(); } bool JSpecificBlockBoolExpression::isValidPosition( int x, int y, Chunk* currentChunk) { return currentChunk && Game::getChunkCenter(x, y) == currentChunk->getCenter(); } Framework::Assembly::AssemblyBlock& JSpecificBlockBoolExpression::buildAssembly( JExpressionMemory* zMemory) { Framework::Assembly::AssemblyBlock& xBlock = x->buildAssembly(zMemory); Framework::Assembly::AssemblyBlock& yBlock = y->buildAssembly(zMemory); Framework::Assembly::AssemblyBlock& zBlock = z->buildAssembly(zMemory); Framework::Assembly::FPRegister xTarget = Framework::Assembly::MM0; if (xBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM1)) { xBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM1); xTarget = Framework::Assembly::MM1; } Framework::Assembly::FPRegister yTarget = Framework::Assembly::MM0; if (yBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM2)) { yBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM2); yTarget = Framework::Assembly::MM2; } Framework::Assembly::FPRegister zTarget = Framework::Assembly::MM0; if (zBlock.isReplacementPossible( Framework::Assembly::MM0, Framework::Assembly::MM3)) { zBlock.replaceRegister( Framework::Assembly::MM0, Framework::Assembly::MM3); zTarget = Framework::Assembly::MM3; } codeBlock.addBlock(&zBlock, {}, {}, {}, 0, &zTarget); codeBlock.addConversion(Framework::Assembly::R9, zTarget, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32, 1); codeBlock.addTest(Framework::Assembly::R9, Framework::Assembly::R9, Framework::Assembly::LOWER32); codeBlock.addJump(Framework::Assembly::JL, "end_false"); codeBlock.addCompare(Framework::Assembly::R9, WORLD_HEIGHT); codeBlock.addJump(Framework::Assembly::JGE, "end_false"); codeBlock.addBlock(&yBlock, {Framework::Assembly::R9}, {}, {}, 0, &yTarget); codeBlock.addConversion(Framework::Assembly::R8, yTarget, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32, 1); codeBlock.addBlock(&xBlock, {Framework::Assembly::R8, Framework::Assembly::R9}, {}, {}, 0, &xTarget); codeBlock.addConversion(Framework::Assembly::RDX, xTarget, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32, 1); codeBlock.addLoadAddress(this, Framework::Assembly::RCX); codeBlock.addPush(Framework::Assembly::RDX, Framework::Assembly::LOWER32); codeBlock.addPush(Framework::Assembly::R8, Framework::Assembly::LOWER32); codeBlock.addPush(Framework::Assembly::R9, Framework::Assembly::LOWER32); codeBlock.addLoadValue( (__int64*)zMemory->zzCurrentChunk(), Framework::Assembly::R9); codeBlock.addMemberCall(&JSpecificBlockBoolExpression::isValidPosition, Framework::Assembly::INT_VALUE, {Framework::Assembly::R9}, {}); codeBlock.addPop(Framework::Assembly::R9, Framework::Assembly::LOWER32); codeBlock.addPop(Framework::Assembly::R8, Framework::Assembly::LOWER32); codeBlock.addPop(Framework::Assembly::RDX, Framework::Assembly::LOWER32); codeBlock.addTest(Framework::Assembly::RAX, Framework::Assembly::RAX, Framework::Assembly::LOWER8); codeBlock.addJump(Framework::Assembly::JZ, "end"); codeBlock.addLoadValue( (__int64*)zMemory->zzCurrentChunk(), Framework::Assembly::RCX); codeBlock.addMemberCall( &Chunk::zBlockConstWC, Framework::Assembly::INT_VALUE, {Framework::Assembly::RCX, Framework::Assembly::RDX, Framework::Assembly::R8, Framework::Assembly::R9}, {}); codeBlock.addMoveValue(Framework::Assembly::RDX, Framework::Assembly::RAX); codeBlock.addLoadValue((__int64*)&filter, Framework::Assembly::RCX); codeBlock.addMemberCall( &BlockFilter::test, Framework::Assembly::INT_VALUE, {Framework::Assembly::RCX, Framework::Assembly::RDX}, {}); codeBlock.addTest(Framework::Assembly::RAX, Framework::Assembly::RAX, Framework::Assembly::LOWER8); codeBlock.addJump(Framework::Assembly::JZ, "end"); codeBlock.addMoveValue(Framework::Assembly::RAX, (char)1); codeBlock.addJump(Framework::Assembly::JMP, "end"); codeBlock.defineJumpTarget("end_false"); codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0); codeBlock.defineJumpTarget("end"); return codeBlock; } void JSpecificBlockBoolExpression::setFilter(BlockFilter* filter) { if (this->filter) { this->filter->release(); } this->filter = filter; } BlockFilter* JSpecificBlockBoolExpression::zFilter() const { return filter; } void JSpecificBlockBoolExpression::setX(JFloatExpression* x) { if (this->x) this->x->release(); this->x = x; } JFloatExpression* JSpecificBlockBoolExpression::zX() const { return x; } void JSpecificBlockBoolExpression::setY(JFloatExpression* y) { if (this->y) this->y->release(); this->y = y; } JFloatExpression* JSpecificBlockBoolExpression::zY() const { return y; } void JSpecificBlockBoolExpression::setZ(JFloatExpression* z) { if (this->z) this->z->release(); this->z = z; } JFloatExpression* JSpecificBlockBoolExpression::zZ() const { return z; } JSpecificBlockBoolExpressionFactory::JSpecificBlockBoolExpressionFactory() : SubTypeFactory() {} JSpecificBlockBoolExpression* JSpecificBlockBoolExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JSpecificBlockBoolExpression* result = new JSpecificBlockBoolExpression(); result->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("condition"))); result->setX(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("x"))); result->setY(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("y"))); result->setZ(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("z"))); return result; } Framework::JSON::JSONObject* JSpecificBlockBoolExpressionFactory::toJsonObject( JSpecificBlockBoolExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue("condition", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter())); result->addValue( "x", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zX())); result->addValue( "y", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zY())); result->addValue( "z", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zZ())); return result; } JSONObjectValidationBuilder* JSpecificBlockBoolExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder ->withRequiredAttribute("condition", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("x", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("y", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("z", Game::INSTANCE->zTypeRegistry()->getValidator()); } const char* JSpecificBlockBoolExpressionFactory::getTypeToken() const { return "specificBlockMatches"; } JFirstBlockAboveBoolExpression::JFirstBlockAboveBoolExpression() : JBoolExpression(), filter(0), maxDistance(0) {} JFirstBlockAboveBoolExpression::~JFirstBlockAboveBoolExpression() { if (filter) filter->release(); } Framework::Assembly::AssemblyBlock& JFirstBlockAboveBoolExpression::buildAssembly(JExpressionMemory* zMemory) { // load x into R12 codeBlock.addLoadValue( zMemory->getFloatVariableP("x"), Framework::Assembly::MM0); codeBlock.addConversion(Framework::Assembly::R12, Framework::Assembly::MM0, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32, 1); // load y into R13 codeBlock.addLoadValue( zMemory->getFloatVariableP("y"), Framework::Assembly::MM0); codeBlock.addConversion(Framework::Assembly::R13, Framework::Assembly::MM0, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32, 1); // load z into R14 codeBlock.addLoadValue( zMemory->getFloatVariableP("z"), Framework::Assembly::MM0); codeBlock.addConversion(Framework::Assembly::R14, Framework::Assembly::MM0, Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::LOWER32, 1); // load current chunk into R15 codeBlock.addLoadValue( (__int64*)zMemory->zzCurrentChunk(), Framework::Assembly::R15); if (maxDistance) { // calculate loop end codeBlock.addMoveValue( Framework::Assembly::RBX, Framework::Assembly::R14); codeBlock.addAddition(Framework::Assembly::RBX, maxDistance + 1); codeBlock.addCompare(Framework::Assembly::RBX, WORLD_HEIGHT); codeBlock.addJump(Framework::Assembly::JL, "continue"); codeBlock.addMoveValue(Framework::Assembly::RBX, WORLD_HEIGHT); codeBlock.defineJumpTarget("continue"); } // begin loop to check above blocks codeBlock.defineJumpTarget("loop_start"); // increment height codeBlock.addAddition( Framework::Assembly::R14, (char)1, Framework::Assembly::LOWER32); // check if height is above loop end if (maxDistance) { codeBlock.addCompare(Framework::Assembly::R14, Framework::Assembly::RBX, Framework::Assembly::LOWER32); } else { codeBlock.addCompare(Framework::Assembly::R14, WORLD_HEIGHT); } codeBlock.addJump(Framework::Assembly::JGE, "end_false"); // load block type at current position into RAX codeBlock.addMoveValue(Framework::Assembly::RCX, Framework::Assembly::R15); codeBlock.addMoveValue(Framework::Assembly::RDX, Framework::Assembly::R12); codeBlock.addMoveValue(Framework::Assembly::R8, Framework::Assembly::R13); codeBlock.addMoveValue(Framework::Assembly::R9, Framework::Assembly::R14); if (maxDistance) { // save loop end in RBX for later comparison codeBlock.addPush( Framework::Assembly::RBX, Framework::Assembly::LOWER32); } codeBlock.addMemberCall( &Chunk::getBlockTypeAtWC, Framework::Assembly::INT_VALUE, {Framework::Assembly::RCX, Framework::Assembly::RDX, Framework::Assembly::R8, Framework::Assembly::R9}, {}); if (maxDistance) { // restore loop end from stack codeBlock.addPop( Framework::Assembly::RBX, Framework::Assembly::LOWER32); } // check if block type is 0 (NO_BLOCK) or 1 (AIR) codeBlock.addCompare(Framework::Assembly::RAX, 1); codeBlock.addJump(Framework::Assembly::JLE, "loop_start"); // end of loop // load current block into RDX codeBlock.addMoveValue(Framework::Assembly::RCX, Framework::Assembly::R15); codeBlock.addMoveValue(Framework::Assembly::RDX, Framework::Assembly::R12); codeBlock.addMoveValue(Framework::Assembly::R8, Framework::Assembly::R13); codeBlock.addMoveValue(Framework::Assembly::R9, Framework::Assembly::R14); codeBlock.addMemberCall( &Chunk::zBlockConstWC, Framework::Assembly::INT_VALUE, {Framework::Assembly::RCX, Framework::Assembly::RDX, Framework::Assembly::R8, Framework::Assembly::R9}, {}); codeBlock.addMoveValue(Framework::Assembly::RDX, Framework::Assembly::RAX); // load filter into RCX codeBlock.addLoadValue((__int64*)&filter, Framework::Assembly::RCX); // check filter condition codeBlock.addMemberCall( &BlockFilter::test, Framework::Assembly::INT_VALUE, {Framework::Assembly::RCX, Framework::Assembly::RDX}, {}); codeBlock.addJump(Framework::Assembly::JMP, "end"); codeBlock.defineJumpTarget("end_false"); codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0); codeBlock.defineJumpTarget("end"); return codeBlock; } void JFirstBlockAboveBoolExpression::setFilter(BlockFilter* filter) { if (this->filter) { this->filter->release(); } this->filter = filter; } BlockFilter* JFirstBlockAboveBoolExpression::zFilter() const { return filter; } void JFirstBlockAboveBoolExpression::setMaxDistance(short maxDistance) { this->maxDistance = maxDistance; } short JFirstBlockAboveBoolExpression::getMaxDistance() const { return maxDistance; } JFirstBlockAboveBoolExpressionFactory::JFirstBlockAboveBoolExpressionFactory() : SubTypeFactory() {} JFirstBlockAboveBoolExpression* JFirstBlockAboveBoolExpressionFactory::fromJson( Framework::JSON::JSONObject* zJson) const { JFirstBlockAboveBoolExpression* result = new JFirstBlockAboveBoolExpression(); result->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("condition"))); if (zJson->hasValue("maxDistance")) { result->setMaxDistance( (short)zJson->zValue("maxDistance")->asNumber()->getNumber()); } return result; } Framework::JSON::JSONObject* JFirstBlockAboveBoolExpressionFactory::toJsonObject( JFirstBlockAboveBoolExpression* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue("condition", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter())); if (zObject->getMaxDistance()) { result->addValue("maxDistance", new Framework::JSON::JSONNumber(zObject->getMaxDistance())); } return result; } JSONObjectValidationBuilder* JFirstBlockAboveBoolExpressionFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder ->withRequiredAttribute("condition", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withOptionalNumber("maxDistance") ->whichIsGreaterThen(0) ->whichIsLessThen(WORLD_HEIGHT) ->finishNumber(); } const char* JFirstBlockAboveBoolExpressionFactory::getTypeToken() const { return "firstBlockAboveMatches"; }