def craftingGuiPostClick(slots: List[Slot], is3x3: bool, app, slotIdx, prevOutput: Stack): if is3x3: totalCraftSlots = 9 + 1 else: totalCraftSlots = 4 + 1 if slotIdx == 0 and prevOutput != slots[0].stack: # Something was crafted for slot in slots[1:totalCraftSlots]: if slot.stack.amount > 0: slot.stack.amount -= 1 def toid(s): return None if s.isEmpty() else s.item rowLen = round(math.sqrt(totalCraftSlots - 1)) c = [] for rowIdx in range(rowLen): row = [] for colIdx in range(rowLen): row.append(toid(slots[1 + rowIdx * rowLen + colIdx].stack)) c.append(row) slots[0].stack = Stack('', 0) for r in app.recipes: if r.isCraftedBy(c): slots[0].stack = copy.copy(r.outputs) break
def __init__(self, app, creative: bool = False, tag: Optional[nbt.TAG_Compound] = None): self.dimension = 'minecraft:overworld' # FIXME: ID super().__init__(app, 1, 'player', 0.0, 0.0, 0.0, nbt=tag) self.reach = 4.0 self.creative = creative self.flying = False self.portalCooldown = 80 if self.creative: if len(app.itemTextures) > 36: # TODO: 1 / 0 self.inventory = [ Slot(stack=Stack(name, -1)) for name in app.itemTextures ] while len(self.inventory) < 36: self.inventory.append(Slot(stack=Stack('', 0))) else: self.inventory = [Slot() for _ in range(36)] if tag is not None: for stackTag in tag["Inventory"]: (stack, slotIdx) = Stack.fromNbt(stackTag, getSlot=True) self.inventory[slotIdx].stack = stack gameMode = tag['playerGameType'].value if gameMode == 0: self.creative = False elif gameMode == 1: self.creative = True else: raise Exception(f'Invalid game mode {gameMode}') self.flying = tag['abilities']['flying'].value != 0 self.dimension = tag['dimension'].value
def getSlotsInWindow(server: ServerState, windowId: int) -> Tuple[Stack, List[Slot]]: if windowId == 0: player = server.getLocalPlayer() if player.entityId not in server.craftSlots: server.craftSlots[player.entityId] = [Slot( canInput=False)] + [Slot() for _ in range(4)] # TODO: Armor slots baseSlots = server.craftSlots[player.entityId] + [ Slot() for _ in range(4) ] else: window = server.openWindows[windowId] player = None for p in server.players: if p.entityId == window.playerId: player = p break if player is None: raise Exception( f'Window click from nonexistent player {window.playerId}') if window.kind == 'furnace': (chunk, localPos) = server.getLocalDimension().world.getChunk(window.pos) furnace: world.Furnace = chunk.tileEntities[localPos] baseSlots = [ furnace.inputSlot, furnace.fuelSlot, furnace.outputSlot ] elif window.kind == 'crafting': if player.entityId not in server.craftSlots: server.craftSlots[player.entityId] = [Slot( canInput=False)] + [Slot() for _ in range(9)] baseSlots = server.craftSlots[player.entityId] else: raise Exception(f'Unknown window kind {window.kind}') slots = baseSlots + player.inventory[9:36] + player.inventory[0:9] if player.entityId not in server.heldItems: server.heldItems[player.entityId] = Stack('', 0) return (server.heldItems[player.entityId], slots)
def updateBlockBreaking(app, server: ServerState): pos = server.breakingBlockPos if server.breakingBlock == 0.0: return wld = server.getLocalDimension().world blockId = wld.getBlock(pos) blockState = wld.getBlockState(pos) if blockId == 'air': print(f'Invalid mining at {server.breakingBlockPos}') return # HACK: player = server.getLocalPlayer() toolStack = player.inventory[player.hotbarIdx].stack if toolStack.isEmpty(): tool = '' else: tool = toolStack.item hardness = resources.getHardnessAgainst(blockId, tool) # TODO: Sound effect packets if server.breakingBlock >= hardness: if blockId == 'oak_log': blockState['axis'] = 'y' mcBlockId = util.REGISTRY.encode_block( {'name': 'minecraft:' + blockId} | blockState) network.s2cQueue.put( network.AckPlayerDiggingS2C(pos, mcBlockId, network.DiggingAction.FINISH_DIGGING, True)) droppedItem = resources.getBlockDrop(app, blockId, tool) resources.getDigSound(app, blockId).play() wld.setBlock((app.textures, app.cube, app.textureIndices), pos, 'air') server.breakingBlock = 0.0 if droppedItem is not None: stack = Stack(droppedItem, 1) entityId = server.getEntityId() xVel = ((random.random() - 0.5) * 0.1) yVel = ((random.random() - 0.5) * 0.1) zVel = ((random.random() - 0.5) * 0.1) # TODO: UUID network.s2cQueue.put( network.SpawnEntityS2C(entityId, None, 37, float(pos.x), float(pos.y), float(pos.z), 0.0, 0.0, 1, int(xVel * 8000), int(yVel * 8000), int(zVel * 8000))) itemId = util.REGISTRY.encode('minecraft:item', 'minecraft:' + stack.item) network.s2cQueue.put( network.EntityMetadataS2C( entityId, {(6, 7): { 'item': itemId, 'count': stack.amount }})) ent = Entity(app, entityId, 'item', float(pos.x), float(pos.y), float(pos.z)) ent.extra.stack = stack ent.velocity = [xVel, yVel, zVel] server.getLocalDimension().entities.append(ent)
def sendChatMessage(app, text: str): if hasattr(app, 'server'): if text.startswith('/'): text = text.removeprefix('/') parts = text.split() server: ServerState = app.server dim = server.getLocalDimension() wld, entities = dim.world, dim.entities print(f"COMMAND {text}") if parts[0] == 'pathfind': player: Player = server.getLocalPlayer() target = player.getBlockPos() for ent in entities: ent.updatePath(wld, target) elif parts[0] == 'give': itemId = parts[1] if len(parts) == 3: amount = int(parts[2]) else: amount = 1 server.getLocalPlayer().pickUpItem(app, Stack(itemId, amount)) elif parts[0] == 'time': if parts[1] == 'set': if parts[2] == 'day': server.time = 1000 elif parts[2] == 'night': server.time = 13000 elif parts[2] == 'midnight': server.time = 18000 else: server.time = int(parts[2]) elif parts[1] == 'add': server.time += int(parts[2]) elif parts[0] == 'gamemode': if parts[1] == 'creative': server.getLocalPlayer().creative = True elif parts[1] == 'survival': server.getLocalPlayer().creative = False elif parts[0] == 'summon': player = server.getLocalPlayer() ent = Entity(app, server.getEntityId(), parts[1], player.pos[0] + 0.5, player.pos[1] + 0.5, player.pos[2] + 0.5) app.entities.append(ent) elif parts[0] == 'explode': power = int(parts[1]) player = server.getLocalPlayer() pos = world.nearestBlockPos(player.pos[0], player.pos[1], player.pos[2]) wld.explodeAt(pos, power, (app.textures, app.cube, app.textureIndices)) elif parts[0] == 'dimension': player = server.getLocalPlayer() if player.dimension == 'minecraft:overworld': player.dimension = 'minecraft:the_nether' elif player.dimension == 'minecraft:the_nether': player.dimension = 'minecraft:overworld' else: raise Exception(player.dimension) import quarry.types.nbt as quarrynbt player.portalCooldown = 80 # TODO: network.s2cQueue.put( network.RespawnS2C(quarrynbt.TagCompound({}), player.dimension, 0, 0, None, False, False, True)) elif parts[0] == 'chunkstates': for dim in server.dimensions: print(f'== DIMENSION {dim} ==') for pos, chunk in dim.world.chunks.items(): print(f'{pos} - {chunk.worldgenStage}') elif parts[0] == 'killall': toRemove = [] idx = 0 dim = server.getLocalDimension() while idx < len(dim.entities): if dim.entities[idx].kind.name != 'player': toRemove.append(dim.entities[idx].entityId) dim.entities.pop(idx) else: idx += 1 network.s2cQueue.put(network.DestroyEntitiesS2C(toRemove)) elif parts[0] == 'tp': # TODO: ''' player = server.getLocalPlayer() player.pos[0] = float(parts[1]) player.pos[1] = float(parts[2]) player.pos[2] = float(parts[3]) ''' else: network.c2sQueue.put(network.ChatMessageC2S(text))
def __init__(self): self.stack = Stack('stone', 1) self.age = 6000 # TODO: should increase if dropped by player or fox self.pickupDelay = 10