private void AddEntToSnapshot(SvEntityState svEntity, SharedEntity gEnt, List<int> entitiesIndex){ //如果已经添加了,就不再次添加 if(svEntity.snapshotCounter == snapshotCounter){ return; } svEntity.snapshotCounter = snapshotCounter; if(entitiesIndex.Count >= CConstVar.MAX_SNAPSHOT_ENTITIES){ return; } entitiesIndex.Add(gEnt.s.entityIndex); }
// Adds a shared entity such as a negative keyword list to the account's library. // Lists in the account's library can be associated with any campaign within the account. private async Task <AddSharedEntityResponse> AddSharedEntityAsync( SharedEntity sharedEntity, IList <SharedListItem> listItems) { var request = new AddSharedEntityRequest { ListItems = listItems, SharedEntity = sharedEntity }; return(await Service.CallAsync((s, r) => s.AddSharedEntityAsync(r), request)); }
public void StoreHistory(SharedEntity sEnt, int time) { historyHead++; if (historyHead >= CConstVar.NUM_CLIENT_HISTORY) { historyHead = 0; } int head = historyHead; history[head].mins = sEnt.r.mins; history[head].maxs = sEnt.r.maxs; history[head].currentOrigin = sEnt.r.currentOrigin; history[head].time = time; }
private void ClientEnterWorld(ClientNode cl, UserCmd cmd){ cl.state = ClientState.ACTIVE; int clNum = Array.IndexOf(clients, cl); SharedEntity ent = gEntities[clNum]; ent.s.entityIndex = clNum; cl.gEntity = ent; cl.deltaMessage = -1; cl.lastSnapshotTime = 0; //立即产生一个snapshot if(cmd != null){ cmd.CopyTo(cl.lastUserCmd); }else{ cl.lastUserCmd.Reset(); } CDataModel.GameSimulate.ClientBegin(clNum); }
//决定哪一个entity对客户端是可见的,并复制playerState。 //这个函数处理多个递归的入口,但是渲染器不会。 //对于其他玩家看到的视野,clent可以是client.gentity以外的东西 private void BuildClientSnapshot(ClientNode client){ snapshotCounter++; SvClientSnapshot frame = client.frames[client.netChan.outgoingSequence & CConstVar.PACKET_MASK]; frame.numEntities = 0; SharedEntity clEnt = client.gEntity; if(client == null || client.state == ClientState.ZOMBIE){ return; } PlayerState ps = GetClientPlayer(client);//client.playerState; ps.CopyTo(frame.playerState); int clientNum = frame.playerState.clientIndex; if(clientNum < 0 || clientNum > CConstVar.MAX_GENTITIES){ CLog.Error("SvEntity for gEntity: bad gEnt"); } var svEnt = svEntities[clientNum]; svEnt.snapshotCounter = snapshotCounter; Vector3 org = ps.origin; org[2] += ps.viewHeight; var entitiesIndex = new List<int>(CConstVar.MAX_SNAPSHOT_ENTITIES); AddEntitiesVisibleFromPoint(org, frame, entitiesIndex, false); //entitiesIndex里面的entityIndex不一定是连续的,但是有序的,从小到大 entitiesIndex.Sort(); frame.numEntities = 0; frame.firstEntity = nextSnapshotEntities; for(int i = 0; i < entitiesIndex.Count; i++){ var ent = gEntities[i]; snapshotEntities[nextSnapshotEntities % numSnapshotEntities] = ent.s; nextSnapshotEntities++; if(nextSnapshotEntities >= 0x7FFFFFFE){ CLog.Error("SV: nextSnapshotEntities wraped"); } frame.numEntities++; } }
// Adds a shared entity such as a negative keyword list to the account's library. // Lists in the account's library can be associated with any campaign within the account. private async Task<AddSharedEntityResponse> AddSharedEntityAsync( SharedEntity sharedEntity, IList<SharedListItem> listItems) { var request = new AddSharedEntityRequest { ListItems = listItems, SharedEntity = sharedEntity }; return (await Service.CallAsync((s, r) => s.AddSharedEntityAsync(r), request)); }
public void Init() { instance = new SharedEntity(); }
private void DirectConnect(IPEndPoint from) { ClientNode cl = null; int newClIdx = 0; ClientNode newcl = null; // ClientNode temp = new ClientNode(); string ip; var userinfo = CDataModel.CmdBuffer.Argv(1); int version = System.Convert.ToInt32(CUtils.GetValueForKey(userinfo, "protocol")); if(version != CConstVar.Protocol){ CNetwork_Server.Instance.OutOfBandSend(NetSrc.SERVER, from, string.Format("server protocol mismatches with client. server:%d, client:%d", CConstVar.Protocol, version)); return; } int chNum = System.Convert.ToInt32(CUtils.GetValueForKey(userinfo, "challenge")); // int qport = System.Convert.ToInt32(CUtils.GetValueForKey(userinfo, "qport")); int qport = from.Port; int port = System.Convert.ToInt32(CUtils.GetValueForKey(userinfo, "port")); from.Port = port; for(int i = 0; i < CConstVar.MAX_CLIENTS; i++){ cl = clients[i]; if(cl.state == ClientState.FREE){ continue; } if(from.Address.Equals(cl.netChan.remoteAddress.Address) && (cl.netChan.qport == qport || from.Port == cl.netChan.remoteAddress.Port)){ if(time - cl.lastConnectTime < CConstVar.reconnectLimit * 1000){ CLog.Info("{0}: reconnect rejected : too soon", from); return; } break; } } if(IPAddress.IsLoopback(from.Address)){ ip = "localhost"; }else{ ip = from.Address.ToString(); } CUtils.SetValueForKey(ref userinfo, "ip", ip); if(IPAddress.IsLoopback(from.Address)){ int ping; SvChallenge ch; int i; for(i = 0; i < CConstVar.MAX_CHALLENGES; i++){ if(from.Address.Equals(challenges[i].adr.Address)){ if(chNum == challenges[i].challenge){ break; } } } if(i == CConstVar.MAX_CHALLENGES){ CNetwork_Server.Instance.OutOfBandSend(NetSrc.SERVER, from, string.Format("no or bad challenge for your address %s", from)); return; } ch = challenges[i]; if(ch.wasrefused){ return; } ping = time - ch.pingTime; //局域网不判断ping if(!CNetwork.IsLANAddress(from.Address)){ if(CConstVar.minPing > 0 && ping < CConstVar.minPing){ CNetwork_Server.Instance.OutOfBandSend(NetSrc.SERVER, from, "server is for high pings only"); ch.wasrefused = true; return; } if(CConstVar.maxPing > 0 && ping < CConstVar.maxPing){ CNetwork_Server.Instance.OutOfBandSend(NetSrc.SERVER, from, "server is for high pings only"); ch.wasrefused = true; return; } } ch.connected = true; } // = temp; Action newClient = ()=>{ // newcl = temp; if(newcl == null) newcl = new ClientNode(); SharedEntity ent = gEntities[newClIdx]; newcl.gEntity = ent; newcl.challenge = chNum; newcl.netChan.SetUp(NetSrc.SERVER, from, chNum, qport); newcl.netChanQueue.Reset(); newcl.userInfo = userinfo; //发送连接消息给客户端 CNetwork_Server.Instance.OutOfBandSend(NetSrc.SERVER, from, string.Format("connectResponse {0} {1} {2}", chNum, CConstVar.ServerPort, CConstVar.serverID)); newcl.state = ClientState.CONNECTED; newcl.lastSnapshotTime = 0; newcl.lastPacketTime = time; newcl.lastConnectTime = time; //当收到来自客户端的第一条消息,就会发现这是来自不同的serverid,而gamestate消息没有发送,强制传输 newcl.gamestateMessageNum = -1; int count = 0; for(int i = 0; i < CConstVar.MAX_CLIENTS; i++){ if(clients[i].state >= ClientState.CONNECTED){ count++; } } if(count == 1 || count == CConstVar.MAX_CLIENTS){ nextHeartbeatTime = -999999; } // ClientEnterWorld(newcl, null); }; //如果有一个这个ip的连接,重用它 for(int i = 0; i < CConstVar.MAX_CLIENTS; i++){ cl = clients[i]; if(cl.state == ClientState.FREE){ continue; } if(from.Address.Equals(cl.netChan.remoteAddress.Address) && (cl.netChan.qport == qport || from.Port == cl.netChan.remoteAddress.Port)){ CLog.Info("{0}: reconnect rejected : too soon", from); newcl = cl; newClIdx = i; newClient(); break; } } //找到一个client //如果CConstVar.PrivateClients > 0, 那么会为"password"设置为的客户端保留位置 // string pwd = CUtils.GetValueForKey(userinfo, "password"); int startIdx = 0; if(pwd == CConstVar.PrivatePwd){ //跳过预留的位置 startIdx = CConstVar.PrivateClients; } newcl = null; for(int i = startIdx; i < CConstVar.MAX_CLIENTS; i++){ cl = clients[i]; if(cl.state == ClientState.FREE){ newcl = cl; newClIdx = i; break; } } if(newcl == null){ if(IPAddress.IsLoopback(from.Address)){ int count = 0; for(int i = startIdx; i < CConstVar.MAX_CLIENTS; i++){ cl = clients[i]; if(cl.netChan.isBot){ count++; } } //如果都是机器人 if(count >= CConstVar.MAX_CLIENTS - startIdx){ DropClient(clients[CConstVar.MAX_CLIENTS - 1],"only bots on server"); newcl = clients[CConstVar.MAX_CLIENTS -1]; newClIdx = CConstVar.MAX_CLIENTS -1; }else{ CLog.Error("server is full on local connect"); return; } } else{ CNetwork_Server.Instance.OutOfBandSend(NetSrc.SERVER, from, "server is full"); CLog.Info("Rejected a connection. {0}", from); return; } } //有一个新的客户端,所有重置reliableSequence和reliableAcknowledge if(cl != null){ cl.reliableAcknowledge = 0; cl.reliableSequence = 0; } newClient(); }
// private void AddEntitiesVisibleFromPoint(Vector3 origin, SvClientSnapshot frame, List<int> entitiesIndex, bool portal){ for(int e = 0; e < numEntities; e++){ SharedEntity ent = gEntities[e]; //没有连入的entity就不发送 if(!ent.r.linked){ continue; } if(ent.s.entityIndex != e){ CLog.Error("SV: entity index mismatch, fixing"); ent.s.entityIndex = e; } //entities能被标记为发送给一个客户端 if((ent.r.svFlags & SVFlags.SINGLE_CLIENT) != SVFlags.NONE){ if(ent.r.singleClinet != frame.playerState.clientIndex){ continue; } } //entities可以标记为发送给每个人但是只有一个客户端 if((ent.r.svFlags & SVFlags.NOTSINGLE_CLIENT) != SVFlags.NONE){ if(ent.r.singleClinet == frame.playerState.clientIndex){ continue; } } //entities可以标记为发送给指定掩码的客户端 if((ent.r.svFlags & SVFlags.CLIENT_MASK) != SVFlags.NONE){ if(frame.playerState.clientIndex > 32){ CLog.Error("SVFlags.CLIENT_MASK: clientNum >= 32"); } if((~ent.r.singleClinet & (1 << frame.playerState.clientIndex)) >0){ continue; } } if(ent == null || ent.s.entityIndex < 0 || ent.s.entityIndex >= CConstVar.MAX_GENTITIES){ CLog.Error("SV: entity index not in range"); } var svEnt = svEntities[ent.s.entityIndex]; //不要添加两次entity if(svEnt.snapshotCounter == snapshotCounter){ continue; } //广播的entities总会发送 if((ent.r.svFlags & SVFlags.BROADCAST) != SVFlags.NONE){ AddEntToSnapshot(svEnt, ent, entitiesIndex); continue; } //这里需要进行判断是否可见等 AddEntToSnapshot(svEnt, ent, entitiesIndex); if((ent.r.svFlags & SVFlags.PORTAL) != SVFlags.NONE){ Vector3 dir = ent.s.origin - origin; if(dir.magnitude > ent.s.generic1){ continue; } AddEntitiesVisibleFromPoint(ent.s.origin2, frame, entitiesIndex, true); } } }
// public bool physicss public GameEntity() { sEnt = new SharedEntity(); }