Esempio n. 1
0
void Agent::vmTick() {
	// Tick the VM associated with this agent.
	
	assert(vm); // There must *be* a VM to tick.
	LifeAssert la(this); // sanity check

	// If we're out of timeslice, give ourselves some more (depending on the game type).
	if (!vm->timeslice) {
		vm->timeslice = (engine.version < 3) ? 1 : 5;
	}

	// Keep trying to run VMs while we don't run out of timeslice, end up with a blocked VM, or a VM stops.
	while (vm && vm->timeslice && !vm->isBlocking() && !vm->stopped()) {
		assert(vm->timeslice > 0);

		// Tell the VM to tick (using all available timeslice), catching exceptions as necessary.
		try {
			vm->tick();
		} catch (invalidAgentException &e) {
			// try letting the exception script handle it
			if (!queueScript(255))
				unhandledException(e.prettyPrint(), true);
			else
				stopScript(); // we still want current script to die
		} catch (creaturesException &e) {
			unhandledException(e.prettyPrint(), true);
		} catch (std::exception &e) {
			unhandledException(e.what(), true);
		}
		
		// If the VM stopped, it's done.
		if (vm && vm->stopped()) {
			world.freeVM(vm);
			vm = NULL;
		}
	}

	// Zot any remaining timeslice, since we're done now.
	if (vm) vm->timeslice = 0;
	
	// If there's no current VM but there's one on the call stack, a previous VM must have finished,
	// pop one from the call stack to run next time.
	if (!vm && !vmstack.empty()) {
		vm = vmstack.front();
		vmstack.pop_front();
	}
}
Esempio n. 2
0
void Agent::physicsTickC2() {
	int dx = velx.getInt(), dy = vely.getInt();

	if (dx != 0 || dy != 0) falling = true;

	if (falling && sufferphysics()) {
		dy += accg.getInt();
	}

	falling = true;

	if (dy == 0 && dx == 0) { // nothing to do
		if (vely.getInt() == 0) {
			// really no motion
			falling = false;
		} else {
			// y motion cancelled by gravity
			vely.setInt(dy);
		}
		return;
	}
	vely.setInt(dy);

	Point deltapt(0,0);
	double delta = 1000000000;

	bool collided = false;

	if (suffercollisions()) {
		MetaRoom *m = world.map.metaRoomAt(x, y);
		if (!m) {
			if (!displaycore)
				unhandledException(boost::str(boost::format("out of room system at (%f, %f)") % x % y), false);
			falling = false;
			displaycore = true;
			return;
		}

		for (unsigned int i = 0; i < 4; i++) {
			Point src = boundingBoxPoint(i);
			findCollisionInDirection(i, m, src, dx, dy, deltapt, delta, collided, true);
		}
	} else {
		deltapt.x = dx;
		deltapt.y = dy;
	}
	
	if (collided && (velx.getInt() != 0 || vely.getInt() != 0) && moved_last_tick) {
		if (lastcollidedirection >= 2) // up and down
			vely.setInt(-(vely.getInt() - (rest.getInt() * vely.getInt()) / 100));
		else
			velx.setInt(-(velx.getInt() - (rest.getInt() * velx.getInt()) / 100));
		queueScript(6, 0);	
	}
	if ((int)deltapt.x == 0 && (int)deltapt.y == 0) {
		if (!moved_last_tick) {
			falling = false;
			velx.setInt(0);
			vely.setInt(0);
		}
		moved_last_tick = false;
	} else {
		moved_last_tick = true;
		moveTo(x + (int)deltapt.x, y + (int)deltapt.y);
		if (sufferphysics()) {
			int fricx = (aero.getInt() * velx.getInt()) / 100;
			int fricy = (aero.getInt() * vely.getInt()) / 100;
			if (abs(velx.getInt()) > 0 && fricx == 0) fricx = (velx.getInt() < 0) ? -1 : 1;
			if (abs(vely.getInt()) > 0 && fricy == 0) fricy = (vely.getInt() < 0) ? -1 : 1;
			velx.setInt(velx.getInt() - fricx);
			vely.setInt(vely.getInt() - fricy);
		}
	}
}
Esempio n. 3
0
// Creatures 2 collision finding
void Agent::findCollisionInDirection(unsigned int i, class MetaRoom *m, Point src, int &dx, int &dy, Point &deltapt, double &delta, bool &collided, bool followrooms) {
	src.x = (int)src.x;
	src.y = (int)src.y;

	if (m->wraparound()) {
		if (src.x > m->x() + m->width() || (dx > 0 && src.x == m->x() + m->width())) src.x -= m->width();
		else if (src.x < m->x() || (dx < 0 && src.x == m->x())) src.x += m->width();
	}

	// TODO: caching rooms affects behaviour - work out if that's a problem
	shared_ptr<Room> room = roomcache[i].lock();
	if (!room || !room->containsPoint(src.x, src.y)) {
		room = bestRoomAt(src.x, src.y, i, m, shared_ptr<Room>());
		roomcache[i] = room;
	}

	if (!room) { // out of room system
		if (!displaycore)
			unhandledException(boost::str(boost::format("out of room system at (%f, %f)") % src.x % src.y), false);
		falling = false;
		displaycore = true;
		return;
	}

	int lastdirection = 0;

	bool steep = abs(dy) > abs(dx);

	int signdx = dx < 0 ? -1 : 1;
	int signdy = dy < 0 ? -1 : 1;

	Line l(Point(0,0),Point(dx,dy));

	Point lastpoint(0,0);

	Vehicle *vehicle = 0;
	if (invehicle) vehicle = dynamic_cast<Vehicle *>(invehicle.get());

	for (int loc = 0; loc <= abs(steep ? dy : dx); loc++) {
		Point p = steep ? l.pointAtY(loc*signdy) : l.pointAtX(loc*signdx);
		p.x = (int)p.x;
		p.y = (int)p.y;

		if (vehicle) {
			if (src.x + p.x < vehicle->x + vehicle->cabinleft) {
				lastdirection = 0;
				collided = true;
				break;
			}
			if (src.x + p.x > vehicle->x + vehicle->cabinright) {
				lastdirection = 1;
				collided = true;
				break;
			}
			if (src.y + p.y < vehicle->y + vehicle->cabintop) {
				lastdirection = 2;
				collided = true;
				break;
			}
			if (src.y + p.y > vehicle->y + vehicle->cabinbottom) {
				lastdirection = 3;
				collided = true;
				break;
			}

			lastpoint = p;

			continue;
		}

		bool trycollisions = false;

		bool endofroom = false;
	
		if (src.x + p.x < room->x_left) {
			if (i != 1 && dx < 0) { trycollisions = true; lastdirection = 0; }
			endofroom = true;
		}
		if (src.x + p.x > room->x_right) {
			if (i != 0 && dx > 0) { trycollisions = true; lastdirection = 1; }
			endofroom = true;
		}
		if (src.y + p.y < room->y_left_ceiling) {
			if (i != 3 && dy < 0) { trycollisions = true; lastdirection = 2; }
			endofroom = true;
		}
		if (src.y + p.y > room->y_left_floor) {
			if (i != 2 && dy > 0) { trycollisions = true; lastdirection = 3; }
			endofroom = true;
		}

		// find the next room, if necessary, and work out whether we should move into it or break out
		if (endofroom) {
			if (m->wraparound()) {
				if (dx > 0 && src.x + p.x >= m->x() + m->width()) src.x -= m->width();
				else if (dx < 0 && src.x + p.x <= m->x()) src.x += m->width();
			}

			shared_ptr<Room> newroom = bestRoomAt(src.x + p.x, src.y + p.y, i, m, room);

			bool collision = false;

			// collide if we're out of the room system
			if (!newroom) {	collision = true; }
			// collide if there's no new room connected to this one
			else if (room->doors.find(newroom) == room->doors.end()) { collision = true; }
			// collide if the PERM between this room and the new room is smaller than or equal to our size
			else if (size.getInt() > room->doors[newroom]->perm) { collision = true; }

			if (collision && (trycollisions || (!newroom))) {
				collided = true;
				break;
			}

			// move to the new room and keep going!
			room = newroom;
		}
	
		if (room->floorpoints.size() && i == 3 && dy >= 0 && size.getInt() > room->floorvalue.getInt()) { // TODO: Hack!
			// TODO: we don't check floorYatX isn't returning a 'real' room floor, but floorpoints should cover the whole floor anyway
			int floory = room->floorYatX(src.x + p.x);
			
			// never collide when the top point of an object is below the floor.
			Point top = boundingBoxPoint(2);

			// TODO: consider steep floors
			if (src.y + p.y > floory && top.y < floory) {
				collided = true;
				lastdirection = 3;
				break;
			}
		}
		
		if ((!followrooms) && endofroom) break;

		lastpoint = p;
	}

	double length2 = (lastpoint.x * lastpoint.x) + (lastpoint.y * lastpoint.y);
	if (length2 < delta) {
		// TODO: !followrooms is a horrible way to detect a non-physics call
		if (collided && followrooms) lastcollidedirection = lastdirection;
		deltapt = lastpoint;
		delta = length2;
	}
}
Esempio n. 4
0
void Agent::physicsTick() {
	if (engine.version == 1) return; // C1 has no physics, and different attributes.

	if (carriedby) return; // We don't move when carried, so what's the point?

	if (engine.version == 2) {
		// Creatures 2 physics is different.
		physicsTickC2();
		return;
	}

	if (!falling) return; // TODO: there are probably all sorts of issues here, untested

	if (!wasmoved) return; // some agents are created outside INST and get autokilled if we try physics on them before they move

	if (invehicle) return; // TODO: c2e verhicle physics

	// set destination point based on velocities
	float destx = x + velx.getFloat();
	float desty = y + vely.getFloat();

	if (rotatable()) {
		// TODO: the real engine seems to reset velx/vely, so i do that here, but why?
		velx.setFloat(0.0f); vely.setFloat(0.0f);

		// TODO: which order should these be in?

		// calculate forwards velocity
		float forward_x = fvel * sinf(spin * (M_PI * 2));
		float forward_y = fvel * -cosf(spin * (M_PI * 2));

		// calculate sideways velocity
		// TODO: this sideways velocity code is untested
		float sideways_x = svel * cosf(spin * (M_PI * 2));
		float sideways_y = svel * -sinf(spin * (M_PI * 2));

		// set destination based on forward/sideways velocity
		destx = x + forward_x + sideways_x;
		desty = y + forward_y + sideways_y;

		// modify spin based on angular velocity
		spin = fmodf(spin + avel, 1.0f);
		if (spin < 0.0f) spin += 1.0f;
	}

	if (sufferphysics()) {
		// TODO: falling behaviour needs looking at more closely..
		// .. but it shouldn't be 'false' by default on non-physics agents, so..
		//falling = false;
		// increase speed according to accg
		// TODO: should we be changing vely first, instead of after a successful move (below)?
		desty += accg.getFloat();
	}
	
	if (suffercollisions()) {
		float lastdistance = 1000000.0f;
		bool collided = false;
		Line wall; // only valid when collided
		unsigned int collidedirection = 0; // only valid when collided
		Point bestmove;

		// iterate through all four points of the bounding box
		for (unsigned int i = 0; i < 4; i++) {
			// this mess is because we want to start with the bottom point - DOWN (3) - before the others, for efficiency
			Point src = boundingBoxPoint((i == 0) ? 3 : i - 1);

			// store values
			float srcx = src.x, srcy = src.y;
			
			shared_ptr<Room> ourRoom = world.map.roomAt(srcx, srcy);
			if (!ourRoom) {
				ourRoom = world.map.roomAt(srcx, srcy);
			}
			if (!ourRoom) {
				if (!displaycore) { // TODO: ugh, displaycore is a horrible thing to use for this
					// we're out of the room system, physics bug, but let's try MVSFing back in to cover for fuzzie's poor programming skills
					static bool tryingmove; tryingmove = false; // avoid infinite loop
					if (!tryingmove && tryMoveToPlaceAround(x, y)) {
						//std::cout << identify() << " was out of room system due to a physics bug but we hopefully moved it back in.." << std::endl;
						tryingmove = true;
						physicsTick();
						return;
					}
					
					// didn't work!
					unhandledException(boost::str(boost::format("out of room system at (%f, %f)") % srcx % srcy), false);
				}
				displaycore = true;
				falling = false;
				return; // out of room system
			}
			
			Point dest(destx + (srcx - x), desty + (srcy - y));
			unsigned int local_collidedirection;
			Line local_wall;
		
			// this changes src to the point at which we end up
			bool local_collided = world.map.collideLineWithRoomSystem(src, dest, ourRoom, src, local_wall, local_collidedirection, perm);

			float dist;
			if (src.x == srcx && src.y == srcy)
				dist = 0.0f;
			else {
				float xdiff = src.x - srcx;
				float ydiff = src.y - srcy;
				dist = xdiff*xdiff + ydiff*ydiff;
			}

			if (dist >= lastdistance) {
				assert(i != 0); // this had better not be our first collision!
				continue; // further away than a previous collision
			}

			lastdistance = dist;
			bestmove.x = x + (src.x - srcx);
			bestmove.y = y + (src.y - srcy);
			collidedirection = local_collidedirection;
			wall = local_wall;
			collided = local_collided;

			if (dist == 0.0f)
				break; // no point checking any more, is there?
		}	

		// *** do actual movement
		if (lastdistance != 0.0f) {	
			moveTo(bestmove.x, bestmove.y);
		
			if (collided) {
				lastcollidedirection = collidedirection;
				queueScript(6, 0, velx, vely); // TODO: include this? .. we need to include SOMETHING, c3 ball checks for <3

				if (elas != 0) {
					if (wall.getType() == HORIZONTAL) {
						vely.setFloat(-vely.getFloat());
					} else if (wall.getType() == VERTICAL) {
						velx.setFloat(-velx.getFloat());
					} else {
						// line starts always have a lower x value than the end
						float xdiff = wall.getEnd().x - wall.getStart().x;
						float ydiff = wall.getEnd().y - wall.getStart().y;
						float fvelx = velx.getFloat(), fvely = vely.getFloat();
					
						// calculate input/slope angles
						double inputangle;
						if (fvelx == 0.0f) {
							if (fvely > 0.0f)
								inputangle = M_PI / 2.0;
							else
								inputangle = 3 * (M_PI / 2.0);
						} else {
							inputangle = atan(fvely / fvelx);
						}
						double slopeangle = atan(-ydiff / xdiff); // xdiff != 0 because wall isn't vertical

						// calculate output angle
						double outputangle = slopeangle + (slopeangle - inputangle) + M_PI;

						// turn back into component velocities
						double vectorlength = sqrt(fvelx*fvelx + fvely*fvely);
						float xoutput = cos(outputangle) * vectorlength;
						float youtput = sin(outputangle) * vectorlength;

						velx.setFloat(xoutput);
						vely.setFloat(-youtput);
					}

					if (elas != 100.0f) {
						velx.setFloat(velx.getFloat() * (elas / 100.0f));
						vely.setFloat(vely.getFloat() * (elas / 100.0f));
					}
				} else				
					vely.setFloat(0);
			} else if (sufferphysics() && accg != 0) {
				vely.setFloat(vely.getFloat() + accg.getFloat());
			}
		} else {
			// TODO: correct?
			if (sufferphysics()) {
				if (velx.getFloat() == 0.0f && vely.getFloat() == 0.0f)
					falling = false;
			}
			velx.setFloat(0);
			vely.setFloat(0);
		}
	} else {
		if (vely.hasDecimal() || velx.hasDecimal())
			moveTo(destx, desty);
		if (sufferphysics())
			vely.setFloat(vely.getFloat() + accg.getFloat());
	}

	if (sufferphysics() && (aero != 0)) {
		// reduce speed according to AERO
		// TODO: aero should be an integer!
		velx.setFloat(velx.getFloat() - (velx.getFloat() * (aero.getFloat() / 100.0f)));
		vely.setFloat(vely.getFloat() - (vely.getFloat() * (aero.getFloat() / 100.0f)));
	}

	if (rotatable()) {
		avel -= avel * admp;
		fvel -= fvel * fdmp;
		svel -= svel * sdmp;
	}
}
TEMPLATE_InterruptHandler
void TEMPLATED_InterruptHandler::handle(
		uint64_t  * savedRegs,
		ExceptionType type,
		ExceptionOrigin origin,
		IntID         id
		)
{
//	kout << INFO << "Handling interrupt\n";
//	kout << "exception type = " ;
//	switch(type)
//	{
//	case ExceptionType::IRQ:
//		kout << "IRQ";
//		break;
//	case ExceptionType::SYNC:
//		kout << "SYNC";
//		break;
//	default:
//		kout << "Other";
//		break;
//	}
//	kout << "\n";
//	kout << "exception origin = ";
//	switch(origin)
//	{
//	case ExceptionOrigin::CUR_SP_EL0:
//	case ExceptionOrigin::CUR_SP_ELx:
//		kout << "Current";
//		break;
//	case ExceptionOrigin::FROM_LOWER_A64:
//		kout << "Lower";
//		break;
//	default:
//		kout << "Other";
//		break;
//	}
//	kout << "\n";
//	RegELR_EL1::read().dump();
//	RegESR_EL1::read().dump();
//	RegFAR_EL1::read().dump();
	if(!_allowSyncExcep)
	{
		kout << FATAL << "synchronous exception happened while the handler indicates that synchronous exception is not allowed.\n";
		asm_wfi_loop();
	}
	_allowSyncExcep=false;// 需要保存状态
	_nestedExceps.emplaceBack(savedRegs,type,origin);
	_allowSyncExcep=true;
	switch(type)
	{
	case ExceptionType::IRQ:
	{
		// 这里需要提供intid
		//The CPU interface has two IARs. Reading the IAR returns the INTID, and advances the interrupt
		//state machine. In a typical interrupt handler, one of the first steps when handling an interrupt is to
		//read one of the IARs
		handleIRQ(id);//NOTE:by reading it, we  acknowledged it.So it will change to 1023 after this read
		break;
	}
	case ExceptionType::FIQ:
	{
		handleFIQ(id);
		break;
	}
	case ExceptionType::SError:
	{
		handleSError();
		break;
	}
	case ExceptionType::SYNC:
	{
		auto esr = RegESR_EL1::make(currentState().esrELx());//ELx的结构都是相同的
		switch(esr.EC)
		{
		case ExceptionClass::UNDEF_INST:
			handleUndefinedInstruction();
			break;
		case ExceptionClass::SVC_AA64:
			handleSVC(static_cast<SvcFunc>(lowerMaskBits(16) & esr.ISS));
			break;
		case ExceptionClass::DATA_ABORT_LOWER_EL:  // user error
		case ExceptionClass::DATA_ABORT_SAME_EL: // system error
			handleDataAbort();
			break;
		case ExceptionClass::INSTR_ABORT_LOWER_EL:
		case ExceptionClass::INSTR_ABORT_SAME_EL:
			handleInstructionAbort();
			break;
		case ExceptionClass::SP_ALIGNMENT_FAULT:
			handleSPAlignmentFault();
			break;
		case ExceptionClass::PC_ALIGNMENT_FAULT:
			handlePCAlignmentFault();
			break;
		case ExceptionClass::SERROR_INTERRUPT:
			handleSError();
			break;
		case ExceptionClass::SMC_AA64:
		{
			// FIXME 尚且不清楚reset的机制,这里的测试结果表明
			//       qemu的reset只是简单地将PC的值置为RVBAR_EL3
			//       通常而言,就是0地址,而其他寄存器值不变
			//       应该有其他方法进行reset,但绝不是简单的跳转。
//			__asm__ ("mrs x0,RVBAR_EL3 \n\t":::"x0");// 0
			auto func=static_cast<SmcFunc>(lowerMaskBits(16) & esr.ISS);
			if(func==SmcFunc::warmReset)
				ASM_WARM_RESET(3);
			break;
		}
		case ExceptionClass::HVC_AA64:
		{
			auto func=static_cast<HvcFunc>(lowerMaskBits(16) & esr.ISS);
			if(func==HvcFunc::warmReset)
				ASM_WARM_RESET(2);
			break;
		}
		default:
			unhandledException();
			break;
		}
		break;
	}
	case ExceptionType::DEBUG:
	{
		break;
	}
	}
	exitCurrent();
}