mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-19 21:46:56 +00:00
Compare commits
2 Commits
v1.0.6
...
v1.0.7-bac
Author | SHA1 | Date | |
---|---|---|---|
|
7b878ff947 | ||
|
c78c480f99 |
@@ -25,9 +25,16 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"net"
|
"net"
|
||||||
|
// _ "net/http/pprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
/*
|
||||||
|
// Only used for profiling
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("0.0.0.0:6060", nil)
|
||||||
|
}()
|
||||||
|
*/
|
||||||
MustParseConfig()
|
MustParseConfig()
|
||||||
MustParseConstants()
|
MustParseConstants()
|
||||||
storage.Init()
|
storage.Init()
|
||||||
|
@@ -483,7 +483,7 @@ func (pR *Room) StartBattle() {
|
|||||||
*/
|
*/
|
||||||
totalElapsedNanos := utils.UnixtimeNano() - battleStartedAt
|
totalElapsedNanos := utils.UnixtimeNano() - battleStartedAt
|
||||||
nextRenderFrameId := int32((totalElapsedNanos + pR.dilutedRollbackEstimatedDtNanos - 1) / pR.dilutedRollbackEstimatedDtNanos) // fast ceiling
|
nextRenderFrameId := int32((totalElapsedNanos + pR.dilutedRollbackEstimatedDtNanos - 1) / pR.dilutedRollbackEstimatedDtNanos) // fast ceiling
|
||||||
toSleepNanos := int64(0)
|
toSleepNanos := int64(pR.dilutedRollbackEstimatedDtNanos >> 1) // Sleep half-frame time by default
|
||||||
if nextRenderFrameId > pR.RenderFrameId {
|
if nextRenderFrameId > pR.RenderFrameId {
|
||||||
if 0 == pR.RenderFrameId {
|
if 0 == pR.RenderFrameId {
|
||||||
// It's important to send kickoff frame iff "0 == pR.RenderFrameId && nextRenderFrameId > pR.RenderFrameId", otherwise it might send duplicate kickoff frames
|
// It's important to send kickoff frame iff "0 == pR.RenderFrameId && nextRenderFrameId > pR.RenderFrameId", otherwise it might send duplicate kickoff frames
|
||||||
@@ -515,7 +515,7 @@ func (pR *Room) StartBattle() {
|
|||||||
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
||||||
|
|
||||||
elapsedInCalculation := (utils.UnixtimeNano() - stCalculation)
|
elapsedInCalculation := (utils.UnixtimeNano() - stCalculation)
|
||||||
toSleepNanos = pR.dilutedRollbackEstimatedDtNanos - elapsedInCalculation // don't sleep if "nextRenderFrame == pR.RenderFrameId"
|
toSleepNanos = pR.dilutedRollbackEstimatedDtNanos - elapsedInCalculation
|
||||||
if elapsedInCalculation > pR.RollbackEstimatedDtNanos {
|
if elapsedInCalculation > pR.RollbackEstimatedDtNanos {
|
||||||
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, RollbackEstimatedDtNanos=%v, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.RollbackEstimatedDtNanos, pR.dilutedRollbackEstimatedDtNanos))
|
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, RollbackEstimatedDtNanos=%v, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.RollbackEstimatedDtNanos, pR.dilutedRollbackEstimatedDtNanos))
|
||||||
}
|
}
|
||||||
@@ -544,13 +544,13 @@ func (pR *Room) StartBattle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
// [WARNING] DON'T put a "default" block here! Otherwise "for { select {... default: } }" pattern would NEVER block on empty channel and thus consume a lot of CPU time unnecessarily!
|
||||||
case inputsBufferSnapshot := <-playerDownsyncChan:
|
case inputsBufferSnapshot := <-playerDownsyncChan:
|
||||||
pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs, inputsBufferSnapshot.ShouldForceResync)
|
pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs, inputsBufferSnapshot.ShouldForceResync)
|
||||||
//Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId))
|
//Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId))
|
||||||
case inputsBufferSnapshot2 := <-playerSecondaryDownsyncChan:
|
case inputsBufferSnapshot2 := <-playerSecondaryDownsyncChan:
|
||||||
pR.downsyncPeerInputFrameUpsyncToSinglePlayer(playerId, player, inputsBufferSnapshot2.ToSendInputFrameDownsyncs, inputsBufferSnapshot2.PeerJoinIndex)
|
pR.downsyncPeerInputFrameUpsyncToSinglePlayer(playerId, player, inputsBufferSnapshot2.ToSendInputFrameDownsyncs, inputsBufferSnapshot2.PeerJoinIndex)
|
||||||
//Logger.Info(fmt.Sprintf("Sent secondary inputsBufferSnapshot to for (roomId: %d, playerId:%d)#2", pR.Id, playerId))
|
//Logger.Info(fmt.Sprintf("Sent secondary inputsBufferSnapshot to for (roomId: %d, playerId:%d)#2", pR.Id, playerId))
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -160,7 +160,6 @@ void startRecvLoop(void* arg) {
|
|||||||
|
|
||||||
int uvCloseRet = uv_loop_close(l);
|
int uvCloseRet = uv_loop_close(l);
|
||||||
CCLOG("UDP recv loop is closed in UvRecvThread, uvCloseRet=%d", uvCloseRet);
|
CCLOG("UDP recv loop is closed in UvRecvThread, uvCloseRet=%d", uvCloseRet);
|
||||||
uv_mutex_destroy(&recvRingBuffLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void startSendLoop(void* arg) {
|
void startSendLoop(void* arg) {
|
||||||
@@ -174,7 +173,6 @@ void startSendLoop(void* arg) {
|
|||||||
|
|
||||||
int uvCloseRet = uv_loop_close(l);
|
int uvCloseRet = uv_loop_close(l);
|
||||||
CCLOG("UDP send loop is closed in UvSendThread, uvCloseRet=%d", uvCloseRet);
|
CCLOG("UDP send loop is closed in UvSendThread, uvCloseRet=%d", uvCloseRet);
|
||||||
uv_mutex_destroy(&sendRingBuffLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int initSendLoop(struct sockaddr const* pUdpAddr) {
|
int initSendLoop(struct sockaddr const* pUdpAddr) {
|
||||||
@@ -189,9 +187,6 @@ int initSendLoop(struct sockaddr const* pUdpAddr) {
|
|||||||
uv_mutex_init(&sendRingBuffLock);
|
uv_mutex_init(&sendRingBuffLock);
|
||||||
sendRingBuff = new SendRingBuff(maxBuffedMsgs);
|
sendRingBuff = new SendRingBuff(maxBuffedMsgs);
|
||||||
|
|
||||||
uv_mutex_init(&recvRingBuffLock);
|
|
||||||
recvRingBuff = new RecvRingBuff(maxBuffedMsgs);
|
|
||||||
|
|
||||||
uv_async_init(sendLoop, &uvSendLoopStopSig, _onUvStopSig);
|
uv_async_init(sendLoop, &uvSendLoopStopSig, _onUvStopSig);
|
||||||
uv_async_init(sendLoop, &uvSendLoopTriggerSig, _onUvSthNewToSend);
|
uv_async_init(sendLoop, &uvSendLoopTriggerSig, _onUvSthNewToSend);
|
||||||
|
|
||||||
@@ -208,6 +203,9 @@ bool initRecvLoop(struct sockaddr const* pUdpAddr) {
|
|||||||
CCLOGERROR("Failed to bind recv; recvSockInitRes=%d, recvbindRes=%d, reason=%s", recvSockInitRes, recvbindRes, uv_strerror(recvbindRes));
|
CCLOGERROR("Failed to bind recv; recvSockInitRes=%d, recvbindRes=%d, reason=%s", recvSockInitRes, recvbindRes, uv_strerror(recvbindRes));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
uv_mutex_init(&recvRingBuffLock);
|
||||||
|
recvRingBuff = new RecvRingBuff(maxBuffedMsgs);
|
||||||
|
|
||||||
uv_udp_recv_start(udpRecvSocket, _allocBuffer, _onRead);
|
uv_udp_recv_start(udpRecvSocket, _allocBuffer, _onRead);
|
||||||
uv_async_init(recvLoop, &uvRecvLoopStopSig, _onUvStopSig);
|
uv_async_init(recvLoop, &uvRecvLoopStopSig, _onUvStopSig);
|
||||||
|
|
||||||
@@ -248,20 +246,41 @@ bool DelayNoMore::UdpSession::openUdpSession(int port) {
|
|||||||
|
|
||||||
bool DelayNoMore::UdpSession::closeUdpSession() {
|
bool DelayNoMore::UdpSession::closeUdpSession() {
|
||||||
CCLOG("About to close udp session and dealloc all resources...");
|
CCLOG("About to close udp session and dealloc all resources...");
|
||||||
|
|
||||||
|
/*
|
||||||
|
[WARNING] It's possible that "closeUdpSession" is called when "openUdpSession" was NEVER CALLED, thus we have to avoid program crash in this case.
|
||||||
|
|
||||||
uv_async_send(&uvSendLoopStopSig);
|
In general one shouldn't just check the state of "sendTid" by whether or not "NULL == sendLoop", but in this particular game, both "openUdpSession" and "closeUdpSession" are only called from "GameThread", no thread-safety concern here, i.e. if "openUdpSession" was ever called earlier, then "sendLoop" wouldn't be NULL when "closeUdpSession" is later called.
|
||||||
CCLOG("Signaling UvSendThread to end in GameThread...");
|
*/
|
||||||
uv_thread_join(&sendTid);
|
if (NULL != sendLoop) {
|
||||||
free(udpSendSocket);
|
uv_async_send(&uvSendLoopStopSig);
|
||||||
free(sendLoop);
|
CCLOG("Signaling UvSendThread to end in GameThread...");
|
||||||
delete sendRingBuff;
|
uv_thread_join(&sendTid);
|
||||||
|
free(udpSendSocket);
|
||||||
|
free(sendLoop);
|
||||||
|
delete sendRingBuff;
|
||||||
|
|
||||||
|
udpSendSocket = NULL;
|
||||||
|
sendLoop = NULL;
|
||||||
|
sendRingBuff = NULL;
|
||||||
|
|
||||||
uv_async_send(&uvRecvLoopStopSig); // The few if not only guaranteed thread safe utility of libuv :) See http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send
|
uv_mutex_destroy(&sendRingBuffLock);
|
||||||
CCLOG("Signaling UvRecvThread to end in GameThread...");
|
}
|
||||||
uv_thread_join(&recvTid);
|
|
||||||
free(udpRecvSocket);
|
if (NULL != recvLoop) {
|
||||||
free(recvLoop);
|
uv_async_send(&uvRecvLoopStopSig); // The few if not only guaranteed thread safe utility of libuv :) See http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send
|
||||||
delete recvRingBuff;
|
CCLOG("Signaling UvRecvThread to end in GameThread...");
|
||||||
|
uv_thread_join(&recvTid);
|
||||||
|
free(udpRecvSocket);
|
||||||
|
free(recvLoop);
|
||||||
|
delete recvRingBuff;
|
||||||
|
|
||||||
|
udpRecvSocket = NULL;
|
||||||
|
recvLoop = NULL;
|
||||||
|
recvRingBuff = NULL;
|
||||||
|
|
||||||
|
uv_mutex_destroy(&recvRingBuffLock);
|
||||||
|
}
|
||||||
|
|
||||||
CCLOG("Closed udp session and dealloc all resources in GameThread...");
|
CCLOG("Closed udp session and dealloc all resources in GameThread...");
|
||||||
|
|
||||||
@@ -356,8 +375,10 @@ bool DelayNoMore::UdpSession::pollUdpRecvRingBuff() {
|
|||||||
while (true) {
|
while (true) {
|
||||||
RecvWork f;
|
RecvWork f;
|
||||||
bool res = recvRingBuff->pop(&f);
|
bool res = recvRingBuff->pop(&f);
|
||||||
if (!res) return false;
|
if (!res) {
|
||||||
|
// Deliberately returning "true" here to prevent "jswrapper" from printing "Failed to invoke Xxx..." too frequently
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// [WARNING] Declaring "AutoHandleScope" is critical here, otherwise "onUdpMessageCb.toObject()" wouldn't be recognized as a function of the ScriptEngine!
|
// [WARNING] Declaring "AutoHandleScope" is critical here, otherwise "onUdpMessageCb.toObject()" wouldn't be recognized as a function of the ScriptEngine!
|
||||||
se::AutoHandleScope hs;
|
se::AutoHandleScope hs;
|
||||||
// [WARNING] Use of the "ScriptEngine" is only allowed in "GameThread a.k.a. CocosThread"!
|
// [WARNING] Use of the "ScriptEngine" is only allowed in "GameThread a.k.a. CocosThread"!
|
||||||
@@ -381,4 +402,4 @@ bool DelayNoMore::UdpSession::pollUdpRecvRingBuff() {
|
|||||||
}
|
}
|
||||||
//uv_mutex_unlock(&recvRingBuffLock);
|
//uv_mutex_unlock(&recvRingBuffLock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user