2011-08-03 20:05:33 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2007, 2010 - Bit-Blot
|
|
|
|
|
|
|
|
This file is part of Aquaria.
|
|
|
|
|
|
|
|
Aquaria is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
*/
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
#include "ActionMapper.h"
|
|
|
|
#include "Core.h"
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
typedef std::vector<unsigned> ButtonList;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
// TODO: clean this up, make single vector of tagged unions, sorted by key
|
|
|
|
struct LegacyActionData
|
2017-01-14 21:53:20 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
LegacyActionData()
|
|
|
|
: id(-1), state(-1)
|
|
|
|
, event(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int id; // -1 if no associated event
|
|
|
|
int state; // -1, 0, or 1
|
|
|
|
Event *event;
|
|
|
|
ButtonList buttonList;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ActionState
|
|
|
|
{
|
|
|
|
ACSTATE_ACTIVE = 0x1, // action is active right now (button is held down)
|
|
|
|
ACSTATE_ACCEPTED = 0x2 // handle that action when it comes in
|
|
|
|
};
|
2017-01-14 21:53:20 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
ActionMapper::ActionMapper()
|
|
|
|
{
|
|
|
|
cleared = false;
|
|
|
|
inputEnabled = true;
|
|
|
|
inUpdate = false;
|
2020-08-11 10:04:15 +00:00
|
|
|
InputMapper::RegisterActionMapper(this);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ActionMapper::~ActionMapper()
|
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
InputMapper::UnregisterActionMapper(this);
|
2011-08-03 20:05:33 +00:00
|
|
|
clearCreatedEvents();
|
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
LegacyActionData *ActionMapper::getActionDataByID(int actionID)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-07-16 01:09:44 +00:00
|
|
|
for (ActionDataSet::iterator i = actionData.begin(); i != actionData.end(); ++i)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if (i->id == actionID)
|
2011-08-03 20:05:33 +00:00
|
|
|
return &(*i);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
bool ActionMapper::isActing(unsigned actionID) const
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
return actionID < _activeActions.size() ? _activeActions[actionID] : false;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::addAction(unsigned actionID, unsigned k)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
assert(k);
|
|
|
|
if(!k)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LegacyActionData *ad = getActionDataByID(actionID);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-06-30 00:58:55 +00:00
|
|
|
if (!ad)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
LegacyActionData data;
|
2011-08-03 20:05:33 +00:00
|
|
|
data.id = actionID;
|
|
|
|
actionData.push_back(data);
|
2016-07-16 01:09:44 +00:00
|
|
|
ad = &actionData.back();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ad)
|
|
|
|
{
|
2015-08-16 00:24:14 +00:00
|
|
|
if(std::find(ad->buttonList.begin(), ad->buttonList.end(), k) == ad->buttonList.end())
|
|
|
|
ad->buttonList.push_back(k);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::addAction(Event *event, unsigned k, int state)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
LegacyActionData data;
|
2011-08-03 20:05:33 +00:00
|
|
|
data.event = event;
|
|
|
|
data.state = state;
|
|
|
|
data.buttonList.push_back(k);
|
|
|
|
actionData.push_back(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
Event* ActionMapper::addCreatedEvent(Event *event)
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < createdEvents.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
if (createdEvents[i] == event)
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
createdEvents.push_back(event);
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionMapper::clearCreatedEvents()
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < createdEvents.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
delete createdEvents[i];
|
|
|
|
}
|
|
|
|
createdEvents.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionMapper::enableInput()
|
|
|
|
{
|
|
|
|
inputEnabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionMapper::disableInput()
|
|
|
|
{
|
|
|
|
inputEnabled = false;
|
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::onUpdate (float dt)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if(inputEnabled && !inUpdate)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
inUpdate = true;
|
|
|
|
updateDirectInput();
|
|
|
|
updateActions();
|
|
|
|
inUpdate = false;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
_actionChanges.clear();
|
|
|
|
_inputChanges.clear();
|
|
|
|
|
2016-07-16 01:09:44 +00:00
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::updateActions()
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
// Trigger queued events and propagate changes
|
|
|
|
for(size_t i = 0; i < _actionChanges.size(); ++i)
|
|
|
|
{
|
|
|
|
const ActionUpdate& am = _actionChanges[i];
|
|
|
|
if(am.id >= _activeActions.size())
|
|
|
|
_activeActions.resize(am.id);
|
|
|
|
_activeActions[am.id] = am.state;
|
|
|
|
action(am.id, am.state, am.playerID, am.device);
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2016-07-17 15:50:27 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::updateDirectInput()
|
2016-05-05 17:40:28 +00:00
|
|
|
{
|
2016-07-17 20:25:24 +00:00
|
|
|
cleared = false;
|
2020-08-11 10:04:15 +00:00
|
|
|
for(size_t q = 0; q < _inputChanges.size(); ++q)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
int ik = _inputChanges[q];
|
|
|
|
bool keyState;
|
|
|
|
unsigned k;
|
|
|
|
if(ik < 0)
|
|
|
|
{
|
|
|
|
keyState = false;
|
|
|
|
k = -ik;
|
|
|
|
}
|
|
|
|
else
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
keyState = true;
|
|
|
|
k = ik;
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
for (ActionDataSet::iterator i = actionData.begin(); i != actionData.end(); ++i)
|
|
|
|
{
|
|
|
|
const LegacyActionData& ad = (*i);
|
|
|
|
for (ButtonList::const_iterator j = ad.buttonList.begin(); j != ad.buttonList.end(); j++)
|
2016-05-05 17:40:28 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if(k == (*j))
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if (ad.event)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if (ad.state==-1 || keyState == !!ad.state)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
ad.event->act();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
action(ad.id, keyState, -1, INP_DEV_NODEVICE);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2020-08-11 10:04:15 +00:00
|
|
|
if (core->loopDone || cleared)
|
|
|
|
return;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-17 20:25:24 +00:00
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::clearActions()
|
2016-07-17 20:25:24 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
cleared = true;
|
|
|
|
actionData.clear();
|
2016-07-17 20:25:24 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::recvAction(unsigned actionID, bool keyState, int playerID, InputDeviceType device)
|
2016-07-17 20:25:24 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if(!inputEnabled)
|
|
|
|
return;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
// enqueue change for later
|
|
|
|
// Since the update order isn't actually *defined* anywhere but it'm almost sure there
|
|
|
|
// will be subtle bugs if things aren't updated in the "right" order
|
|
|
|
// (aka as it happened to be, so far),
|
|
|
|
// use a queue so that the code can keep believing it's polling changes, while in fact
|
|
|
|
// under the hood it's a push-based system.
|
|
|
|
// Pushing every change to a queue also ensures we can't miss a button press that
|
|
|
|
// lasts shorter than one frame.
|
|
|
|
ActionUpdate am;
|
|
|
|
am.id = actionID;
|
|
|
|
am.state = keyState;
|
|
|
|
am.playerID = playerID;
|
|
|
|
am.device = device;
|
|
|
|
_actionChanges.push_back(am);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2016-07-17 20:25:24 +00:00
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::recvDirectInput(unsigned k, bool keyState)
|
2016-07-17 20:25:24 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
if(!inputEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_inputChanges.push_back(keyState ? (int)k : -(int)k);
|
2016-07-17 20:25:24 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 10:04:15 +00:00
|
|
|
void ActionMapper::ImportInput(const NamedAction *actions, size_t N)
|
2016-07-17 20:25:24 +00:00
|
|
|
{
|
2020-08-11 10:04:15 +00:00
|
|
|
// FIXME controllerfixup
|
|
|
|
InputMapper *im = NULL;
|
|
|
|
ActionSet as;
|
|
|
|
|
|
|
|
/*
|
|
|
|
for(size_t i = 0; i < dsq->user.control.actionSets.size(); ++i)
|
|
|
|
{
|
|
|
|
const ActionSet& as = dsq->user.control.actionSets[i];
|
|
|
|
*/
|
|
|
|
|
|
|
|
for(size_t i = 0; i < N; ++i)
|
|
|
|
as.importAction(im, actions[i].name, actions[i].actionID);
|
2016-07-17 23:27:58 +00:00
|
|
|
}
|