Add recon drones and body burial; stabilize spectator camera
This commit is contained in:
@@ -10,7 +10,7 @@ def adapt(s):
|
||||
s=s.replace('m_ERRViewWatchers[i].','m_ERRViewWatchers[i]->')
|
||||
for cls in ['ERR_ObserverScope','ERR_GameMode','ERR_Actors','ERR_ObserverRules','ERR_ObserverViewRules','Replication','SCR_PlayerController','RplComponent','SCR_FactionManager','RplId','Math','vector']:s=s.replace(cls+'.',cls+'::')
|
||||
s=s.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->').replace('GetPlayerManager().','GetPlayerManager()->').replace('Players().','Players()->').replace('Get().','Get()->')
|
||||
s=s.replace('actor.FindComponent(RplComponent)', 'actor->FindComponent()')
|
||||
s=s.replace('actor.FindComponent(RplComponent)', 'actor->FindComponent()').replace('actor.GetOrigin()', 'actor->GetOrigin()')
|
||||
s=s.replace('Rpc(ERR_EnableViewPublisher)', 'SendLease()')
|
||||
return s
|
||||
methods='\n'.join(adapt(body(p,k)) for k in ['bool ERR_ViewRecipient(', 'protected void ERR_RequestPlayerView(', 'void ERR_AddViewWatcher(', 'protected void ERR_EnableViewPublisher(', 'protected void ERR_SubmitPlayerView(', 'protected void ERR_ReceivePlayerView('])
|
||||
@@ -20,12 +20,13 @@ run(r'''
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
struct vector {float operator[](int i){return i==0?x:(i==1?y:z);}bool operator==(vector b){return x==b.x&&y==b.y&&z==b.z;}static vector Zero;float x=0,y=0,z=0;float LengthSq(){return x*x+y*y+z*z;}static float Dot(vector a,vector b){return a.x*b.x+a.y*b.y+a.z*b.z;}};
|
||||
#include <limits>
|
||||
struct vector {vector operator+(vector b){return{x+b.x,y+b.y,z+b.z};}vector operator-(vector b){return{x-b.x,y-b.y,z-b.z};}float operator[](int i){return i==0?x:(i==1?y:z);}bool operator==(vector b){return x==b.x&&y==b.y&&z==b.z;}static vector Zero;float x=0,y=0,z=0;float LengthSq(){return x*x+y*y+z*z;}static float Dot(vector a,vector b){return a.x*b.x+a.y*b.y+a.z*b.z;}};
|
||||
vector vector::Zero;
|
||||
namespace Math{float Round(float f){return std::round(f);}float AbsFloat(float a){return fabs(a);}}
|
||||
struct RplId{int value=-1;RplId(int i=-1):value(i){}static RplId Invalid(){return{-1};}bool operator==(RplId b){return value==b.value;}bool operator!=(RplId b){return value!=b.value;}};
|
||||
struct RplComponent{RplId id{11};RplId Id(){return id;}static RplComponent* Cast(RplComponent* p){return p;}};
|
||||
struct Actor {bool alive=true,conscious=true;int faction=1;RplComponent replication;RplComponent* FindComponent(){return &replication;}};using IEntity=Actor*;
|
||||
struct Actor {vector origin;vector GetOrigin(){return origin;}bool alive=true,conscious=true;int faction=1;RplComponent replication;RplComponent* FindComponent(){return &replication;}};using IEntity=Actor*;
|
||||
struct ERR_PlayerLife {int ConnectionId=1;bool valid=true;};
|
||||
struct Roster {std::map<IEntity,ERR_PlayerLife*> lives;ERR_PlayerLife* CurrentActor(IEntity a){auto p=lives.find(a);return p!=lives.end()&&p->second->valid?p->second:nullptr;}};
|
||||
struct ERR_GameMode {bool active=true;Roster roster;static ERR_GameMode* current;static ERR_GameMode* Get(){return current;}bool Active(){return active;}Roster* Players(){return &roster;}int PlayerFaction(){return 1;}};ERR_GameMode* ERR_GameMode::current;
|
||||
@@ -34,7 +35,7 @@ namespace SCR_FactionManager{int SGetFaction(IEntity a){return a?a->faction:0;}}
|
||||
namespace ERR_ObserverReason{int NONE=0,UNCONSCIOUS=4;}
|
||||
struct ERR_ObserverRules {'''+body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_Observer.c','static bool View(').replace('ERR_ObserverReason.','ERR_ObserverReason::')+r'''};
|
||||
template<class T>struct Array:std::vector<T>{int Count(){return this->size();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}void Insert(T v){this->push_back(v);}void Remove(int i){this->erase(this->begin()+i);}};
|
||||
struct ERR_ObserverViewRules {'''+adapt(body(p,'static bool Sample('))+adapt(body(p,'static bool Packet('))+r'''};
|
||||
struct ERR_ObserverViewRules {'''+''.join(adapt(body(p,k)) for k in ('static bool Sample(', 'static bool Origin(', 'static bool NearBody(', 'static vector WorldPosition(', 'static bool Packet('))+r'''};
|
||||
struct ERR_ObserverScope {'''+adapt(body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_ObserverScope.c','static bool Valid('))+r'''};
|
||||
namespace Replication{bool server=true;bool IsServer(){return server;}}
|
||||
struct SCR_PlayerController;
|
||||
@@ -42,7 +43,7 @@ struct Game {float now=1000;SCR_PlayerController* local=nullptr;std::map<int,SCR
|
||||
Game* GetWorld(){return this;}Game* GetPlayerManager(){return this;}float GetWorldTime(){return now;}SCR_PlayerController* GetPlayerController(){return local;}SCR_PlayerController* GetPlayerController(int id){return controllers[id];}} game;
|
||||
Game* GetGame(){return &game;}
|
||||
|
||||
struct Buffer{float pipFov=0;int pushes=0,stamp=-1;RplId target;bool Accepts(RplId t,int s){return t!=target||s>stamp;}void Clear(){stamp=-1;target=-1;}void Push(RplId t,int s,float,vector,vector,vector,float,float,RplId,vector,float pf=0,vector g={},float v=0){pushes++;stamp=s;target=t;pipFov=pf;}};
|
||||
struct Buffer{vector position;float pipFov=0;int pushes=0,stamp=-1;RplId target;bool Accepts(RplId t,int s){return t!=target||s>stamp;}void Clear(){stamp=-1;target=-1;}void Push(RplId t,int s,float,vector p,vector,vector,float,float,RplId,vector,float pf=0,vector g={},float v=0){position=p;pushes++;stamp=s;target=t;pipFov=pf;}};
|
||||
struct SCR_PlayerController {
|
||||
int id=0;IEntity controlled=nullptr,m_ERRServerObserved=nullptr,m_ERRViewSourceBody=nullptr;RplId m_ERRObservedId;
|
||||
int m_ERRObserverReason=1,m_ERRViewInputSequence=0,leases=0,deliveries=0;float m_ERRViewLeaseUntil=-1,m_ERRViewServerRequestAt=-1000,m_ERRViewLeaseSent=-1000,m_ERRViewPublishUntil=-1,m_ERRViewLastPacket=-1000;
|
||||
@@ -51,8 +52,8 @@ struct SCR_PlayerController {
|
||||
void SendLease(){leases++;}
|
||||
void ERR_DeliverPlayerView(RplId,int,Array<vector>*,RplId,vector){deliveries++;}
|
||||
// Legacy scenario call shape only constructs the new on-wire packet.
|
||||
void ERR_SubmitPlayerView(int seq,vector p,vector f,vector u,float fov,float near,RplId weapon,vector data){Array<vector> a;a.Insert(p);a.Insert(f);a.Insert(u);a.Insert({fov,near,0});ERR_SubmitPlayerView(seq,&a,weapon,data);}
|
||||
void ERR_ReceivePlayerView(RplId target,int stamp,vector p,vector f,vector u,float fov,float near,RplId weapon,vector data){Array<vector> a;a.Insert(p);a.Insert(f);a.Insert(u);a.Insert({fov,near,0});ERR_ReceivePlayerView(target,stamp,&a,weapon,data);}
|
||||
void ERR_SubmitPlayerView(int seq,vector p,vector f,vector u,float fov,float near,RplId weapon,vector data){Array<vector> a;a.Insert(p);a.Insert(f);a.Insert(u);a.Insert({fov,near,0});a.Insert({});ERR_SubmitPlayerView(seq,&a,weapon,data);}
|
||||
void ERR_ReceivePlayerView(RplId target,int stamp,vector p,vector f,vector u,float fov,float near,RplId weapon,vector data){Array<vector> a;a.Insert(p);a.Insert(f);a.Insert(u);a.Insert({fov,near,0});a.Insert({});ERR_ReceivePlayerView(target,stamp,&a,weapon,data);}
|
||||
'''+methods+r'''
|
||||
};
|
||||
int main(){
|
||||
@@ -84,13 +85,33 @@ int main(){
|
||||
game.local=&stranger;watcher.ERR_ReceivePlayerView({11},3,position,forward,up,60,.0125, -1, {});assert(watcher.m_ERRViewBuffer.pushes==1);
|
||||
game.local=&watcher;mode.active=false;watcher.ERR_ReceivePlayerView({11},4,position,forward,up,60,.0125, -1, {});assert(watcher.m_ERRViewBuffer.pushes==1);
|
||||
mode.active=true;game.local=&watcher;
|
||||
Array<vector> dual;for(vector v:{position,forward,up,vector{12,.02,6},position,forward,up,vector{60,.02,0},vector{0,0,1}})dual.Insert(v);
|
||||
Array<vector> dual;for(vector v:{position,forward,up,vector{12,.02,6},position,forward,up,vector{60,.02,0},vector{0,0,1},vector{15000,300,-16000}})dual.Insert(v);
|
||||
watcher.ERR_ReceivePlayerView(11,20,&dual,22,{1,0,0});assert(watcher.m_ERRHasPIP&&watcher.m_ERREyeBuffer.stamp==20&&watcher.m_ERRViewBuffer.stamp==20&&watcher.m_ERRViewBuffer.pipFov==6);
|
||||
assert(watcher.m_ERRViewBuffer.position==vector({15000,301.6,-16000}));
|
||||
assert(watcher.m_ERREyeBuffer.position==vector({15000,301.6,-16000}));
|
||||
dual[3].z=4;watcher.ERR_ReceivePlayerView(11,19,&dual,22,{1,0,0});assert(watcher.m_ERRViewBuffer.pipFov==6&&watcher.m_ERREyeBuffer.stamp==20);
|
||||
dual[4]={999,0,0};watcher.ERR_ReceivePlayerView(11,21,&dual,22,{1,0,0});assert(watcher.m_ERRViewBuffer.stamp==20);dual[4]=position;
|
||||
watcher.ERR_ReceivePlayerView(11,21,&dual,-1,{});assert(watcher.m_ERRViewBuffer.stamp==20); // PiP requires a scoped weapon
|
||||
watcher.ERR_ReceivePlayerView(11,22,position,forward,up,60,.02,-1,{});assert(!watcher.m_ERRHasPIP&&watcher.m_ERREyeBuffer.stamp==-1&&watcher.m_ERRViewBuffer.stamp==22);
|
||||
// Nonfinite origins and malformed/old packet shapes cannot advance either buffer.
|
||||
dual[9]={std::numeric_limits<float>::quiet_NaN(),0,0};
|
||||
watcher.ERR_ReceivePlayerView(11,23,&dual,22,{1,0,0});assert(watcher.m_ERRViewBuffer.stamp==22);
|
||||
dual[9]={0,std::numeric_limits<float>::infinity(),0};assert(!ERR_ObserverViewRules::Packet(&dual));
|
||||
dual[9]={0,0,10000001};assert(!ERR_ObserverViewRules::Packet(&dual));
|
||||
dual[9]={0,10000000,0};assert(!ERR_ObserverViewRules::Packet(&dual)); // reconstructed eye must remain bounded too
|
||||
dual.pop_back();assert(!ERR_ObserverViewRules::Packet(&dual));assert(!ERR_ObserverViewRules::Packet(nullptr));
|
||||
// Authority compares the captured origin to the canonical body's position,
|
||||
// without replacing that origin with the server's independently timed pose.
|
||||
game.now+=500;watcher.ERR_RequestPlayerView();
|
||||
Array<vector> ordinary;for(vector v:{position,forward,up,vector{60,.02,0},vector{15000,300,-16000}})ordinary.Insert(v);
|
||||
target.origin={15000,300,-16000};int delivered=watcher.deliveries;
|
||||
source.ERR_SubmitPlayerView(100,&ordinary,-1,{});assert(watcher.deliveries==delivered+1);
|
||||
game.now+=50;ordinary[4]={15100,300,-16000};source.ERR_SubmitPlayerView(101,&ordinary,-1,{});assert(watcher.deliveries==delivered+2);
|
||||
game.now+=50;ordinary[4]={15100.1,300,-16000};source.ERR_SubmitPlayerView(102,&ordinary,-1,{});
|
||||
assert(watcher.deliveries==delivered+2&&source.m_ERRViewInputSequence==101);
|
||||
ordinary[4]={std::numeric_limits<float>::quiet_NaN(),0,0};source.ERR_SubmitPlayerView(102,&ordinary,-1,{});assert(source.m_ERRViewInputSequence==101);
|
||||
ordinary.pop_back();source.ERR_SubmitPlayerView(102,&ordinary,-1,{});assert(source.m_ERRViewInputSequence==101);
|
||||
assert(!ERR_ObserverViewRules::Packet(&ordinary)); // legacy four-vector packet
|
||||
mode.active=true;game.local=&source;source.ERR_EnableViewPublisher();assert(source.m_ERRViewPublishUntil==game.now+2000);
|
||||
}
|
||||
''')
|
||||
|
||||
Reference in New Issue
Block a user