From 3da47d22d6f7dd8105422fbd4941c9b66d3cefdc Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 11 Nov 2019 11:22:36 -0800 Subject: [PATCH 01/44] Sane behavior in unexpected situation: clear sprite .txt file cache.fcz whenver we rebuild .tga file bin_cache.fcz There's a chance that Steam doesn't properly update cache.fcz, leaving it outdated. --- gameSource/folderCache.cpp | 10 +++++++++- gameSource/folderCache.h | 3 ++- gameSource/spriteBank.cpp | 11 ++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/gameSource/folderCache.cpp b/gameSource/folderCache.cpp index 0228b5305..06a0edd90 100644 --- a/gameSource/folderCache.cpp +++ b/gameSource/folderCache.cpp @@ -13,7 +13,8 @@ FolderCache initFolderCache( const char *inFolderName, - char *outRebuildingCache ) { + char *outRebuildingCache, + char inForceRebuild ) { *outRebuildingCache = false; File *folderDir = new File( NULL, inFolderName ); @@ -27,6 +28,13 @@ FolderCache initFolderCache( const char *inFolderName, File *cacheFile = folderDir->getChildFile( "cache.fcz" ); + if( inForceRebuild && cacheFile->exists() ) { + printf( "Forcing remove/rebuild of cache.fcz in %s folder\n", + inFolderName ); + + cacheFile->remove(); + } + FolderCache c; c.folderDir = folderDir; diff --git a/gameSource/folderCache.h b/gameSource/folderCache.h index 0d60c50b1..97c1c338f 100644 --- a/gameSource/folderCache.h +++ b/gameSource/folderCache.h @@ -30,7 +30,8 @@ typedef struct FolderCache { FolderCache initFolderCache( const char *inFolderName, - char *outRebuildingCache ); + char *outRebuildingCache, + char inForceRebuild = false ); // both results destroyed by caller diff --git a/gameSource/spriteBank.cpp b/gameSource/spriteBank.cpp index 5988d8dbd..f8c85f4ec 100644 --- a/gameSource/spriteBank.cpp +++ b/gameSource/spriteBank.cpp @@ -88,10 +88,19 @@ int initSpriteBankStart( char *outRebuildingCache ) { currentBinFile = 0; char rebuildingA, rebuildingB; - cache = initFolderCache( "sprites", &rebuildingA ); + binCache = initBinFolderCache( "sprites", ".tga", &rebuildingB ); + char forceRebuild = false; + + if( rebuildingB ) { + forceRebuild = true; + } + + cache = initFolderCache( "sprites", &rebuildingA, forceRebuild ); + + *outRebuildingCache = rebuildingA || rebuildingB; From b49eef5d8f8bd9c18f9cb09196b59358253abcb9 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 11 Nov 2019 11:51:50 -0800 Subject: [PATCH 02/44] When skipping loading tga for a non-existing .txt (and thus no sprite record), don't skip reading data from bin cache file (to advance the file read). --- gameSource/spriteBank.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/gameSource/spriteBank.cpp b/gameSource/spriteBank.cpp index f8c85f4ec..5f39017c9 100644 --- a/gameSource/spriteBank.cpp +++ b/gameSource/spriteBank.cpp @@ -456,25 +456,27 @@ float initSpriteBankStep() { if( spriteID > 0 ) { - SpriteRecord *r = getSpriteRecord( spriteID ); - - // there might be tga file that we have no .txt file, and thus - // no record, for - if( r != NULL ) { - int contSize; - unsigned char *contents = getFileContents( binCache, i, - fileName, - &contSize ); - if( contents != NULL ) { - + int contSize; + unsigned char *contents = getFileContents( binCache, i, + fileName, + &contSize ); + if( contents != NULL ) { + + // there might be tga file that we have no .txt file, + // and thus no record + // Note that we still must read content for such a file, + // because binCache must be read in order. + SpriteRecord *r = getSpriteRecord( spriteID ); + + if( r != NULL ) { loadSpriteFromRawTGAData( spriteID, contents, contSize ); r->numStepsUnused = 0; loadedSprites.push_back( spriteID ); - - delete [] contents; } + + delete [] contents; } } } From f41465a5af36b28cd97ea4bbd58433ea546cf97e Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 11 Nov 2019 13:14:28 -0800 Subject: [PATCH 03/44] Factored out which files should be loaded in each bank into a function call. --- gameSource/animationBank.cpp | 10 +++++++++- gameSource/categoryBank.cpp | 10 +++++++++- gameSource/objectBank.cpp | 15 ++++++++++++--- gameSource/spriteBank.cpp | 16 ++++++++++++---- gameSource/transitionBank.cpp | 11 ++++++++++- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/gameSource/animationBank.cpp b/gameSource/animationBank.cpp index 0e960d5af..1dfe3643a 100644 --- a/gameSource/animationBank.cpp +++ b/gameSource/animationBank.cpp @@ -76,6 +76,14 @@ bool isTrippingEffectOn; bool trippingEffectDisabled; +static char shouldFileBeCached( char *inFileName ) { + if( strstr( inFileName, ".txt" ) != NULL ) { + return true; + } + return false; + } + + int initAnimationBankStart( char *outRebuildingCache ) { @@ -183,7 +191,7 @@ float initAnimationBankStep() { char *txtFileName = getFileName( cache, i ); - if( strstr( txtFileName, ".txt" ) != NULL ) { + if( shouldFileBeCached( txtFileName ) ) { // every .txt file is an animation file diff --git a/gameSource/categoryBank.cpp b/gameSource/categoryBank.cpp index d047a6dda..37d70b585 100644 --- a/gameSource/categoryBank.cpp +++ b/gameSource/categoryBank.cpp @@ -43,6 +43,14 @@ static int maxID; static int maxObjectID; +static char shouldFileBeCached( char *inFileName ) { + if( strstr( inFileName, ".txt" ) != NULL ) { + return true; + } + return false; + } + + int initCategoryBankStart( char *outRebuildingCache ) { maxID = 0; @@ -70,7 +78,7 @@ float initCategoryBankStep() { char *txtFileName = getFileName( cache, i ); - if( strstr( txtFileName, ".txt" ) != NULL ) { + if( shouldFileBeCached( txtFileName ) ) { // a category txt file! diff --git a/gameSource/objectBank.cpp b/gameSource/objectBank.cpp index 9ba59a823..7a078aad2 100644 --- a/gameSource/objectBank.cpp +++ b/gameSource/objectBank.cpp @@ -256,6 +256,17 @@ void setDrawColor( FloatRGB inColor ) { +static char shouldFileBeCached( char *inFileName ) { + if( strstr( inFileName, ".txt" ) != NULL && + strstr( inFileName, "groundHeat_" ) == NULL && + strcmp( inFileName, "nextObjectNumber.txt" ) != 0 ) { + return true; + } + return false; + } + + + static char autoGenerateUsedObjects = false; static char autoGenerateVariableObjects = false; @@ -726,9 +737,7 @@ float initObjectBankStep() { char *txtFileName = getFileName( cache, i ); - if( strstr( txtFileName, ".txt" ) != NULL && - strstr( txtFileName, "groundHeat_" ) == NULL && - strcmp( txtFileName, "nextObjectNumber.txt" ) != 0 ) { + if( shouldFileBeCached( txtFileName ) ) { // an object txt file! diff --git a/gameSource/spriteBank.cpp b/gameSource/spriteBank.cpp index 5f39017c9..53d745f77 100644 --- a/gameSource/spriteBank.cpp +++ b/gameSource/spriteBank.cpp @@ -80,6 +80,17 @@ void enableSpriteSearch( char inEnable ) { +// skip all non-txt files (only read meta data files on init, +// not bulk data tga files) +static char shouldFileBeCached( char *inFileName ) { + if( strstr( inFileName, ".txt" ) != NULL && + strcmp( inFileName, "nextSpriteNumber.txt" ) != 0 ) { + return true; + } + return false; + } + + int initSpriteBankStart( char *outRebuildingCache ) { maxID = 0; @@ -290,10 +301,7 @@ float initSpriteBankStep() { char *fileName = getFileName( cache, i ); - // skip all non-txt files (only read meta data files on init, - // not bulk data tga files) - if( strstr( fileName, ".txt" ) != NULL && - strcmp( fileName, "nextSpriteNumber.txt" ) != 0 ) { + if( shouldFileBeCached( fileName ) ) { //printf( "Loading sprite from path %s\n", fileName ); diff --git a/gameSource/transitionBank.cpp b/gameSource/transitionBank.cpp index bbacc513f..068fc2f43 100644 --- a/gameSource/transitionBank.cpp +++ b/gameSource/transitionBank.cpp @@ -60,6 +60,15 @@ static char autoGenerateGenericUseTransitions = false; static char autoGenerateVariableTransitions = false; +static char shouldFileBeCached( char *inFileName ) { + if( strstr( inFileName, ".txt" ) != NULL ) { + return true; + } + return false; + } + + + int initTransBankStart( char *outRebuildingCache, char inAutoGenerateCategoryTransitions, char inAutoGenerateUsedObjectTransitions, @@ -94,7 +103,7 @@ float initTransBankStep() { char *txtFileName = getFileName( cache, i ); - if( strstr( txtFileName, ".txt" ) != NULL ) { + if( shouldFileBeCached( txtFileName ) ) { int actor = 0; int target = -2; From 33cd1ab519d0beb0005d088f9b190abe5cc47158 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 11 Nov 2019 15:10:38 -0800 Subject: [PATCH 04/44] Making sure cache.fcz has exactly same list of files as corresponding folder. Checks file names only, not contents. On mismatch, cache.fcz is rebuilt. --- gameSource/animationBank.cpp | 3 +- gameSource/categoryBank.cpp | 3 +- gameSource/folderCache.cpp | 119 ++++++++++++++++++++++++++++++++++ gameSource/folderCache.h | 4 ++ gameSource/objectBank.cpp | 3 +- gameSource/spriteBank.cpp | 3 +- gameSource/transitionBank.cpp | 3 +- 7 files changed, 133 insertions(+), 5 deletions(-) diff --git a/gameSource/animationBank.cpp b/gameSource/animationBank.cpp index 1dfe3643a..1695d0a56 100644 --- a/gameSource/animationBank.cpp +++ b/gameSource/animationBank.cpp @@ -173,7 +173,8 @@ int initAnimationBankStart( char *outRebuildingCache ) { currentFile = 0; - cache = initFolderCache( "animations", outRebuildingCache ); + cache = initFolderCache( "animations", outRebuildingCache, + shouldFileBeCached ); return cache.numFiles; } diff --git a/gameSource/categoryBank.cpp b/gameSource/categoryBank.cpp index 37d70b585..9c8a4c600 100644 --- a/gameSource/categoryBank.cpp +++ b/gameSource/categoryBank.cpp @@ -59,7 +59,8 @@ int initCategoryBankStart( char *outRebuildingCache ) { currentFile = 0; - cache = initFolderCache( "categories", outRebuildingCache ); + cache = initFolderCache( "categories", outRebuildingCache, + shouldFileBeCached ); return cache.numFiles; } diff --git a/gameSource/folderCache.cpp b/gameSource/folderCache.cpp index 06a0edd90..2cd07ca34 100644 --- a/gameSource/folderCache.cpp +++ b/gameSource/folderCache.cpp @@ -11,9 +11,16 @@ +static int stringSortCompare(const void *inA, const void * inB ) { + + return strcmp( *(char**)inA, *(char**)inB ); + } + + FolderCache initFolderCache( const char *inFolderName, char *outRebuildingCache, + char (*inInclusionTest)( char *inFileName ), char inForceRebuild ) { *outRebuildingCache = false; @@ -117,6 +124,9 @@ FolderCache initFolderCache( const char *inFolderName, *outRebuildingCache = false; + printf( "cache.fcz file in folder %s good with %d files\n", + inFolderName, c.numFiles ); + delete [] charData; } } @@ -124,6 +134,112 @@ FolderCache initFolderCache( const char *inFolderName, } delete cacheFile; + + + if( cacheGood ) { + // make sure cache matches existing folder contents + + printf( "Checking that cache contains all of %s folder's " + "current files...\n", inFolderName ); + + double startTime = Time::getCurrentTime(); + + int numChildFiles; + File **childFiles = + folderDir->getChildFilesSorted( &numChildFiles ); + + + char **cacheFileNames = new char*[ c.numFiles ]; + + for( int j=0; jgetFileName(); + + // skip our special cache data file + if( ! childFiles[i]->isDirectory() + && + // make sure file should be included + inInclusionTest( fileName ) + && + strcmp( fileName, "cache.fcz" ) != 0 ) { + + + if( j < c.numFiles ) { + if( strcmp( cacheFileNames[j], fileName ) != 0 ) { + cacheStale = true; + printf( + "Cache file %s does not match folder file %s\n", + cacheFileNames[j], fileName ); + delete [] fileName; + break; + } + } + else { + cacheStale = true; + printf( + "Folder file %s not present in cache.\n", fileName ); + delete [] fileName; + break; + } + j++; + } + delete [] fileName; + } + + if( ! cacheStale && j < c.numFiles ) { + printf( "Cache contains %d extra files not present in folder\n", + c.numFiles - j ); + cacheStale = true; + } + + delete [] cacheFileNames; + + for( int i=0; i(); + + cacheGood = false; + } + } + + + + if( !cacheGood ) { // cache stale or not present @@ -144,6 +260,9 @@ FolderCache initFolderCache( const char *inFolderName, // skip our special cache data file if( ! childFiles[i]->isDirectory() + && + // make sure file should be included + inInclusionTest( fileName ) && strcmp( fileName, "cache.fcz" ) != 0 ) { diff --git a/gameSource/folderCache.h b/gameSource/folderCache.h index 97c1c338f..ca12c12ef 100644 --- a/gameSource/folderCache.h +++ b/gameSource/folderCache.h @@ -29,8 +29,12 @@ typedef struct FolderCache { +// inInclusionTest is a function that takes a file name and returns +// true if the file should be included in the cache + FolderCache initFolderCache( const char *inFolderName, char *outRebuildingCache, + char (*inInclusionTest)( char *inFileName ), char inForceRebuild = false ); diff --git a/gameSource/objectBank.cpp b/gameSource/objectBank.cpp index 7a078aad2..fe84f53b7 100644 --- a/gameSource/objectBank.cpp +++ b/gameSource/objectBank.cpp @@ -279,7 +279,8 @@ int initObjectBankStart( char *outRebuildingCache, currentFile = 0; - cache = initFolderCache( "objects", outRebuildingCache ); + cache = initFolderCache( "objects", outRebuildingCache, + shouldFileBeCached ); autoGenerateUsedObjects = inAutoGenerateUsedObjects; autoGenerateVariableObjects = inAutoGenerateVariableObjects; diff --git a/gameSource/spriteBank.cpp b/gameSource/spriteBank.cpp index 53d745f77..85b546b34 100644 --- a/gameSource/spriteBank.cpp +++ b/gameSource/spriteBank.cpp @@ -109,7 +109,8 @@ int initSpriteBankStart( char *outRebuildingCache ) { forceRebuild = true; } - cache = initFolderCache( "sprites", &rebuildingA, forceRebuild ); + cache = initFolderCache( "sprites", &rebuildingA, shouldFileBeCached, + forceRebuild ); *outRebuildingCache = rebuildingA || rebuildingB; diff --git a/gameSource/transitionBank.cpp b/gameSource/transitionBank.cpp index 068fc2f43..e3ff374f7 100644 --- a/gameSource/transitionBank.cpp +++ b/gameSource/transitionBank.cpp @@ -85,7 +85,8 @@ int initTransBankStart( char *outRebuildingCache, currentFile = 0; - cache = initFolderCache( "transitions", outRebuildingCache ); + cache = initFolderCache( "transitions", outRebuildingCache, + shouldFileBeCached ); return cache.numFiles; } From 479df3b72695dab2dfed16840670e593c86c8326 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Tue, 12 Nov 2019 11:24:52 -0800 Subject: [PATCH 05/44] Map change log now includes playerID responsible for each change. --- server/map.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/server/map.cpp b/server/map.cpp index 178eaff2d..5411f68f1 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -7450,32 +7450,41 @@ static void logMapChange( int inX, int inY, int inID ) { if( o != NULL && o->floor ) { extraFlag = "f"; } - + + int respPlayer = currentResponsiblePlayer; + + if( respPlayer != -1 && respPlayer < 0 ) { + respPlayer = - respPlayer; + } + if( o != NULL && o->isUseDummy ) { - fprintf( mapChangeLogFile, - "%.2f %d %d %s%du%d\n", + fprintf( mapChangeLogFile, + "%.2f %d %d %s%du%d %d\n", Time::getCurrentTime() - mapChangeLogTimeStart, inX, inY, extraFlag, o->useDummyParent, - o->thisUseDummyIndex ); + o->thisUseDummyIndex, + respPlayer ); } else if( o != NULL && o->isVariableDummy ) { - fprintf( mapChangeLogFile, - "%.2f %d %d %s%dv%d\n", + fprintf( mapChangeLogFile, + "%.2f %d %d %s%dv%d %d\n", Time::getCurrentTime() - mapChangeLogTimeStart, inX, inY, extraFlag, o->variableDummyParent, - o->thisVariableDummyIndex ); + o->thisVariableDummyIndex, + respPlayer ); } else { - fprintf( mapChangeLogFile, - "%.2f %d %d %s%d\n", + fprintf( mapChangeLogFile, + "%.2f %d %d %s%d %d\n", Time::getCurrentTime() - mapChangeLogTimeStart, inX, inY, extraFlag, - inID ); + inID, + respPlayer ); } } } From e10575351e3100add949a4ae96c760be776d088f Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Tue, 12 Nov 2019 13:32:30 -0800 Subject: [PATCH 06/44] Map change logs now roll over every 24 hours and don't include biome seed. --- server/map.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/server/map.cpp b/server/map.cpp index 5411f68f1..4366b3a3e 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -2765,9 +2765,8 @@ static void setupMapChangeLogFile() { // file does not exist char *newFileName = - autoSprintf( "%.ftime_%useedA_%useedB_mapLog.txt", - Time::getCurrentTime(), - biomeRandSeedA, biomeRandSeedB ); + autoSprintf( "%.ftime_mapLog.txt", + Time::getCurrentTime() ); File *f = logFolder.getChildFile( newFileName ); @@ -2956,6 +2955,7 @@ void reseedMap( char inForceFresh ) { } } } + delete [] allObjects; } } @@ -7442,7 +7442,17 @@ void setMapObjectRaw( int inX, int inY, int inID ) { static void logMapChange( int inX, int inY, int inID ) { // log it? if( mapChangeLogFile != NULL ) { - + + double timeDelta = Time::getCurrentTime() - mapChangeLogTimeStart; + + if( timeDelta > 3600 * 24 ) { + // break logs int 24-hour chunks + setupMapChangeLogFile(); + timeDelta = Time::getCurrentTime() - mapChangeLogTimeStart; + } + + + ObjectRecord *o = getObject( inID ); const char *extraFlag = ""; @@ -7459,8 +7469,8 @@ static void logMapChange( int inX, int inY, int inID ) { if( o != NULL && o->isUseDummy ) { fprintf( mapChangeLogFile, - "%.2f %d %d %s%du%d %d\n", - Time::getCurrentTime() - mapChangeLogTimeStart, + "%.2f %d %d %s%du%d %d\n", + timeDelta, inX, inY, extraFlag, o->useDummyParent, @@ -7470,7 +7480,7 @@ static void logMapChange( int inX, int inY, int inID ) { else if( o != NULL && o->isVariableDummy ) { fprintf( mapChangeLogFile, "%.2f %d %d %s%dv%d %d\n", - Time::getCurrentTime() - mapChangeLogTimeStart, + timeDelta, inX, inY, extraFlag, o->variableDummyParent, @@ -7480,7 +7490,7 @@ static void logMapChange( int inX, int inY, int inID ) { else { fprintf( mapChangeLogFile, "%.2f %d %d %s%d %d\n", - Time::getCurrentTime() - mapChangeLogTimeStart, + timeDelta, inX, inY, extraFlag, inID, From 5f8693f9e46b6aede6486ac3cb505fab9450a9c3 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 13 Nov 2019 09:18:02 -0800 Subject: [PATCH 07/44] Map biome seed now logged in separate file along with map change logs, but that seed file is only published after the map is reseeded (if it ever is, due to a wipe or player-triggered apocalypse). --- scripts/syncMapChangeLogs.sh | 0 server/map.cpp | 31 ++++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) mode change 100755 => 100644 scripts/syncMapChangeLogs.sh diff --git a/scripts/syncMapChangeLogs.sh b/scripts/syncMapChangeLogs.sh old mode 100755 new mode 100644 diff --git a/server/map.cpp b/server/map.cpp index 4366b3a3e..17ed3e7af 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -2801,7 +2801,7 @@ void reseedMap( char inForceFresh ) { if( seedFile != NULL ) { int numRead = - fscanf( seedFile, "%d %d", &biomeRandSeedA, &biomeRandSeedB ); + fscanf( seedFile, "%u %u", &biomeRandSeedA, &biomeRandSeedB ); fclose( seedFile ); if( numRead == 2 ) { @@ -2957,6 +2957,35 @@ void reseedMap( char inForceFresh ) { } delete [] allObjects; } + + + setupMapChangeLogFile(); + + if( !set && mapChangeLogFile != NULL ) { + // whenever we actually change the seed, save it to a separate + // file in log folder + + File logFolder( NULL, "mapChangeLogs" ); + + char *newFileName = + autoSprintf( "%.ftime_mapSeed.txt", + Time::getCurrentTime() ); + + File *f = logFolder.getChildFile( newFileName ); + + delete [] newFileName; + + char *fullName = f->getFullFileName(); + + delete f; + + FILE *seedFile = fopen( fullName, "w" ); + delete [] fullName; + + fprintf( seedFile, "%u %u", biomeRandSeedA, biomeRandSeedB ); + + fclose( seedFile ); + } } From 775fc7c828abde0d274fcab40558aaf7212e9fc0 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Tue, 12 Nov 2019 18:21:22 -0800 Subject: [PATCH 08/44] Fixed cache size inconsistency. --- server/map.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/server/map.cpp b/server/map.cpp index 17ed3e7af..7d86ab955 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -2036,10 +2036,21 @@ static int computeDBCacheHash( int inKeyA, int inKeyB, } return hashKey; } - - - - + + + +static int computeBLCacheHash( int inKeyA, int inKeyB ) { + + int hashKey = ( inKeyA * CACHE_PRIME_A + + inKeyB * CACHE_PRIME_B ) % DB_CACHE_SIZE; + if( hashKey < 0 ) { + hashKey += DB_CACHE_SIZE; + } + return hashKey; + } + + + typedef struct DBTimeCacheRecord { int x, y, slot, subCont; timeSec_t timeVal; @@ -2140,8 +2151,8 @@ static void dbTimePutCached( int inX, int inY, int inSlot, int inSubCont, // returns -1 on miss static char blockingGetCached( int inX, int inY ) { BlockingCacheRecord r = - blockingCache[ computeXYCacheHash( inX, inY ) ]; - + blockingCache[ computeBLCacheHash( inX, inY ) ]; + if( r.x == inX && r.y == inY && r.blocking != -1 ) { return r.blocking; @@ -2155,16 +2166,16 @@ static char blockingGetCached( int inX, int inY ) { static void blockingPutCached( int inX, int inY, char inBlocking ) { BlockingCacheRecord r = { inX, inY, inBlocking }; - - blockingCache[ computeXYCacheHash( inX, inY ) ] = r; + + blockingCache[ computeBLCacheHash( inX, inY ) ] = r; } static void blockingClearCached( int inX, int inY ) { BlockingCacheRecord *r = - &( blockingCache[ computeXYCacheHash( inX, inY ) ] ); - + &( blockingCache[ computeBLCacheHash( inX, inY ) ] ); + if( r->x == inX && r->y == inY ) { r->blocking = -1; } From c7f71a4e2169e80cde261980f56ba2dcb7e62161 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 18 Nov 2019 11:38:38 -0800 Subject: [PATCH 09/44] Fixed client to not hang on loading if an expected sound file is missing. --- gameSource/soundBank.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gameSource/soundBank.cpp b/gameSource/soundBank.cpp index 6d761a0a0..5d8c75472 100644 --- a/gameSource/soundBank.cpp +++ b/gameSource/soundBank.cpp @@ -1135,7 +1135,10 @@ char markSoundLive( int inID ) { SoundRecord *r = getSoundRecord( inID ); if( r == NULL ) { - return false; + // if sound record doesn't exist, sound will never load + // count sound as live so that parts of code that are waiting + // for it to load can move on + return true; } r->numStepsUnused = 0; From dfc5fe05ce2861d2c4e6e79ed076398ae26c99c4 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 5 Dec 2019 16:02:20 -0800 Subject: [PATCH 10/44] Fixed so that when growing, any bonus food is used to fill empty food bars that are added. This prevents building up an unnaturally huge food bonus when growing. Fixes #440. Similar to pull request #461 --- server/server.cpp | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index 92816ce28..f57004d25 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -837,6 +837,10 @@ typedef struct LiveObject { // these are used first before food is decremented int yummyBonusStore; + // last time we told player their capacity in a food update + // what did we tell them? + int lastReportedFoodCapacity; + ClothingSet clothing; @@ -7409,6 +7413,8 @@ int processLoggedInPlayer( char inAllowReconnect, newObject.yummyBonusStore = 0; + newObject.lastReportedFoodCapacity = 0; + newObject.clothing = getEmptyClothingSet(); for( int c=0; cfoodStore += eatBonus; - checkForFoodEatingEmot( nextPlayer, - targetObj->id ); - - int cap = - computeFoodCapacity( nextPlayer ); + int cap = + nextPlayer->lastReportedFoodCapacity; if( nextPlayer->foodStore > cap ) { @@ -18714,7 +18717,14 @@ int main() { ObjectRecord *obj = getObject( nextPlayer->holdingID ); - int cap = computeFoodCapacity( targetPlayer ); + // don't use "live" computed capacity here + // because that will allow player to spam + // click to pack in food between food + // decrements when they are growing + // instead, stick to the food cap shown + // in the client (what we last reported + // to them) + int cap = nextPlayer->lastReportedFoodCapacity; // first case: @@ -23900,6 +23910,27 @@ int main() { nextPlayer->foodStore = cap; } + if( cap > nextPlayer->lastReportedFoodCapacity ) { + + // stomach grew + + // fill empty space from bonus store automatically + int extraCap = + cap - nextPlayer->lastReportedFoodCapacity; + + while( nextPlayer->yummyBonusStore > 0 && + extraCap > 0 && + nextPlayer->foodStore < cap ) { + nextPlayer->foodStore ++; + extraCap --; + nextPlayer->yummyBonusStore--; + } + } + + + nextPlayer->lastReportedFoodCapacity = cap; + + int yumMult = nextPlayer->yummyFoodChain.size() - 1; if( yumMult < 0 ) { From f98b5b028fd56b45cf6b97081b7c5e534728da95 Mon Sep 17 00:00:00 2001 From: Alec Yawata Date: Sat, 7 Dec 2019 23:45:39 +0000 Subject: [PATCH 11/44] No longer over feeding. Fixes #466 --- server/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.cpp b/server/server.cpp index f57004d25..2ae8a3ab3 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -18724,7 +18724,7 @@ int main() { // instead, stick to the food cap shown // in the client (what we last reported // to them) - int cap = nextPlayer->lastReportedFoodCapacity; + int cap = targetPlayer->lastReportedFoodCapacity; // first case: From 1e19b23965c51dca73c16e08b1aa5aa2b8199209 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 16 Dec 2019 15:19:17 -0800 Subject: [PATCH 12/44] Fixed so that we don't burn lives when reconnecting, even if server sees us as still connected when we reconnect. Fixes #443 --- server/server.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/server.cpp b/server/server.cpp index 2ae8a3ab3..5138c1096 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -13624,12 +13624,14 @@ int main() { nextConnection->ticketServerAccepted && ! nextConnection->lifeTokenSpent ) { + // this "butDisconnected" state applies even if + // we see them as connected, becasue they are clearly + // reconnecting now char liveButDisconnected = false; for( int p=0; perror && - ! o->connected && strcmp( o->email, nextConnection->email ) == 0 ) { liveButDisconnected = true; From cf76b42f142b63a0ef3758d67c3fadc990059d30 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 16 Dec 2019 17:01:30 -0800 Subject: [PATCH 13/44] Fixed so that when contents of a held container go through transition, the generic pickup sound is correctly played (was playing container creation sound by accident). Fixes #431 --- gameSource/LivingLifePage.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index a2725aeef..39bb74ccf 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -16811,7 +16811,8 @@ void LivingLifePage::step() { getObject( existing->holdingID ); - if( oldHeld > 0 && + if( oldHeld > 0 && + oldHeld != existing->holdingID && heldTransitionSourceID == -1 ) { // held object auto-decayed from // some other object @@ -16877,7 +16878,8 @@ void LivingLifePage::step() { } - if( ( ! otherSoundPlayed || + if( oldHeld != existing->holdingID && + ( ! otherSoundPlayed || heldObj->creationSoundForce ) && ! clothingChanged && From fa81d5a48793a95f94280c25c875a700749b5c71 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Tue, 5 Nov 2019 15:36:53 -0800 Subject: [PATCH 14/44] Finally fixed main cause of moon-walking glitch. Fixes #309 --- gameSource/LivingLifePage.cpp | 117 ++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 27 deletions(-) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index 39bb74ccf..d0b08eb09 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -22148,6 +22148,74 @@ char LivingLifePage::getCellBlocksWalking( int inMapX, int inMapY ) { + +static int savedXD = 0; +static int savedYD = 0; +static char savedInMotion = false; +static GridPos *savedPathToDest = NULL; +static int savedPathLength = 0; +static int savedCurrentPathStep = 0; +static char savedOnFinalPathStep = false; +static int savedNumFramesOnCurrentStep = 0; +static char savedDestTruncated = false; +static doublePair savedCurrentMoveDirection = { 0, 0 }; + + +// saves path +// restore or free calls must be used to free memory +static void savePlayerPath( LiveObject *inObject ) { + + if( inObject->pathToDest != NULL ) { + savedXD = inObject->xd; + savedYD = inObject->yd; + savedInMotion = inObject->inMotion; + + savedPathLength = inObject->pathLength; + savedPathToDest = new GridPos[ savedPathLength ]; + + memcpy( savedPathToDest, inObject->pathToDest, + sizeof( GridPos ) * inObject->pathLength ); + savedCurrentPathStep = inObject->currentPathStep; + savedOnFinalPathStep = inObject->onFinalPathStep; + savedNumFramesOnCurrentStep = inObject->numFramesOnCurrentStep; + savedDestTruncated = inObject->destTruncated; + savedCurrentMoveDirection = inObject->currentMoveDirection; + } + } + + +static void restoreSavedPath( LiveObject *inObject ) { + + if( inObject->pathToDest != NULL ) { + delete [] inObject->pathToDest; + } + + inObject->xd = savedXD; + inObject->yd = savedYD; + inObject->inMotion = savedInMotion; + inObject->pathToDest = savedPathToDest; + inObject->pathLength = savedPathLength; + inObject->currentPathStep = savedCurrentPathStep; + inObject->onFinalPathStep = savedOnFinalPathStep; + inObject->numFramesOnCurrentStep = savedNumFramesOnCurrentStep; + inObject->destTruncated = savedDestTruncated; + inObject->currentMoveDirection = savedCurrentMoveDirection; + } + + +static void freeSavedPath() { + if( savedPathToDest != NULL ) { + delete [] savedPathToDest; + savedPathToDest = NULL; + } + } + + + + + + + void LivingLifePage::pointerDown( float inX, float inY ) { int mouseButton = getLastMouseButton(); @@ -23211,6 +23279,10 @@ void LivingLifePage::pointerDown( float inX, float inY ) { int closestDist = 9999999; char oldPathExists = ( ourLiveObject->pathToDest != NULL ); + + if( oldPathExists ) { + savePlayerPath( ourLiveObject ); + } // don't consider dest spot itself generally int nStart = 1; @@ -23355,8 +23427,7 @@ void LivingLifePage::pointerDown( float inX, float inY ) { if( oldPathExists ) { - // restore it - computePathToDest( ourLiveObject ); + restoreSavedPath( ourLiveObject ); } if( foundEmpty ) { @@ -23655,7 +23726,15 @@ void LivingLifePage::pointerDown( float inX, float inY ) { if( mustMove ) { + + char oldPathExists = ( ourLiveObject->pathToDest != NULL ); + if( oldPathExists ) { + savePlayerPath( ourLiveObject ); + } + + + int oldXD = ourLiveObject->xd; int oldYD = ourLiveObject->yd; @@ -23663,21 +23742,11 @@ void LivingLifePage::pointerDown( float inX, float inY ) { ourLiveObject->yd = moveDestY; ourLiveObject->destTruncated = false; - ourLiveObject->inMotion = true; - GridPos *oldPathToDest = NULL; - int oldPathLength = 0; - int oldCurrentPathStep = 0; - if( ourLiveObject->pathToDest != NULL ) { - oldPathLength = ourLiveObject->pathLength; - oldPathToDest = new GridPos[ oldPathLength ]; + ourLiveObject->inMotion = true; - memcpy( oldPathToDest, ourLiveObject->pathToDest, - sizeof( GridPos ) * ourLiveObject->pathLength ); - oldCurrentPathStep = ourLiveObject->currentPathStep; - } computePathToDest( ourLiveObject ); @@ -23692,14 +23761,9 @@ void LivingLifePage::pointerDown( float inX, float inY ) { if( ourLiveObject->xd == oldXD && ourLiveObject->yd == oldYD ) { // completely blocked in, no path at all toward dest - if( oldPathToDest != NULL ) { - // restore it - ourLiveObject->pathToDest = oldPathToDest; - ourLiveObject->pathLength = oldPathLength; - ourLiveObject->currentPathStep = oldCurrentPathStep; - oldPathToDest = NULL; + if( oldPathExists ) { + restoreSavedPath( ourLiveObject ); } - // ignore click @@ -23708,13 +23772,13 @@ void LivingLifePage::pointerDown( float inX, float inY ) { delete [] nextActionMessageToSend; nextActionMessageToSend = NULL; } - ourLiveObject->inMotion = false; + return; } - if( oldPathToDest != NULL ) { - delete [] oldPathToDest; - oldPathToDest = NULL; + if( oldPathExists ) { + freeSavedPath(); + oldPathExists = false; } @@ -23804,9 +23868,8 @@ void LivingLifePage::pointerDown( float inX, float inY ) { } - if( oldPathToDest != NULL ) { - delete [] oldPathToDest; - oldPathToDest = NULL; + if( oldPathExists ) { + freeSavedPath(); } if( drunkEmotionIndex != -1 && From 2e10cf25bce9b1e66711ac799eebe3523c752f32 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Tue, 31 Dec 2019 12:22:15 -0800 Subject: [PATCH 15/44] Fixed another possible cause of the bouncing forever bug (wild bug): don't ever set inMotion to true unless we actually send a MOVE message to the server. --- gameSource/LivingLifePage.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index d0b08eb09..9789dca1e 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -23745,8 +23745,6 @@ void LivingLifePage::pointerDown( float inX, float inY ) { - ourLiveObject->inMotion = true; - computePathToDest( ourLiveObject ); @@ -23920,6 +23918,10 @@ void LivingLifePage::pointerDown( float inX, float inY ) { // start moving before we hear back from server + + ourLiveObject->inMotion = true; + + double floorSpeedMod = computePathSpeedMod( ourLiveObject, From d03ca0c035d603dc624695ab6debf98aedb4183d Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 3 Jan 2020 11:52:37 -0800 Subject: [PATCH 16/44] Fixed so that murder victims that die of starvation before dying from their wound are still logged as murdered in lifeLog. Fixes #483 --- server/server.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index 5138c1096..37ed42509 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -20330,7 +20330,9 @@ int main() { male, dropPos.x, dropPos.y, players.size() - 1, - disconnect ); + disconnect, + nextPlayer->murderPerpID, + nextPlayer->murderPerpEmail ); if( shutdownMode ) { handleShutdownDeath( @@ -21427,7 +21429,9 @@ int main() { ! getFemale( decrementedPlayer ), deathPos.x, deathPos.y, players.size() - 1, - false ); + false, + nextPlayer->murderPerpID, + nextPlayer->murderPerpEmail ); } if( shutdownMode && From 814c1d086ecc35ec1621b0314ac808d18c91ccd5 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Mon, 13 Jan 2020 09:30:36 -0800 Subject: [PATCH 17/44] No longer playing eating animation when sticking food in clothing container. Fixes #490 --- gameSource/LivingLifePage.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index 9789dca1e..6c79f7c8e 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -22685,6 +22685,15 @@ void LivingLifePage::pointerDown( float inX, float inY ) { if( ourLiveObject->holdingID > 0 && getObject( ourLiveObject->holdingID )->foodValue > 0 ) { nextActionEating = true; + + if( p.hitClothingIndex >= 0 && + clothingByIndex( ourLiveObject->clothing, + p.hitClothingIndex )->numSlots > 0 ) { + // clicked on container clothing + // server interprets this as an insert request, not + // an eat request + nextActionEating = false; + } } nextActionMessageToSend = From 3e97220bfe9e74c7de51b0370504326f40da33bf Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 29 Jan 2020 14:08:13 -0800 Subject: [PATCH 18/44] Fixed case of usingSound for target not playing if actor object also has uses. --- gameSource/LivingLifePage.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index 6c79f7c8e..7f5e78324 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -17107,7 +17107,11 @@ void LivingLifePage::step() { heldTransitionSourceID ); if( tr != NULL && - tr->newActor == existing->holdingID && + ( tr->newActor == existing->holdingID + || + bothSameUseParent( tr->newActor, + existing->holdingID ) ) + && tr->target == heldTransitionSourceID && ( tr->newTarget == tr->target || From 10bbeab3443429c3d39744c3cbfcbd2617aa89b8 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 26 Feb 2020 10:55:32 -0800 Subject: [PATCH 19/44] Fixed potential server-side crash in atoi by using safer strtol instead. --- server/server.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index 37ed42509..2786fec51 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -2158,6 +2158,13 @@ typedef struct ClientMessage { static int pathDeltaMax = 16; + +static int stringToInt( char *inString ) { + return strtol( inString, NULL, 10 ); + } + + + // if extraPos present in result, destroyed by caller // inMessage may be modified by this call ClientMessage parseMessage( LiveObject *inPlayer, char *inMessage ) { @@ -2207,11 +2214,11 @@ ClientMessage parseMessage( LiveObject *inPlayer, char *inMessage ) { } break; case 1: - m.x = atoi( &( inMessage[i] ) ); + m.x = stringToInt( &( inMessage[i] ) ); numRead++; break; case 2: - m.y = atoi( &( inMessage[i] ) ); + m.y = stringToInt( &( inMessage[i] ) ); numRead++; break; } @@ -2275,7 +2282,8 @@ ClientMessage parseMessage( LiveObject *inPlayer, char *inMessage ) { if( atPos != NULL ) { // skip @ symbol in token and parse int - m.sequenceNumber = atoi( &( tokens->getElementDirect( 3 )[1] ) ); + m.sequenceNumber = + stringToInt( &( tokens->getElementDirect( 3 )[1] ) ); } int numTokens = tokens->size(); @@ -2290,12 +2298,12 @@ ClientMessage parseMessage( LiveObject *inPlayer, char *inMessage ) { char *yToken = tokens->getElementDirect( offset + e * 2 + 1 ); // profiler found sscanf is a bottleneck here - // try atoi instead + // try atoi (stringToInt) instead //sscanf( xToken, "%d", &( m.extraPos[e].x ) ); //sscanf( yToken, "%d", &( m.extraPos[e].y ) ); - m.extraPos[e].x = atoi( xToken ); - m.extraPos[e].y = atoi( yToken ); + m.extraPos[e].x = stringToInt( xToken ); + m.extraPos[e].y = stringToInt( yToken ); if( abs( m.extraPos[e].x ) > pathDeltaMax || From 66c6ce4cce79b48eb6d4325e4e8e90f83dcbc566 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 26 Feb 2020 11:52:43 -0800 Subject: [PATCH 20/44] Fixed server-side crash when VOGM coordinates out of bounds. --- server/map.cpp | 17 ++++++++++++++++- server/server.cpp | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/server/map.cpp b/server/map.cpp index 7d86ab955..bff3ca82e 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -6703,7 +6703,22 @@ unsigned char *getChunkMessage( int inStartX, int inStartY, int endY = inStartY + inHeight; int endX = inStartX + inWidth; - + + if( endY < inStartY ) { + // wrapped around in integer space + // pull inStartY back from edge + inStartY -= inHeight; + endY = inStartY + inHeight; + } + if( endX < inStartX ) { + // wrapped around in integer space + // pull inStartY back from edge + inStartX -= inWidth; + endX = inStartX + inWidth; + } + + + timeSec_t curTime = MAP_TIMESEC; // look at four corners of chunk whenever we fetch one diff --git a/server/server.cpp b/server/server.cpp index 2786fec51..f58c661de 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -4395,6 +4395,12 @@ int sendMapChunkMessage( LiveObject *inO, // remove top of bar horBarH = lastY - yd; } + + if( horBarH > chunkDimensionY ) { + // don't allow bar to grow too big if we have a huge jump + // like from VOG mode + horBarH = chunkDimensionY; + } int vertBarStartX = fullStartX; @@ -4412,6 +4418,14 @@ int sendMapChunkMessage( LiveObject *inO, vertBarW = lastX - xd; } + + if( vertBarW > chunkDimensionX ) { + // don't allow bar to grow too big if we have a huge jump + // like from VOG mode + vertBarW = chunkDimensionX; + } + + // now trim vert bar where it intersects with hor bar if( yd > lastY ) { // remove top of vert bar From 8463a6c586dae196f08b2d4d6361a50d94addd2f Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 27 Feb 2020 17:32:19 -0800 Subject: [PATCH 21/44] Send food update immediately after reconnecting. Fixes #547 --- server/server.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/server.cpp b/server/server.cpp index f58c661de..4ade12889 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -6928,6 +6928,8 @@ int processLoggedInPlayer( char inAllowReconnect, o->firstMapSent = false; o->firstMessageSent = false; o->inFlight = false; + + o->foodUpdate = true; o->connected = true; o->cravingKnown = false; From 417b3c47e82f3266ed4d0213e1a1a24fedabbfdf Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 28 Feb 2020 11:48:04 -0800 Subject: [PATCH 22/44] Added support for same-color verification when checking for sprite-subset for single-sprite objects. This allows dyed objects to count as NOT the same object for initial-only creation sounds. --- gameSource/objectBank.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gameSource/objectBank.cpp b/gameSource/objectBank.cpp index fe84f53b7..a2beb72fb 100644 --- a/gameSource/objectBank.cpp +++ b/gameSource/objectBank.cpp @@ -5893,7 +5893,12 @@ char isSpriteSubset( int inSuperObjectID, int inSubObjectID, for( int ss=0; ssnumSprites; ss++ ) { if( superO->sprites[ ss ] == spriteID ) { - return true; + + // do make sure that color matches too + if( equal( superO->spriteColor[ ss ], + subO->spriteColor[ 0 ] ) ) { + return true; + } } } // if our sub-obj's single sprite does not occur, From 1447880a310756117af8c28af117a162186d85ea Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 12 Mar 2020 11:26:41 -0700 Subject: [PATCH 23/44] Fixed baby bones (SIDS) grave identity tracking. Fixes #559 --- server/server.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index 4ade12889..9421caff7 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -15209,10 +15209,6 @@ int main() { gravePos.x, gravePos.y, nextPlayer->id ); - setHeldGraveOrigin( adult, - gravePos.x, - gravePos.y, - 0 ); playerIndicesToSendUpdatesAbout.push_back( getLiveObjectIndex( holdingAdultID ) ); @@ -15269,6 +15265,12 @@ int main() { // in their hands adult->holdingID = babyBonesID; + setHeldGraveOrigin( adult, + gravePos.x, + gravePos.y, + 0 ); + + // this works to force client to play // creation sound for baby bones. adult->heldTransitionSourceID = From 15c8faf368ed4b428cdec320c8d915be50f23bad Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 12 Mar 2020 14:38:13 -0700 Subject: [PATCH 24/44] Phantom baby position (for held baby) no longer counted when looking for closest player (like for bear to chase). Fixes #564 --- server/server.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/server.cpp b/server/server.cpp index 9421caff7..bb5daf1e7 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -4039,6 +4039,9 @@ GridPos getClosestPlayerPos( int inX, int inY ) { if( o->error ) { continue; } + if( o->heldByOther ) { + continue; + } GridPos p; From 65a1e52bc1dacaee76bbfc8c5ea31cdfe3085243 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 19 Mar 2020 08:58:33 -0700 Subject: [PATCH 25/44] Fixed glitch with swapping a sub-container into a super-container that is already filled with identical sub-containers (before, you could store a hidden extra sub-container in there). Fixes #572 --- server/server.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/server.cpp b/server/server.cpp index bb5daf1e7..573e6d167 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -9067,6 +9067,12 @@ static char addHeldToContainer( LiveObject *inPlayer, idToAdd = r->newTarget; } + + if( inPlayer->numContained > 0 ) { + // negative to indicate sub-container + idToAdd *= -1; + } + int swapInd = getContainerSwapIndex ( inPlayer, idToAdd, true, From 4f445dbcd48bce49ae24e96938c958c29b55eee4 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 26 Mar 2020 11:52:54 -0700 Subject: [PATCH 26/44] Fixed bug in way held object was being set after SELF action to transform clothing (eta decay for held wasn't being set). Fixed to handle instant-decay (1-second auto-decay) when processing SELF action to use object on clothing. --- server/server.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index 573e6d167..c79328aa5 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -18800,6 +18800,31 @@ int main() { isContainmentTransition = true; } + if( clickedClothingTrans == NULL ) { + // check if held has instant-decay + TransRecord *heldDecay = + getPTrans( + -1, + nextPlayer->holdingID ); + if( heldDecay != NULL && + heldDecay->autoDecaySeconds + == 1 && + heldDecay->newTarget > 0 ) { + + // force decay NOW and try again + handleHeldDecay( + nextPlayer, + i, + &playerIndicesToSendUpdatesAbout, + &playerIndicesToSendHealingAbout ); + clickedClothingTrans = + getPTrans( + nextPlayer->holdingID, + clickedClothing->id ); + } + } + + if( clickedClothingTrans != NULL ) { int na = clickedClothingTrans->newActor; @@ -19200,9 +19225,6 @@ int main() { // now. Works for removing sword // from backpack - nextPlayer->holdingID = - bareHandClothingTrans->newActor; - handleHoldingChange( nextPlayer, bareHandClothingTrans->newActor ); From acdc886d166bc97af7c140a2197022adfd655a5e Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 27 Mar 2020 15:11:55 -0700 Subject: [PATCH 27/44] printTrans now includes info about probabilistic actor and target changes. --- gameSource/transitionBank.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gameSource/transitionBank.cpp b/gameSource/transitionBank.cpp index e3ff374f7..66efeb267 100644 --- a/gameSource/transitionBank.cpp +++ b/gameSource/transitionBank.cpp @@ -3052,6 +3052,19 @@ void printTrans( TransRecord *inTrans ) { printf( " (move=%s,dist=%d)", moveName, inTrans->desiredMoveDist ); } + if( inTrans->actorChangeChance < 1.0 ) { + printf( " (pA=%0.2f,[%s])", + inTrans->actorChangeChance, + getObjName( inTrans->newActorNoChange ) ); + } + + if( inTrans->targetChangeChance < 1.0 ) { + printf( " (pT=%0.2f,[%s])", + inTrans->targetChangeChance, + getObjName( inTrans->newTargetNoChange ) ); + } + + printf( "\n" ); } From 5cbf96ad71d1fa75d229bfd1aaa7b0d751f9a897 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 27 Mar 2020 15:56:06 -0700 Subject: [PATCH 28/44] Support for transitions where lastUseActor AND lastUseTarget is flagged at same time. This has never been needed before, but was needed for mining pick used on mine, since both can be exhausted. --- gameSource/transitionBank.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/gameSource/transitionBank.cpp b/gameSource/transitionBank.cpp index 66efeb267..263ed65eb 100644 --- a/gameSource/transitionBank.cpp +++ b/gameSource/transitionBank.cpp @@ -1154,8 +1154,22 @@ void initTransBankFinish() { if( ! processed ) { if( tr->lastUseActor || tr->lastUseTarget ) { - - if( tr->lastUseActor && + + if( tr->lastUseActor && tr->lastUseTarget && + actor != NULL && actor->numUses > 1 && + target != NULL && target->numUses > 1 ) { + + // map last use of actor to newActor + if( ! tr->reverseUseActor ) { + newTrans.actor = actor->useDummyIDs[0]; + } + // map last use of target to newTarget + if( ! tr->reverseUseTarget ) { + newTrans.target = target->useDummyIDs[0]; + } + transToAdd.push_back( newTrans ); + } + else if( tr->lastUseActor && actor != NULL && actor->numUses > 1 ) { @@ -1193,7 +1207,7 @@ void initTransBankFinish() { } } } - if( tr->lastUseTarget && + else if( tr->lastUseTarget && target != NULL && target->numUses > 1 ) { From 75753b88f3cf87449664e734dee48c44081da105 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 27 Mar 2020 20:16:48 -0700 Subject: [PATCH 29/44] Object report can be run from different center coordinates, and has separate x and y range. --- server/map.cpp | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/server/map.cpp b/server/map.cpp index bff3ca82e..70675e5c3 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -1968,41 +1968,44 @@ void printBiomeSamples() { biomeSamples[i] / (double)numSamples ); } } - - - -void printObjectSamples() { + + + +int printObjectSamples( int inXCenter, int inYCenter ) { int objectToCount = 2285; JenkinsRandomSource sampleRandSource; int numSamples = 0; - - int range = 500; - + + int rangeX = 354; + int rangeY = 354; + int count = 0; - - for( int y=-range; y Date: Tue, 31 Mar 2020 11:05:59 -0700 Subject: [PATCH 30/44] Script for printing object creation times and locations based on logs. --- server/printObjectCreationLocations.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 server/printObjectCreationLocations.sh diff --git a/server/printObjectCreationLocations.sh b/server/printObjectCreationLocations.sh new file mode 100755 index 000000000..dcca5b86e --- /dev/null +++ b/server/printObjectCreationLocations.sh @@ -0,0 +1,21 @@ +if [ $# -ne 2 ] +then + echo "Usage:" + echo "./printObjectCreationLocations.sh mapChangeLogFile object_id" + exit +fi + + +startTime=`echo -n "$1" | sed -e "s/time_mapLog.txt//" | sed "s/.*\///" ` + +echo "startTime = $startTime" + + +while read time coord id user +do + timestamp=`echo "$startTime + $time" | bc` + + date=`date -d @$timestamp` + + echo "$coord || $date || $id " +done < <( cat $1 | sed -e "s/\([0-9.]* \)\([0-9\-]*\) \([0-9\-]*\) /\1(\2,\3) id=/" | grep "id=$2" ) \ No newline at end of file From 06f86bb9a0d3db6c9390321843b623f5157dd02f Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 1 Apr 2020 09:57:51 -0700 Subject: [PATCH 31/44] Script for printing Eve spawn locations on a given day (non-tutorial locations). --- server/printEveSpawns.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 server/printEveSpawns.sh diff --git a/server/printEveSpawns.sh b/server/printEveSpawns.sh new file mode 100755 index 000000000..62b990b19 --- /dev/null +++ b/server/printEveSpawns.sh @@ -0,0 +1,18 @@ + +if [ $# -ne 1 ] +then + echo "Usage:" + echo "./printEveSpawns.sh lifeLogFile" + exit +fi + + + + +while read b time coord +do + + date=`date -d @$time` + + echo "$date || $coord " +done < <( grep noParent $1 | grep -v ",-20" | grep " F " | sed -e "s/\(B [0-9]* \).* F /\1/" | sed "s/ noParent.*//" ) \ No newline at end of file From 418f6ba0d5cc78fb55ce4d01ca606b48818884b8 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 1 Apr 2020 10:02:21 -0700 Subject: [PATCH 32/44] Fixed to discard +20K tutorial positions. --- server/printEveSpawns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/printEveSpawns.sh b/server/printEveSpawns.sh index 62b990b19..04688029b 100755 --- a/server/printEveSpawns.sh +++ b/server/printEveSpawns.sh @@ -15,4 +15,4 @@ do date=`date -d @$time` echo "$date || $coord " -done < <( grep noParent $1 | grep -v ",-20" | grep " F " | sed -e "s/\(B [0-9]* \).* F /\1/" | sed "s/ noParent.*//" ) \ No newline at end of file +done < <( grep noParent $1 | grep -v ",-20" | grep -v ",20" | grep " F " | sed -e "s/\(B [0-9]* \).* F /\1/" | sed "s/ noParent.*//" ) \ No newline at end of file From 51c421867f49d197ff89ae7965585ac73fa15197 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 1 Apr 2020 14:51:04 -0700 Subject: [PATCH 33/44] Chasing (and fleeing) animals now react to nearby players as far as 10 away (was 7). --- server/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/map.cpp b/server/map.cpp index 70675e5c3..796c58b55 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -5205,8 +5205,8 @@ int checkDecayObject( int inX, int inY, int inID ) { double dY = (double)p.y - (double)inY; double dist = sqrt( dX * dX + dY * dY ); - - if( dist <= 7 && + + if( dist <= 10 && ( p.x != 0 || p.y != 0 ) ) { if( t->move == 1 && dist <= desiredMoveDist ) { From 8345781ffdb0e9d2a2bdf6cff4a56f75b38a3430 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 23 Jul 2020 10:26:10 -0700 Subject: [PATCH 34/44] Fixed endless looping behavior if custom server address includes a bad hostname that gets looked up as invalid instantly. Fixes #662 --- gameSource/LivingLifePage.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index 7f5e78324..b251c87b3 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -1022,6 +1022,7 @@ static void replaceLastMessageSent( char *inNewMessage ) { SimpleVector serverSocketBuffer; static char serverSocketConnected = false; +static char serverSocketHardFail = false; static float connectionMessageFade = 1.0f; static double connectedTime = 0; @@ -12228,17 +12229,42 @@ void LivingLifePage::step() { mouseDownFrames++; } + double pageLifeTime = game_getCurrentTime() - mPageStartTime; + if( mServerSocket == -1 ) { serverSocketConnected = false; connectionMessageFade = 1.0f; - mServerSocket = openSocketConnection( serverIP, serverPort ); - timeLastMessageSent = game_getCurrentTime(); + + // don't keep looping to reconnect on instant hard-fail + if( ! serverSocketHardFail ) { + mServerSocket = openSocketConnection( serverIP, serverPort ); + timeLastMessageSent = game_getCurrentTime(); + + if( mServerSocket == -1 ) { + // instant hard-fail, probably from bad hostname that + // gets looked up right away. + serverSocketHardFail = true; + } + } + + + if( mServerSocket == -1 ) { + // hard fail condition + + if( pageLifeTime >= 1 ) { + // they have seen "CONNECTING" long enough + + setWaiting( false ); + setSignal( "connectionFailed" ); + } + } + return; } - double pageLifeTime = game_getCurrentTime() - mPageStartTime; + if( pageLifeTime < 1 ) { // let them see CONNECTING message for a bit @@ -21114,6 +21140,7 @@ void LivingLifePage::makeActive( char inFresh ) { waitForFrameMessages = false; serverSocketConnected = false; + serverSocketHardFail = false; connectionMessageFade = 1.0f; connectedTime = 0; From 2bd571c339b5deffbf880ff54282def9e534d573 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Wed, 28 Oct 2020 20:18:23 -0400 Subject: [PATCH 35/44] Fixed undefined value error. --- server/server.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index c79328aa5..ea7888f6e 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -7428,9 +7428,8 @@ int processLoggedInPlayer( char inAllowReconnect, newObject.isIndoors = false; - newObject.foodDecrementETASeconds = - currentTime + - computeFoodDecrementTimeSeconds( &newObject ); + + newObject.foodUpdate = true; newObject.lastAteID = 0; @@ -8187,6 +8186,11 @@ int processLoggedInPlayer( char inAllowReconnect, } } + newObject.foodDecrementETASeconds = + currentTime + + computeFoodDecrementTimeSeconds( &newObject ); + + if( forceSpawn ) { newObject.forceSpawn = true; newObject.xs = forceSpawnInfo.pos.x; From 168fe9da070ff8cd337778bdcc7e57a7c281f999 Mon Sep 17 00:00:00 2001 From: risvh <67486979+risvh@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:03:13 +0000 Subject: [PATCH 36/44] Partially cherry picking 8bf4eaa74 https://github.com/jasonrohrer/OneLife/commit/8bf4eaa74 --- server/server.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index ea7888f6e..7f8943448 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -1041,6 +1041,12 @@ char isKnownOwned( LiveObject *inPlayer, GridPos inPos ) { return isKnownOwned( inPlayer, inPos.x, inPos.y ); } + + +void sendGlobalMessage( char *inMessage, + LiveObject *inOnePlayerOnly = NULL ); + + void sendMessageToPlayer( LiveObject *inPlayer, char *inMessage, int inLength ); @@ -4132,8 +4138,8 @@ static void setPlayerDisconnected( LiveObject *inPlayer, // if inOnePlayerOnly set, we only send to that player -static void sendGlobalMessage( char *inMessage, - LiveObject *inOnePlayerOnly = NULL ) { +void sendGlobalMessage( char *inMessage, + LiveObject *inOnePlayerOnly ) { char found; char *noSpaceMessage = replaceAll( inMessage, " ", "_", &found ); From d2245b879a7a6002ea862846785669f2cec43724 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Thu, 17 Dec 2020 18:51:46 -0500 Subject: [PATCH 37/44] If multiple DING messages would be sent to client at same time, making them pass by instantly and be unreadable, the server queues them up instead and sends one to the client every 7 seconds. Fixes #723 --- server/server.cpp | 66 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index 7f8943448..b82558e90 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -925,6 +925,14 @@ typedef struct LiveObject { GridPos forceFlightDest; double forceFlightDestSetTime; + + // don't send global messages too quickly + // give player chance to read each one + double lastGlobalMessageTime; + + SimpleVector globalMessageQueue; + + } LiveObject; @@ -1042,6 +1050,10 @@ char isKnownOwned( LiveObject *inPlayer, GridPos inPos ) { } +// messages with no follow-up hang out on client for 10 seconds +// 7 seconds should be long enough to read if there's a follow-up waiting +static double minGlobalMessageSpacingSeconds = 7; + void sendGlobalMessage( char *inMessage, LiveObject *inOnePlayerOnly = NULL ); @@ -1760,7 +1772,9 @@ void quitCleanup() { delete [] nextPlayer->murderPerpEmail; } - + nextPlayer->globalMessageQueue.deallocateStringElements(); + + freePlayerContainedArrays( nextPlayer ); @@ -4140,6 +4154,9 @@ static void setPlayerDisconnected( LiveObject *inPlayer, // if inOnePlayerOnly set, we only send to that player void sendGlobalMessage( char *inMessage, LiveObject *inOnePlayerOnly ) { + + double curTime = Time::getCurrentTime(); + char found; char *noSpaceMessage = replaceAll( inMessage, " ", "_", &found ); @@ -4157,13 +4174,26 @@ void sendGlobalMessage( char *inMessage, } if( ! o->error && ! o->isTutorial && o->connected ) { - int numSent = - o->sock->send( (unsigned char*)fullMessage, - len, - false, false ); - - if( numSent != len ) { - setPlayerDisconnected( o, "Socket write failed" ); + + + if( curTime - o->lastGlobalMessageTime > + minGlobalMessageSpacingSeconds ) { + + int numSent = + o->sock->send( (unsigned char*)fullMessage, + len, + false, false ); + + o->lastGlobalMessageTime = curTime; + + if( numSent != len ) { + setPlayerDisconnected( o, "Socket write failed" ); + } + } + else { + // messages are coming too quickly for this player to read + // them, wait before sending this one + o->globalMessageQueue.push_back( stringDuplicate( inMessage ) ); } } } @@ -8234,6 +8264,9 @@ int processLoggedInPlayer( char inAllowReconnect, } + newObject.lastGlobalMessageTime = 0; + + newObject.birthPos.x = newObject.xd; newObject.birthPos.y = newObject.yd; @@ -13206,6 +13239,21 @@ int main() { lowestCravingID = nextPlayer->cravingFood.uniqueID; } + + // also send queued global messages + if( nextPlayer->globalMessageQueue.size() > 0 && + curStepTime - nextPlayer->lastGlobalMessageTime > + minGlobalMessageSpacingSeconds ) { + + // send next one + char *message = + nextPlayer->globalMessageQueue.getElementDirect( 0 ); + nextPlayer->globalMessageQueue.deleteElement( 0 ); + + sendGlobalMessage( message, nextPlayer ); + + delete [] message; + } } purgeStaleCravings( lowestCravingID ); } @@ -24306,6 +24354,8 @@ int main() { delete [] nextPlayer->deathReason; } + nextPlayer->globalMessageQueue.deallocateStringElements(); + delete nextPlayer->babyBirthTimes; delete nextPlayer->babyIDs; From 7748bdf97b889a98017fe3ac5ba2fc118ce6ca90 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 18 Dec 2020 13:26:39 -0500 Subject: [PATCH 38/44] Server now keeps client connection open longer (10 seconds, was 5 seconds) after sending death message to client. This should reduce the chance that the connection is closed before the client receives and processes the message. Fixes #726 --- server/server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index b82558e90..d4bed3d1f 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -20254,9 +20254,9 @@ int main() { nextPlayer->isNew = false; nextPlayer->deleteSent = true; - // wait 5 seconds before closing their connection + // wait 10 seconds before closing their connection // so they can get the message - nextPlayer->deleteSentDoneETA = Time::getCurrentTime() + 5; + nextPlayer->deleteSentDoneETA = Time::getCurrentTime() + 10; if( areTriggersEnabled() ) { // add extra time so that rest of triggers can be received From 3cf6e806c089c5ea549ca305d01221548cbf1eb3 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Tue, 26 Oct 2021 22:59:07 -0400 Subject: [PATCH 39/44] Support for loading OGG files from sounds folder (along with AIFF files), to save data space on longer sounds, like snippets of music. --- gameSource/binFolderCache.cpp | 23 ++++++++++++++--- gameSource/binFolderCache.h | 2 ++ gameSource/makeFileListEditor | 1 + gameSource/ogg.cpp | 14 ++++++++++ gameSource/ogg.h | 5 ++++ gameSource/soundBank.cpp | 48 +++++++++++++++++++++++++++-------- 6 files changed, 79 insertions(+), 14 deletions(-) diff --git a/gameSource/binFolderCache.cpp b/gameSource/binFolderCache.cpp index 17a4db492..45d0c8490 100644 --- a/gameSource/binFolderCache.cpp +++ b/gameSource/binFolderCache.cpp @@ -163,18 +163,35 @@ BinFolderCache initBinFolderCache( const char *inFolderName, c.numFiles = numChildFiles; + int numPatternParts = 0; + char **patternParts = split( inPattern, "|", &numPatternParts ); + for( int i=0; igetFileName(); - if( strstr( name, inPattern ) != NULL ) { - c.dirFiles->push_back( childFiles[i] ); + char matchedPattern = false; + + for( int j=0; jpush_back( childFiles[i] ); + matchedPattern = true; + break; + } } - else { + + if( !matchedPattern ) { delete childFiles[i]; } delete [] name; } delete [] childFiles; + + + for( int j=0; jsize(); diff --git a/gameSource/binFolderCache.h b/gameSource/binFolderCache.h index c5e567827..cadac1d3e 100644 --- a/gameSource/binFolderCache.h +++ b/gameSource/binFolderCache.h @@ -15,6 +15,8 @@ typedef struct BinFolderCache { BinFolderCache initBinFolderCache( const char *inFolderName, // example: ".tga" + // multiple patterns can be separated + // by | like: ".aiff|.ogg" const char *inFilePattern, char *outRebuildingCache ); diff --git a/gameSource/makeFileListEditor b/gameSource/makeFileListEditor index 0394b1397..2768c8b3d 100644 --- a/gameSource/makeFileListEditor +++ b/gameSource/makeFileListEditor @@ -50,6 +50,7 @@ soundBank.cpp \ SoundWidget.cpp \ convolution.cpp \ fft.cpp \ +ogg.cpp \ zoomView.cpp \ categoryBank.cpp \ EditorCategoryPage.cpp \ diff --git a/gameSource/ogg.cpp b/gameSource/ogg.cpp index 00238ee4c..6efac41b3 100644 --- a/gameSource/ogg.cpp +++ b/gameSource/ogg.cpp @@ -61,6 +61,20 @@ int readNextSamplesOGG( OGGHandle inOGG, } + +void readAllMonoSamplesOGG( OGGHandle inOGG, + int16_t *inMonoBuffer ) { + stb_vorbis *v = (stb_vorbis*)inOGG; + + int16_t *buffers[1] = { inMonoBuffer }; + + + stb_vorbis_get_samples_short( v, 1, buffers, + getOGGTotalSamples( inOGG ) ); + } + + + char seekOGG( OGGHandle inOGG, int inNextSample ) { stb_vorbis *v = (stb_vorbis*)inOGG; diff --git a/gameSource/ogg.h b/gameSource/ogg.h index 6039ca7a9..7bc79d51d 100644 --- a/gameSource/ogg.h +++ b/gameSource/ogg.h @@ -28,6 +28,11 @@ int readNextSamplesOGG( OGGHandle inOGG, float *inLeftBuffer, float *inRightBuffer ); + +void readAllMonoSamplesOGG( OGGHandle inOGG, + int16_t *inMonoBuffer ); + + // seeks in the OGG char seekOGG( OGGHandle inOGG, int inNextSample ); diff --git a/gameSource/soundBank.cpp b/gameSource/soundBank.cpp index 5d8c75472..c1036f656 100644 --- a/gameSource/soundBank.cpp +++ b/gameSource/soundBank.cpp @@ -1,5 +1,6 @@ #include "soundBank.h" +#include "ogg.h" #include "objectBank.h" #include "animationBank.h" @@ -390,7 +391,8 @@ int initSoundBankStart( char *outRebuildingCache ) { char rebuildingSounds, rebuildingReverbs; - soundCache = initBinFolderCache( "sounds", ".aiff", &rebuildingSounds ); + soundCache = initBinFolderCache( "sounds", + ".aiff|.ogg", &rebuildingSounds ); reverbCache = initBinFolderCache( "reverbCache", ".aiff", &rebuildingReverbs ); @@ -462,6 +464,10 @@ int initSoundBankStart( char *outRebuildingCache ) { delete childFiles[i]; // skip all non-AIFF files + // note that we do NOT generate reverbs for OGG files, + // since those tend to be longer (snippets of music) + // and aren't positioned in the environment in the same + // way as one-hit sounds if( strstr( fileName, ".aiff" ) != NULL ) { int id = 0; @@ -509,8 +515,9 @@ float initSoundBankStep() { char *fileName = getFileName( soundCache, i ); - // skip all non-AIFF files - if( strstr( fileName, ".aiff" ) != NULL ) { + // skip all non-AIFF, non-OGG files + if( strstr( fileName, ".aiff" ) != NULL || + strstr( fileName, ".ogg" ) != NULL ) { char added = false; SoundRecord *r = new SoundRecord; @@ -525,18 +532,37 @@ float initSoundBankStep() { r->id = 0; - sscanf( fileName, "%d.aiff", &( r->id ) ); + sscanf( fileName, "%d.", &( r->id ) ); - int aiffDataLength; - unsigned char *aiffData = + int soundDataLength; + unsigned char *soundData = getFileContents( soundCache, i, - fileName, &aiffDataLength ); + fileName, &soundDataLength ); - if( aiffData != NULL ) { + if( soundData != NULL ) { int numSamples; - int16_t *samples = - readMono16AIFFData( aiffData, aiffDataLength, &numSamples ); + int16_t *samples; + + if( strstr( fileName, ".aiff" ) != NULL ) { + samples = + readMono16AIFFData( soundData, + soundDataLength, &numSamples ); + } + else if( strstr( fileName, ".ogg" ) != NULL ) { + OGGHandle o = openOGG( soundData, soundDataLength ); + + int numChan = getOGGChannels( o ); + if( numChan == 1 ) { + numSamples = getOGGTotalSamples( o ); + samples = new int16_t[ numSamples ]; + + readAllMonoSamplesOGG( o, samples ); + } + // skip non-mono OGG files + + closeOGG( o ); + } if( samples != NULL ) { @@ -552,7 +578,7 @@ float initSoundBankStep() { delete [] samples; } - delete [] aiffData; + delete [] soundData; } if( !added ) { From e44097e63ef61385fb88030d0e9a70acce8f92c9 Mon Sep 17 00:00:00 2001 From: Jason Rohrer Date: Fri, 12 May 2023 17:24:34 -0400 Subject: [PATCH 40/44] Fixed windows script for makeRegenerateCaches to handle ogg.cpp building. --- gameSource/makeRegenerateCachesWindows | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gameSource/makeRegenerateCachesWindows b/gameSource/makeRegenerateCachesWindows index d83baa28e..7d3f2048c 100644 --- a/gameSource/makeRegenerateCachesWindows +++ b/gameSource/makeRegenerateCachesWindows @@ -1 +1 @@ -g++ -g -o regenerateCaches -I../.. regenerateCaches.cpp spriteBank.cpp objectBank.cpp objectMetadata.cpp soundBank.cpp animationBank.cpp transitionBank.cpp categoryBank.cpp groundSprites.cpp folderCache.cpp binFolderCache.cpp ageControl.cpp convolution.cpp fft.cpp SoundUsage.cpp ../commonSource/fractalNoise.cpp ../../minorGems/util/SettingsManager.cpp ../../minorGems/crypto/hashes/sha1.cpp ../../minorGems/sound/formats/aiff.cpp ../../minorGems/util/stringUtils.cpp ../../minorGems/util/StringTree.cpp ../../minorGems/io/file/win32/PathWin32.cpp ../../minorGems/formats/encodingUtils.cpp ../../minorGems/io/file/win32/DirectoryWin32.cpp ../../minorGems/system/win32/TimeWin32.cpp ../../minorGems/game/doublePair.cpp ../../minorGems/io/win32/TypeIOWin32.cpp ../../minorGems/util/StringBufferOutputStream.cpp \ No newline at end of file +g++ -g -o regenerateCaches -I../.. regenerateCaches.cpp spriteBank.cpp objectBank.cpp objectMetadata.cpp soundBank.cpp animationBank.cpp transitionBank.cpp categoryBank.cpp groundSprites.cpp folderCache.cpp binFolderCache.cpp ageControl.cpp convolution.cpp fft.cpp ogg.cpp SoundUsage.cpp ../commonSource/fractalNoise.cpp ../../minorGems/util/SettingsManager.cpp ../../minorGems/crypto/hashes/sha1.cpp ../../minorGems/sound/formats/aiff.cpp ../../minorGems/util/stringUtils.cpp ../../minorGems/util/StringTree.cpp ../../minorGems/io/file/win32/PathWin32.cpp ../../minorGems/formats/encodingUtils.cpp ../../minorGems/io/file/win32/DirectoryWin32.cpp ../../minorGems/system/win32/TimeWin32.cpp ../../minorGems/game/doublePair.cpp ../../minorGems/io/win32/TypeIOWin32.cpp ../../minorGems/util/StringBufferOutputStream.cpp \ No newline at end of file From 42d81e6f5144558a14dc8e31729ed44a907544c6 Mon Sep 17 00:00:00 2001 From: risvh <67486979+risvh@users.noreply.github.com> Date: Wed, 31 Jan 2024 23:55:57 +0800 Subject: [PATCH 41/44] Some keyboard sends 97 instead of 1 on ctrl + A also refractored some of the code into the already existing function --- gameSource/LivingLifePage.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index b251c87b3..fb8a94310 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -2654,7 +2654,9 @@ void LivingLifePage::setOurSendPosXY(int &x, int &y) { bool LivingLifePage::isCharKey(unsigned char c, unsigned char key) { char tKey = key; - return (c == key || c == toupper(tKey)); + return (c == key || c == toupper(tKey) || + c+64 == toupper(tKey) // ctrl + key + ); } @@ -24140,57 +24142,57 @@ void LivingLifePage::keyDown( unsigned char inASCII ) { } if (!shiftKey && !commandKey) { - if (inASCII == charKey_Up || inASCII == toupper(charKey_Up)) { + if (isCharKey(inASCII, charKey_Up)) { upKeyDown = true; //stopAutoRoadRun = true; return; } - if (inASCII == charKey_Left || inASCII == toupper(charKey_Left)) { + if (isCharKey(inASCII, charKey_Left)) { leftKeyDown = true; //stopAutoRoadRun = true; return; } - if (inASCII == charKey_Down || inASCII == toupper(charKey_Down)) { + if (isCharKey(inASCII, charKey_Down)) { downKeyDown = true; //stopAutoRoadRun = true; return; } - if (inASCII == charKey_Right || inASCII == toupper(charKey_Right)) { + if (isCharKey(inASCII, charKey_Right)) { rightKeyDown = true; //stopAutoRoadRun = true; return; } } else if (commandKey) { - if (inASCII+64 == toupper(charKey_Up)) { + if (isCharKey(inASCII, charKey_Up)) { actionBetaRelativeToMe( 0, 1 ); return; } - if (inASCII+64 == toupper(charKey_Left)) { + if (isCharKey(inASCII, charKey_Left)) { actionBetaRelativeToMe( -1, 0 ); return; } - if (inASCII+64 == toupper(charKey_Down)) { + if (isCharKey(inASCII, charKey_Down)) { actionBetaRelativeToMe( 0, -1 ); return; } - if (inASCII+64 == toupper(charKey_Right)) { + if (isCharKey(inASCII, charKey_Right)) { actionBetaRelativeToMe( 1, 0 ); return; } } else if (shiftKey) { - if (inASCII == charKey_Up || inASCII == toupper(charKey_Up)) { + if (isCharKey(inASCII, charKey_Up)) { actionAlphaRelativeToMe( 0, 1 ); return; } - if (inASCII == charKey_Left || inASCII == toupper(charKey_Left)) { + if (isCharKey(inASCII, charKey_Left)) { actionAlphaRelativeToMe( -1, 0 ); return; } - if (inASCII == charKey_Down || inASCII == toupper(charKey_Down)) { + if (isCharKey(inASCII, charKey_Down)) { actionAlphaRelativeToMe( 0, -1 ); return; } - if (inASCII == charKey_Right || inASCII == toupper(charKey_Right)) { + if (isCharKey(inASCII, charKey_Right)) { actionAlphaRelativeToMe( 1, 0 ); return; } From 86c9d945c5e1f8252270448ccf9c4799be6de8ec Mon Sep 17 00:00:00 2001 From: risvh <67486979+risvh@users.noreply.github.com> Date: Thu, 1 Feb 2024 21:57:20 +0800 Subject: [PATCH 42/44] Allow tapout to happen at a specific relative coords, or up to a max number of objects --- gameSource/objectBank.cpp | 56 +++++++-------- gameSource/objectBank.h | 12 ++-- server/map.cpp | 141 +++++++++++++++++--------------------- 3 files changed, 93 insertions(+), 116 deletions(-) diff --git a/gameSource/objectBank.cpp b/gameSource/objectBank.cpp index a2beb72fb..5e7045bc2 100644 --- a/gameSource/objectBank.cpp +++ b/gameSource/objectBank.cpp @@ -624,34 +624,43 @@ static void setupTapout( ObjectRecord *inR ) { char *triggerPos = strstr( inR->description, "+tapoutTrigger" ); if( triggerPos != NULL ) { - int xGrid, yGrid; - int xLimit, yLimit; - int buildCountLimit = -1; - int postBuildLimitX = 0; - int postBuildLimitY = 0; + int xGrid = -1; + int yGrid = -1; + int xLimit = -1; + int yLimit = -1; + int tapoutCountLimit = -1; int numRead = sscanf( triggerPos, - "+tapoutTrigger,%d,%d,%d,%d," - "%d,%d,%d", + "+tapoutTrigger,%d,%d,%d,%d,%d", &xGrid, &yGrid, &xLimit, &yLimit, - &buildCountLimit, - &postBuildLimitX, - &postBuildLimitY ); - if( numRead == 4 || numRead == 7 ) { + &tapoutCountLimit ); + if( numRead == 2 || numRead == 4 || numRead == 5 ) { // valid tapout trigger TapoutRecord r; r.triggerID = inR->id; - r.gridSpacingX = xGrid; - r.gridSpacingY = yGrid; - r.limitX = xLimit; - r.limitY = yLimit; - r.buildCountLimit = buildCountLimit; - r.buildCount = 0; - r.postBuildLimitX = postBuildLimitX; - r.postBuildLimitY = postBuildLimitY; + r.gridSpacingX = -1; + r.gridSpacingY = -1; + r.limitX = -1; + r.limitY = -1; + r.tapoutCountLimit = -1; + r.specificX = 9999; + r.specificY = 9999; + + if( numRead == 2 ) { + r.specificX = xGrid; + r.specificY = yGrid; + } + else if( numRead == 4 || numRead == 5 ) { + r.gridSpacingX = xGrid; + r.gridSpacingY = yGrid; + r.limitX = xLimit; + r.limitY = yLimit; + if( numRead == 5 ) + r.tapoutCountLimit = tapoutCountLimit; + } tapoutRecords.push_back( r ); @@ -6236,13 +6245,4 @@ TapoutRecord *getTapoutRecord( int inObjectID ) { } } return NULL; - } - - - -void clearTapoutCounts() { - for( int i=0; ibuildCount = 0; - } } \ No newline at end of file diff --git a/gameSource/objectBank.h b/gameSource/objectBank.h index c1903b26c..15bb0f5ba 100644 --- a/gameSource/objectBank.h +++ b/gameSource/objectBank.h @@ -29,11 +29,10 @@ typedef struct TapoutRecord { int gridSpacingX, gridSpacingY; // how far to reach in +/- x and y when tapping out int limitX, limitY; - int buildCount; - int buildCountLimit; - // how far to reach in +/- x and y when tapping out - // after build count limit reached - int postBuildLimitX, postBuildLimitY; + // 2HOL - can set the max number of objects to be tapped out by one operation + int tapoutCountLimit; + // 2HOL - can specify coordinates to tap out + int specificX, specificY; } TapoutRecord; @@ -944,8 +943,5 @@ char canPickup( int inObjectID, double inPlayerAge ); TapoutRecord *getTapoutRecord( int inObjectID ); -void clearTapoutCounts(); - - #endif \ No newline at end of file diff --git a/server/map.cpp b/server/map.cpp index 796c58b55..2820ad9fa 100644 --- a/server/map.cpp +++ b/server/map.cpp @@ -7080,15 +7080,34 @@ static int applyTapoutGradientRotate( int inX, int inY, -// returns true if tapout-triggered a +primaryHomeland object -static char runTapoutOperation( int inX, int inY, - int inRadiusX, int inRadiusY, - int inSpacingX, int inSpacingY, - int inTriggerID, - char inPlayerHasPrimaryHomeland, - char inIsPost = false ) { - - char returnVal = false; +static void runTapoutOperation( int inX, int inY, + TapoutRecord *inR, + int inTriggerID ) { + + if( inR->gridSpacingX == -1 && inR->gridSpacingY == -1 ) { + + int x = inX + inR->specificX; + int y = inY + inR->specificY; + int id = getMapObjectRaw( x, y ); + + TransRecord *t = getPTrans( inTriggerID, id ); + + if( t != NULL ) { + setMapObject( x, y, t->newTarget ); + } + + return; + + } + + // not a tapout on a specific tile + + int inRadiusX = inR->limitX; + int inRadiusY = inR->limitY; + int inSpacingX = inR->gridSpacingX; + int inSpacingY = inR->gridSpacingY; + + int tapoutCount = 0; for( int y = inY - inRadiusY; y <= inY + inRadiusY; @@ -7112,7 +7131,7 @@ static char runTapoutOperation( int inX, int inY, int newTarget = -1; - if( ! inIsPost ) { + if( true ) { // last use target signifies what happens in // same row or column as inX, inY @@ -7140,55 +7159,44 @@ static char runTapoutOperation( int inX, int inY, } if( newTarget != -1 ) { - ObjectRecord *nt = getObject( newTarget ); + tapoutCount++; - if( strstr( nt->description, "+primaryHomeland" ) != NULL ) { - if( inPlayerHasPrimaryHomeland ) { - // block creation of objects that require - // +primaryHomeland - // player already has a primary homeland - - newTarget = -1; - } - else { - // created a +primaryHomeland object - returnVal = true; + setMapObjectRaw( x, y, newTarget ); + + TransRecord *newDecayT = getMetaTrans( -1, newTarget ); + + timeSec_t mapETA = 0; + + if( newDecayT != NULL ) { + + // add some random variation to avoid lock-step + // especially after a server restart + int tweakedSeconds = + randSource.getRandomBoundedInt( + lrint( newDecayT->autoDecaySeconds * 0.9 ), + newDecayT->autoDecaySeconds ); + + if( tweakedSeconds < 1 ) { + tweakedSeconds = 1; } + mapETA = MAP_TIMESEC + tweakedSeconds; } + else { + // no further decay + mapETA = 0; + } + + setEtaDecay( x, y, mapETA, newDecayT ); } - - if( newTarget != -1 ) { - setMapObjectRaw( x, y, newTarget ); - - TransRecord *newDecayT = getMetaTrans( -1, newTarget ); - - timeSec_t mapETA = 0; - - if( newDecayT != NULL ) { - - // add some random variation to avoid lock-step - // especially after a server restart - int tweakedSeconds = - randSource.getRandomBoundedInt( - lrint( newDecayT->autoDecaySeconds * 0.9 ), - newDecayT->autoDecaySeconds ); - - if( tweakedSeconds < 1 ) { - tweakedSeconds = 1; - } - mapETA = MAP_TIMESEC + tweakedSeconds; - } - else { - // no further decay - mapETA = 0; - } - - setEtaDecay( x, y, mapETA, newDecayT ); + + if( inR->tapoutCountLimit != -1 && tapoutCount >= inR->tapoutCountLimit ) { + return; } + } } - return returnVal; + return; } @@ -7442,20 +7450,12 @@ void setMapObjectRaw( int inX, int inY, int inID ) { } else if( o->isTapOutTrigger ) { // this object, when created, taps out other objects in grid around - - char playerHasPrimaryHomeland = false; if( currentResponsiblePlayer != -1 ) { int pID = currentResponsiblePlayer; if( pID < 0 ) { pID = -pID; } - //primaryHomeland is not in 2HOL - // int lineage = getPlayerLineage( pID ); - - // if( lineage != -1 ) { - // playerHasPrimaryHomeland = hasPrimaryHomeland( lineage ); - // } } // don't make current player responsible for all these changes @@ -7465,30 +7465,11 @@ void setMapObjectRaw( int inX, int inY, int inID ) { TapoutRecord *r = getTapoutRecord( inID ); if( r != NULL ) { - - // char tappedOutPrimaryHomeland = false; //primaryHomeland is not in 2HOL - // tappedOutPrimaryHomeland = runTapoutOperation( inX, inY, - r->limitX, r->limitY, - r->gridSpacingX, r->gridSpacingY, - inID, - playerHasPrimaryHomeland ); - + r, + inID ); - r->buildCount++; - - if( r->buildCountLimit != -1 && - r->buildCount >= r->buildCountLimit ) { - // hit limit! - // tapout a larger radius now - // tappedOutPrimaryHomeland = - runTapoutOperation( inX, inY, - r->postBuildLimitX, r->postBuildLimitY, - r->gridSpacingX, r->gridSpacingY, - inID, - playerHasPrimaryHomeland, true ); - } } currentResponsiblePlayer = restoreResponsiblePlayer; From 202a73e5d2dbe20c957e57dc906caa8abfffdf62 Mon Sep 17 00:00:00 2001 From: risvh <67486979+risvh@users.noreply.github.com> Date: Thu, 1 Feb 2024 23:30:53 +0800 Subject: [PATCH 43/44] Revert "Automatically toggle forceShutdownMode back after it takes effect" This reverts commit 3bddef1805489f487368fb6cd48daf67835ddee1. --- server/server.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/server.cpp b/server/server.cpp index d4bed3d1f..3cdd30207 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -13141,8 +13141,6 @@ int main() { nextPlayer->errorCauseString = "Forced server shutdown"; } - - SettingsManager::setSetting( "forceShutdownMode", 0 ); } else if( shutdownMode ) { // any disconnected players should be killed now From a1ec6829ed3795a2b44e63b98c3b22a6ece6a495 Mon Sep 17 00:00:00 2001 From: risvh <67486979+risvh@users.noreply.github.com> Date: Thu, 1 Feb 2024 23:33:22 +0800 Subject: [PATCH 44/44] Putting back the line to toggle forceShutdownMode automatically --- server/server.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/server.cpp b/server/server.cpp index 3cdd30207..291a2a8d6 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -24385,6 +24385,8 @@ int main() { AppLog::info( "Done." ); + + SettingsManager::setSetting( "forceShutdownMode", 0 ); return 0; }