static BlockID Particle_GetBlock(Int32 x, Int32 y, Int32 z) { if (World_IsValidPos(x, y, z)) { return World_GetBlock(x, y, z); } if (y >= WorldEnv_EdgeHeight) return BLOCK_AIR; if (y >= WorldEnv_SidesHeight) return WorldEnv_EdgeBlock; return WorldEnv_SidesBlock; }
static inline Block fastBlockFetch(World* world, Chunk* chunk, Cluster* cluster, int x, int y, int z) { world->errFlags = 0; return (x < 0 || y < 0 || z < 0 || x >= CHUNK_WIDTH || y >= CHUNK_CLUSTER_HEIGHT || z >= CHUNK_DEPTH) ? World_GetBlock(world, (chunk->x * CHUNK_WIDTH) + x, (cluster->y * CHUNK_CLUSTER_HEIGHT) + y, (chunk->z * CHUNK_DEPTH) + z) : cluster->blocks[x][y][z]; }
BlockID World_SafeGetBlock_3I(Vector3I p) { return World_Contains(p.X, p.Y, p.Z) ? World_GetBlock(p.X, p.Y, p.Z) : BLOCK_AIR; }
BlockID World_GetPhysicsBlock(int x, int y, int z) { if (y < 0 || !World_ContainsXZ(x, z)) return BLOCK_BEDROCK; if (y >= World.Height) return BLOCK_AIR; return World_GetBlock(x, y, z); }
void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right) { TimeMS now = DateTime_CurrentUTC_MS(); int delta = (int)(now - input_lastClick); Vector3I pos; BlockID old, cur, block; int i; if (cooldown && delta < 250) return; /* 4 times per second */ input_lastClick = now; if (Server.SupportsPlayerClick && !Gui_GetActiveScreen()->HandlesAllInput) { input_pickingId = -1; InputHandler_ButtonStateChanged(MOUSE_LEFT, left); InputHandler_ButtonStateChanged(MOUSE_RIGHT, right); InputHandler_ButtonStateChanged(MOUSE_MIDDLE, middle); } if (Gui_GetActiveScreen()->HandlesAllInput) return; if (left) { /* always play delete animations, even if we aren't picking a block */ HeldBlockRenderer_ClickAnim(true); pos = Game_SelectedPos.BlockPos; if (!Game_SelectedPos.Valid || !World_Contains(pos.X, pos.Y, pos.Z)) return; old = World_GetBlock(pos.X, pos.Y, pos.Z); if (Blocks.Draw[old] == DRAW_GAS || !Blocks.CanDelete[old]) return; Game_ChangeBlock(pos.X, pos.Y, pos.Z, BLOCK_AIR); Event_RaiseBlock(&UserEvents.BlockChanged, pos, old, BLOCK_AIR); } else if (right) { pos = Game_SelectedPos.TranslatedPos; if (!Game_SelectedPos.Valid || !World_Contains(pos.X, pos.Y, pos.Z)) return; old = World_GetBlock(pos.X, pos.Y, pos.Z); block = Inventory_SelectedBlock; if (AutoRotate_Enabled) block = AutoRotate_RotateBlock(block); if (Game_CanPick(old) || !Blocks.CanPlace[block]) return; /* air-ish blocks can only replace over other air-ish blocks */ if (Blocks.Draw[block] == DRAW_GAS && Blocks.Draw[old] != DRAW_GAS) return; if (!InputHandler_CheckIsFree(block)) return; Game_ChangeBlock(pos.X, pos.Y, pos.Z, block); Event_RaiseBlock(&UserEvents.BlockChanged, pos, old, block); } else if (middle) { pos = Game_SelectedPos.BlockPos; if (!World_Contains(pos.X, pos.Y, pos.Z)) return; cur = World_GetBlock(pos.X, pos.Y, pos.Z); if (Blocks.Draw[cur] == DRAW_GAS) return; if (!(Blocks.CanPlace[cur] || Blocks.CanDelete[cur])) return; if (!Inventory_CheckChangeSelected() || Inventory_SelectedBlock == cur) return; /* Is the currently selected block an empty slot? */ if (Inventory_SelectedBlock == BLOCK_AIR) { Inventory_SetSelectedBlock(cur); return; } /* Try to replace same block */ for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) { if (Inventory_Get(i) != cur) continue; Inventory_SetSelectedIndex(i); return; } /* Try to replace empty slots */ for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) { if (Inventory_Get(i) != BLOCK_AIR) continue; Inventory_Set(i, cur); Inventory_SetSelectedIndex(i); return; } /* Finally, replace the currently selected block */ Inventory_SetSelectedBlock(cur); } }