minetest源码解析八:ClientEnvironment

时间:2022-06-05 17:19:38

minetest源码解析八:ClientEnvironment


ClientEnvironment

minetest->environment.h


class ClientEnvironment : public Environment

{

void step(f32 dtime);

ClientMap *m_map;

std::map<u16,ClientActiveObject*> m_active_objects;

std::list<ClientSimpleObject*> m_simple_objects;

std::list<ClientEnvEvent> m_client_event_queue;

std::list<Player*> m_players;

};


这个对象主要是客户端环境对象,继承于Environment。服务端也有对应的ServerEnvironment类,同样也是继承于Environment


ClientEnvironment对象中主要包含ClientMap(客户端地图)、Players(玩家)、ClientActiveObject(客户端激活对象)这几个对象。函数方法中有个step()函数比较重要,主要是通过它来进行客户端环境更新的。


ClientEnvironment->step() 调用

只有客户端进行更新时才会调用客户端环境更新(ClientEnvironment->step()),即client->step()中有m_env->step()


客户端环境进行更新,主要更新光照、溺水、液体流淌等或者是设置客户端环境事件。然后在客户端更新中获取客户端环境事件,并根据相应事件类型做出相应的操作。


涉及函数


// Step environment
m_env.step(dtime);

/*
Get events
*/
for(;;)
{
ClientEnvEvent event = m_env.getClientEvent();
if(event.type == CEE_NONE)
{
break;
}
else if(event.type == CEE_PLAYER_DAMAGE)
{
if(m_ignore_damage_timer <= 0)
{
u8 damage = event.player_damage.amount;

if(event.player_damage.send_to_server)
sendDamage(damage);

// Add to ClientEvent queue
ClientEvent event;
event.type = CE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
m_client_event_queue.push_back(event);
}
}
else if(event.type == CEE_PLAYER_BREATH)
{
u16 breath = event.player_breath.amount;
sendBreath(breath);
}
}


客户端环境事件相关定义


enum ClientEnvEventType
{
CEE_NONE,
CEE_PLAYER_DAMAGE,
CEE_PLAYER_BREATH
};

struct ClientEnvEvent
{
ClientEnvEventType type;
union {
struct{
} none;
struct{
u8 amount;
bool send_to_server;
} player_damage;
struct{
u16 amount;
} player_breath;
};
};



客户端环境更新流程图


minetest源码解析八:ClientEnvironment



客户端环境更新流程图核心函数说明


1.Step time of day

更新day time


2.Get some settings

获取玩家的flyfree_move属性


3.Get local playerGet the speed the player is going

获取本地玩家以及当前玩家的速度,主要为后面做准备


4.Maximum position increment

最大位置增量、时间增量等


5.Handle local play->move(最大时间增量)应用物理:重力、液体浮力、液体下沉、液体阻力

循环执行,根据物理特性(重力、液体浮力、液体下沉、液体阻力)以及当前玩家的速度等计算玩家新的速度,来最终执行玩家移动。玩家以新的速度在最大的时间增量范围内移动。


6.坠落损伤:客户端环境事件

计算玩家坠落时的速度,根据速度来进一步确定玩家受伤情况甚至死亡。如果玩家死亡则执行damageLocalPlayer(damage,true);这里主要设置了一个玩家消亡的环境事件,没有真的立马执行玩家消亡事件,而是在退出客户端环境更新时再执行的。

涉及到的函数

damageLocalPlayer(damage, true);


void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
{
LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer);

if(handle_hp){
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
}

ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
event.player_damage.send_to_server = handle_hp;
m_client_event_queue.push_back(event);
}



7.熔岩损伤:客户端环境事件

先获取玩家头、中间、脚不同位置的node,根据nodenodedefinition中的contentFeature中的damage_per_second计算损伤,从而进行damageLocalPlayer(damage_per_second,true)


8.Drowning:溺水时呼吸、玩家生命值没了damage

溺水大于2s时头溺水情况,如果头已经在水里了,就需要计算玩家的呼吸情况以及要更新玩家呼吸事件,如果呼吸为0了,还需要damage玩家。

呼吸间隔大于0.5s时,如果没有溺水,就正常更新玩家呼吸情况,并更新环境事件列表。


涉及到的函数

void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
{
ClientEnvEvent event;
event.type = CEE_PLAYER_BREATH;
event.player_breath.amount = breath;
m_client_event_queue.push_back(event);
}


9.non-local palyers->move

处理不是本地的玩家move


10.Update lighting on all players on client

更新客户端上所有玩家的光照


11.Step active objects and update lighting of them

更新active objects以及它们的光照


12.Step and handle simple objects

更新处理simple Objects


13.GetClientEnvironmentEvent并处理

循环获取客户端环境事件,知道所有事件处理完毕退出循环。