void JitBlockCache::InvalidateICache(u32 address, const u32 length) { // Convert the logical address to a physical address for the block map const u32 pAddr = address & 0x1FFFFFFF; const u32 pEnd = pAddr + length; // Blocks may start and end in overlapping ways, and destroying one invalidates iterators. // So after destroying one, we start over. do { restart: auto next = block_map_.lower_bound(std::make_pair(pAddr, 0)); auto last = block_map_.upper_bound(std::make_pair(pEnd + MAX_BLOCK_INSTRUCTIONS, 0)); // Note that if next is end(), last will be end() too (equal.) for (; next != last; ++next) { const u32 blockStart = next->first.second; const u32 blockEnd = next->first.first; if (blockStart < pEnd && blockEnd > pAddr) { DestroyBlock(next->second, true); // Our iterator is now invalid. Break and search again. // Most of the time there shouldn't be a bunch of matching blocks. goto restart; } } // We got here - it wasn't in the map at all (or anymore.) } while (false); }
void OnSetBlock(Packet& packet) { auto chmgr = ChunkManager::Get(); u8 orientation; u16 chunkID, blockType; ivec3 vxPos; // Assume vxPos is in bounds packet.Read(chunkID); packet.Read<ivec3>(vxPos); packet.Read(blockType); orientation = blockType & 3; blockType >>= 2; auto ch = chmgr->GetChunk(chunkID); if(!ch) { logger << "Missing chunkID " << chunkID; return; } if(blockType) { auto blk = ch->CreateBlock(vxPos, blockType); if(blk) blk->orientation = orientation; else logger << "Block create failed at " << vxPos; }else{ ch->DestroyBlock(vxPos); } }
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache // is full and when saving and loading states. void JitBlockCache::Clear() { block_map_.clear(); proxyBlockMap_.clear(); for (int i = 0; i < num_blocks_; i++) DestroyBlock(i, false); links_to_.clear(); num_blocks_ = 0; blockMemRanges_[JITBLOCK_RANGE_SCRATCH] = std::make_pair(0xFFFFFFFF, 0x00000000); blockMemRanges_[JITBLOCK_RANGE_RAMBOTTOM] = std::make_pair(0xFFFFFFFF, 0x00000000); blockMemRanges_[JITBLOCK_RANGE_RAMTOP] = std::make_pair(0xFFFFFFFF, 0x00000000); }
void JitBlockCache::DestroyBlock(int block_num, bool invalidate) { if (block_num < 0 || block_num >= num_blocks_) { ERROR_LOG_REPORT(JIT, "DestroyBlock: Invalid block number %d", block_num); return; } JitBlock *b = &blocks_[block_num]; // No point it being in there anymore. RemoveBlockMap(block_num); // Pure proxy blocks always point directly to a real block, there should be no chains of // proxy-only blocks pointing to proxy-only blocks. // Follow a block proxy chain. // Destroy the block that transitively has this as a proxy. Likely the root block once inlined // this block or its 'parent', so now that this block has changed, the root block must be destroyed. if (b->proxyFor) { for (size_t i = 0; i < b->proxyFor->size(); i++) { int proxied_blocknum = GetBlockNumberFromStartAddress((*b->proxyFor)[i], false); // If it was already cleared, we don't know which to destroy. if (proxied_blocknum != -1) { DestroyBlock(proxied_blocknum, invalidate); } } b->proxyFor->clear(); delete b->proxyFor; b->proxyFor = 0; } auto range = proxyBlockMap_.equal_range(b->originalAddress); for (auto it = range.first; it != range.second; ++it) { if (it->second == block_num) { // Found it. Delete and bail. proxyBlockMap_.erase(it); break; } } // TODO: Handle the case when there's a proxy block and a regular JIT block at the same location. // In this case we probably "leak" the proxy block currently (no memory leak but it'll stay enabled). if (b->invalid) { if (invalidate) ERROR_LOG(JIT, "Invalidating invalid block %d", block_num); return; } b->invalid = true; if (Memory::ReadUnchecked_U32(b->originalAddress) == GetEmuHackOpForBlock(block_num).encoding) Memory::Write_Opcode_JIT(b->originalAddress, b->originalFirstOpcode); // It's not safe to set normalEntry to 0 here, since we use a binary search // that looks at that later to find blocks. Marking it invalid is enough. UnlinkBlock(block_num); #if defined(ARM) // Send anyone who tries to run this block back to the dispatcher. // Not entirely ideal, but .. pretty good. // I hope there's enough space... // checkedEntry is the only "linked" entrance so it's enough to overwrite that. ARMXEmitter emit((u8 *)b->checkedEntry); emit.MOVI2R(R0, b->originalAddress); emit.STR(R0, CTXREG, offsetof(MIPSState, pc)); emit.B(MIPSComp::jit->dispatcher); emit.FlushIcache(); #elif defined(_M_IX86) || defined(_M_X64) // Send anyone who tries to run this block back to the dispatcher. // Not entirely ideal, but .. pretty good. // Spurious entrances from previously linked blocks can only come through checkedEntry XEmitter emit((u8 *)b->checkedEntry); emit.MOV(32, M(&mips_->pc), Imm32(b->originalAddress)); emit.JMP(MIPSComp::jit->Asm().dispatcher, true); #elif defined(PPC) PPCXEmitter emit((u8 *)b->checkedEntry); emit.MOVI2R(R3, b->originalAddress); emit.STW(R0, CTXREG, offsetof(MIPSState, pc)); emit.B(MIPSComp::jit->dispatcher); emit.FlushIcache(); #endif }
void Player::AttackAnimationTimerFinished() { if (IsBow()) { } else if (IsBoomerang()) { vec3 boomerangSpawnPosition = GetCenter() + (m_forward*0.75f) + (GetRightVector()*-0.4f) + (GetUpVector()*0.5f); float cameraModification = (m_cameraForward.y*17.5f); if (m_cameraForward.y < 0.0f) { cameraModification = (m_cameraForward.y*5.0f); } vec3 boomerangTarget = boomerangSpawnPosition + m_forward*15.0f + (vec3(0.0f, 1.0f, 0.0f) * cameraModification); if (m_pTargetEnemy != NULL) { boomerangTarget = m_pTargetEnemy->GetProjectileHitboxCenter(); if (m_pTargetEnemy->IsMoving()) { boomerangTarget += m_pTargetEnemy->GetForwardVector() * (m_pTargetEnemy->GetMovementSpeed() / 3.0f); } } float curveTime = length(boomerangTarget - boomerangSpawnPosition) / 15.0f; if (curveTime <= 0.4f) curveTime = 0.4f; Projectile* pProjectile = m_pProjectileManager->CreateProjectile(boomerangSpawnPosition, vec3(0.0f, 0.0f, 0.0f), 0.0f, "media/gamedata/weapons/Boomerang/BoomerangThrown.weapon", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); pProjectile->SetReturnToPlayer(true); pProjectile->SetProjectileCurveParams(m_forward, boomerangTarget, curveTime); pProjectile->SetWorldCollisionEnabled(true); m_pVoxelCharacter->SetRenderRightWeapon(false); } else if (IsStaff()) { float powerAmount = 25.0f; float cameraMultiplier = 25.0f; vec3 spellSpawnPosition = GetCenter() + (m_forward*1.25f) + (GetUpVector()*0.25f); if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; spellSpawnPosition.y += 0.75f; } vec3 spellSpawnVelocity = m_forward * powerAmount + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); if (m_pTargetEnemy != NULL) { vec3 toTarget = m_pTargetEnemy->GetProjectileHitboxCenter() - GetCenter(); spellSpawnVelocity = (normalize(toTarget) * powerAmount); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(spellSpawnPosition, spellSpawnVelocity, 0.0f, "media/gamedata/items/Fireball/Fireball.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); } else if (IsWand()) { } else if (IsBomb()) { vec3 bombSpawnPosition = GetCenter() + (m_forward*0.75f) + (GetUpVector()*0.5f); float liftAmount = 8.0f; float powerAmount = 30.0f; float cameraMultiplier = 25.0f; if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; } vec3 bombSpawnVelocity; if (m_pTargetEnemy) { // Enemy target vec3 toTarget = m_pTargetEnemy->GetCenter() - GetCenter(); float toTargetDistance = length(toTarget); liftAmount += toTargetDistance * 0.04f; bombSpawnVelocity = (normalize(toTarget) * powerAmount) + vec3(0.0f, liftAmount, 0.0f); } else { bombSpawnVelocity = (m_forward * powerAmount) + (GetUpVector() * liftAmount) + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(bombSpawnPosition, bombSpawnVelocity, 0.0f, "media/gamedata/items/Bomb/BombThrown.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(3.5f); float explodeRadius = 3.5f - (GetRandomNumber(-150, 0, 2) * 0.01f); pProjectile->SetExplodingProjectile(true, explodeRadius); //m_pVoxelCharacter->SetRenderRightWeapon(false); InventoryItem* pItem = m_pInventoryManager->GetInventoryItemForEquipSlot(EquipSlot_RightHand); if (pItem != NULL) { if (pItem->m_quantity != -1) { pItem->m_quantity -= 1; } if (pItem->m_quantity == 0) { // Remove this item from the manager, and remove it from the inventory and GUI UnequipItem(EquipSlot_RightHand, false, false); m_pInventoryManager->RemoveInventoryItem(EquipSlot_RightHand); m_pActionBar->RemoveInventoryItemFromActionBar(pItem->m_title); } } } else if (IsConsumable()) { } else if (IsDagger()) { } else if (IsHammer()) { } else if (IsMace()) { } else if (IsSickle()) { } else if (IsPickaxe()) { Item* pInteractItem = VoxGame::GetInstance()->GetInteractItem(); if (pInteractItem != NULL) { pInteractItem->Interact(); } else { DestroyBlock(); } } else if (IsAxe()) { } else if (Is2HandedSword()) { } else if (IsSword()) { } else if (IsBlockPlacing()) { } else if (IsItemPlacing()) { } else if (IsSceneryPlacing()) { } else if (IsSpellHands()) { float powerAmount = 25.0f; float cameraMultiplier = 25.0f; vec3 spellSpawnPosition = GetCenter() + (m_forward*0.5f) + (GetUpVector()*0.0f); // For right hand spellSpawnPosition += -(GetRightVector()*0.4f); if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; spellSpawnPosition.y += 0.75f; } vec3 spellSpawnVelocity = m_forward * powerAmount + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); if (m_pTargetEnemy != NULL) { vec3 toTarget = m_pTargetEnemy->GetProjectileHitboxCenter() - GetCenter(); spellSpawnVelocity = (normalize(toTarget) * powerAmount); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(spellSpawnPosition, spellSpawnVelocity, 0.0f, "media/gamedata/items/Fireball/FireballBlue.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); } else if (IsShield()) { } else if (IsTorch()) { } }
void Terrain::DestroyTarget(Player *player) { PositionedBlock *block = CheckAim(player); if (!block) return; DestroyBlock(block); }