예제 #1
0
func (p *_player) sendWorldData() {
	go func() {
		for {
			for i, chunk := range p.chunkSet {
				x, z := chunk.X, chunk.Z
				dx, dz := (int32(p.stored.Position[0])>>4)-x, (int32(p.stored.Position[2])>>4)-z
				if dx > 10 || dx < -10 || dz > 10 || dz < -10 {
					storage.ReleaseChunk(x, z)
					sendChunk(p, x, z, nil)
					delete(p.chunkSet, i)
				}
			}

			for i := int32(1); i <= 8; i++ {
				middleX, middleZ := int32(p.stored.Position[0]/16), int32(p.stored.Position[2]/16)
				for x := middleX - i; x < middleX+i; x++ {
					for z := middleZ - i; z < middleZ+i; z++ {
						id := uint64(uint32(x))<<32 | uint64(uint32(z))
						if _, ok := p.chunkSet[id]; !ok {
							p.chunkSet[id] = storage.GetChunk(x, z)
							sendChunk(p, x, z, p.chunkSet[id])
							runtime.Gosched()
						}
					}
				}

				if i == 2 && !p.spawned {
					p.sendSpawnPacket()
					p.spawned = true
				}
			}
			time.Sleep(100 * time.Millisecond)
		}
	}()
}
예제 #2
0
func ticker() {
	for {
		time.Sleep(50 * time.Millisecond)

		updateLock.Lock()

		queue := updateQueue
		updateQueue = make(map[struct{ x, y, z int32 }]bool)

		updateLock.Unlock()

		updateCount := 0

		for loc, _ := range queue {
			x, y, z := loc.x, loc.y, loc.z
			blockType := GetBlockAt(x, y, z)
			switch blockType {
			case block.Water:
				if !spreadWater(x, y, z) && GetBlockAt(x, y, z) == block.Water {
					setBlockNoUpdate(x, y, z, block.StationaryWater, GetBlockDataAt(x, y, z))
				}
			case block.Sand, block.Gravel, block.LongGrass, block.RedFlower, block.YellowFlower:
				if GetBlockAt(x, y-1, z).Passable() {
					blockData := GetBlockDataAt(x, y, z)
					SetBlockAt(x, y, z, GetBlockAt(x, y-1, z), GetBlockDataAt(x, y-1, z))
					SetBlockAt(x, y-1, z, blockType, blockData)
				}
			case block.Sponge:
				switch GetBlockAt(x, y+1, z) {
				case block.Water, block.StationaryWater:
					decrementWater(x, y+1, z)
				}
			}
			updateCount++
			delete(queue, loc)
			runtime.Gosched() // Don't cause too much lag
			if updateCount >= 10000 {
				log.Print("> 10000 updates. Waiting for the next tick to resume updating.")
				break
			}
		}

		for loc, _ := range queue {
			queueUpdate(loc.x, loc.y, loc.z)
		}

		blockSendLock.Lock()
		for chunk, blocks := range blockSendQueue {
			c := storage.GetChunk(chunk.x, chunk.z)
			packet := protocol.MultiBlockChange{X: chunk.x, Z: chunk.z, Blocks: make([]uint32, 0, len(blocks))}
			for block, _ := range blocks {
				packet.Blocks = append(packet.Blocks, uint32(block.x&0xF)<<28|uint32(block.z&0xF)<<24|uint32(block.y)<<16|uint32(c.GetBlock(block.x, block.y, block.z))<<4|uint32(c.GetData(block.x, block.y, block.z)))
			}
			storage.ReleaseChunk(chunk.x, chunk.z)
			SendToAll(packet)
			delete(blockSendQueue, chunk)
		}
		blockSendLock.Unlock()
	}
}
예제 #3
0
func sendPacket(p Player, conn net.Conn, packet protocol.Packet) {
	if kick, ok := packet.(protocol.Kick); ok {
		if p.Username() != "" {
			if strings.HasPrefix(kick.Reason, "Error: ") {
				log.Print("Dropping ", conn.RemoteAddr(), " ", p.Username(), " - ", kick.Reason)
				SendToAll(protocol.Chat{Message: fmt.Sprintf("%s is error %s", formatUsername(p), strings.ToLower(kick.Reason)[7:])})
			} else {
				log.Print("Kicking ", conn.RemoteAddr(), " ", p.Username(), " - ", kick.Reason)
				SendToAll(protocol.Chat{Message: fmt.Sprintf("%s was kicked: %s", formatUsername(p), kick.Reason)})
			}
		}
		for _, chunk := range p.(*_player).chunkSet {
			storage.ReleaseChunk(chunk.X, chunk.Z)
		}
	}
	if _, err := conn.Write(packet.Packet()); err != nil {
		panic(err)
	}
}