From f117bb90b00354498a84d99361ce0b3837f5569d Mon Sep 17 00:00:00 2001 From: Fabian Meyer <3982806+meyfa@users.noreply.github.com> Date: Sat, 22 Feb 2025 20:01:21 +0100 Subject: [PATCH] fix: Move entities between chunks (#349) When an entity moves from one chunk to another, it must be removed from the previous chunk's linked list of entities and added to the new chunk's instead. --- src/_copybooks/structs/DD-ENTITY.cpy | 10 +++ src/world/entities.cob | 106 ++++++++++++++++++++++++--- src/world/world.cob | 3 + 3 files changed, 108 insertions(+), 11 deletions(-) diff --git a/src/_copybooks/structs/DD-ENTITY.cpy b/src/_copybooks/structs/DD-ENTITY.cpy index e87b94c..918fe9a 100644 --- a/src/_copybooks/structs/DD-ENTITY.cpy +++ b/src/_copybooks/structs/DD-ENTITY.cpy @@ -2,7 +2,9 @@ 30 ENTITY-ID BINARY-LONG. 30 ENTITY-UUID PIC X(16). + 30 ENTITY-TYPE BINARY-LONG. + 30 ENTITY-POSITION. 31 ENTITY-X FLOAT-LONG. 31 ENTITY-Y FLOAT-LONG. @@ -15,8 +17,16 @@ 31 ENTITY-VELOCITY-Y FLOAT-LONG. 31 ENTITY-VELOCITY-Z FLOAT-LONG. 30 ENTITY-ON-GROUND BINARY-CHAR UNSIGNED. + 30 ENTITY-AGE BINARY-LONG. 30 ENTITY-NO-GRAVITY BINARY-CHAR UNSIGNED. + +*> The chunk the entity is in (chunk coordinates, i.e. position/16). +*> This may diverge from the entity's position while the entity is being moved. It is used to determine which chunk to +*> remove the entity from before adding it to its new chunk. +30 ENTITY-CHUNK-X BINARY-LONG. +30 ENTITY-CHUNK-Z BINARY-LONG. + *> TODO make entity data more generic *> for item entities: item stack 30 ENTITY-ITEM-SLOT. diff --git a/src/world/entities.cob b/src/world/entities.cob index 32b27ab..eadb1d0 100644 --- a/src/world/entities.cob +++ b/src/world/entities.cob @@ -11,27 +11,27 @@ WORKING-STORAGE SECTION. COPY DD-WORLD. COPY DD-CHUNK-REF. COPY DD-CHUNK-ENTITY. - 01 POS-CHUNK-X BINARY-LONG. - 01 POS-CHUNK-Z BINARY-LONG. 01 CHUNK-INDEX BINARY-LONG UNSIGNED. COPY DD-CLIENTS. COPY DD-CLIENT-STATES. COPY DD-SERVER-PROPERTIES. 01 CLIENT-ID BINARY-LONG UNSIGNED. LINKAGE SECTION. - *> The entity data. ID and UUID will be set by this program. + *> The entity data. ID, UUID, and some internal data will be set by this program. 01 LK-ENTITY. COPY DD-ENTITY REPLACING LEADING ==ENTITY== BY ==LK-ENTITY==. PROCEDURE DIVISION USING LK-ENTITY. *> Find the chunk - DIVIDE LK-ENTITY-X BY 16 GIVING POS-CHUNK-X ROUNDED MODE IS TOWARD-LESSER - DIVIDE LK-ENTITY-Z BY 16 GIVING POS-CHUNK-Z ROUNDED MODE IS TOWARD-LESSER - CALL "World-EnsureChunk" USING POS-CHUNK-X POS-CHUNK-Z CHUNK-INDEX + DIVIDE LK-ENTITY-X BY 16 GIVING LK-ENTITY-CHUNK-X ROUNDED MODE IS TOWARD-LESSER + DIVIDE LK-ENTITY-Z BY 16 GIVING LK-ENTITY-CHUNK-Z ROUNDED MODE IS TOWARD-LESSER + + CALL "World-EnsureChunk" USING LK-ENTITY-CHUNK-X LK-ENTITY-CHUNK-Z CHUNK-INDEX IF CHUNK-INDEX = 0 DISPLAY "Failed to spawn entity: chunk not found" GOBACK END-IF + SET ADDRESS OF CHUNK TO WORLD-CHUNK-POINTER(CHUNK-INDEX) *> Generate a unique entity ID @@ -144,8 +144,6 @@ WORKING-STORAGE SECTION. COPY DD-WORLD. COPY DD-CHUNK-REF. COPY DD-CHUNK-ENTITY. - 01 POS-CHUNK-X BINARY-LONG. - 01 POS-CHUNK-Z BINARY-LONG. 01 CHUNK-INDEX BINARY-LONG UNSIGNED. 01 PREV-ENTITY-PTR POINTER. 01 ENTITY-PTR POINTER. @@ -163,12 +161,11 @@ PROCEDURE DIVISION USING LK-ENTITY. END-PERFORM *> Find the chunk - DIVIDE LK-ENTITY-X BY 16 GIVING POS-CHUNK-X ROUNDED MODE IS TOWARD-LESSER - DIVIDE LK-ENTITY-Z BY 16 GIVING POS-CHUNK-Z ROUNDED MODE IS TOWARD-LESSER - CALL "World-EnsureChunk" USING POS-CHUNK-X POS-CHUNK-Z CHUNK-INDEX + CALL "World-EnsureChunk" USING LK-ENTITY-CHUNK-X LK-ENTITY-CHUNK-Z CHUNK-INDEX IF CHUNK-INDEX = 0 GOBACK END-IF + SET ADDRESS OF CHUNK TO WORLD-CHUNK-POINTER(CHUNK-INDEX) *> Find the entity in the linked list @@ -199,10 +196,97 @@ PROCEDURE DIVISION USING LK-ENTITY. SET ENTITY-LIST-NEXT TO NEXT-ENTITY-PTR END-IF + SUBTRACT 1 FROM CHUNK-ENTITY-COUNT + GOBACK. END PROGRAM World-RemoveEntity. +*> --- World-UpdateEntityChunk --- +*> Entities are stored in a linked list per chunk. This program computes the chunk that an entity should be part of, +*> and moves it from its current chunk to the new one if necessary. +IDENTIFICATION DIVISION. +PROGRAM-ID. World-UpdateEntityChunk. + +DATA DIVISION. +WORKING-STORAGE SECTION. + COPY DD-WORLD. + COPY DD-CHUNK-REF. + COPY DD-CHUNK-ENTITY. + *> Entity chunk coordinates after update + 01 NEW-CHUNK-X BINARY-LONG. + 01 NEW-CHUNK-Z BINARY-LONG. + 01 NEW-CHUNK-INDEX BINARY-LONG UNSIGNED. + *> Current chunk + 01 PREV-CHUNK-INDEX BINARY-LONG UNSIGNED. + *> Linked list pointers + 01 PREV-ENTITY-PTR POINTER. + 01 ENTITY-PTR POINTER. + 01 NEXT-ENTITY-PTR POINTER. +LINKAGE SECTION. + 01 LK-ENTITY. + COPY DD-ENTITY REPLACING LEADING ==ENTITY== BY ==LK-ENTITY==. + +PROCEDURE DIVISION USING LK-ENTITY. + DIVIDE LK-ENTITY-X BY 16 GIVING NEW-CHUNK-X ROUNDED MODE IS TOWARD-LESSER + DIVIDE LK-ENTITY-Z BY 16 GIVING NEW-CHUNK-Z ROUNDED MODE IS TOWARD-LESSER + + IF LK-ENTITY-CHUNK-X = NEW-CHUNK-X AND LK-ENTITY-CHUNK-Z = NEW-CHUNK-Z + GOBACK + END-IF + + CALL "World-EnsureChunk" USING LK-ENTITY-CHUNK-X LK-ENTITY-CHUNK-Z PREV-CHUNK-INDEX + CALL "World-EnsureChunk" USING NEW-CHUNK-X NEW-CHUNK-Z NEW-CHUNK-INDEX + + IF PREV-CHUNK-INDEX = 0 OR NEW-CHUNK-INDEX = 0 + GOBACK + END-IF + + SET ADDRESS OF CHUNK TO WORLD-CHUNK-POINTER(PREV-CHUNK-INDEX) + + *> Find the entity in the linked list + SET PREV-ENTITY-PTR TO NULL + SET ENTITY-PTR TO CHUNK-ENTITY-LIST + PERFORM UNTIL ENTITY-PTR = NULL + SET ADDRESS OF ENTITY-LIST TO ENTITY-PTR + IF ENTITY-ID = LK-ENTITY-ID + SET NEXT-ENTITY-PTR TO ENTITY-LIST-NEXT + EXIT PERFORM + END-IF + SET PREV-ENTITY-PTR TO ENTITY-PTR + SET ENTITY-PTR TO ENTITY-LIST-NEXT + END-PERFORM + + IF ENTITY-PTR = NULL + GOBACK + END-IF + + *> Remove the entity from the linked list (without deallocating it) + IF PREV-ENTITY-PTR = NULL + SET CHUNK-ENTITY-LIST TO NEXT-ENTITY-PTR + ELSE + SET ADDRESS OF ENTITY-LIST TO PREV-ENTITY-PTR + SET ENTITY-LIST-NEXT TO NEXT-ENTITY-PTR + END-IF + + SUBTRACT 1 FROM CHUNK-ENTITY-COUNT + + SET ADDRESS OF CHUNK TO WORLD-CHUNK-POINTER(NEW-CHUNK-INDEX) + + *> Add the entity to the new chunk's linked list + SET ADDRESS OF ENTITY-LIST TO ENTITY-PTR + SET ENTITY-LIST-NEXT TO CHUNK-ENTITY-LIST + SET CHUNK-ENTITY-LIST TO ENTITY-PTR + + ADD 1 TO CHUNK-ENTITY-COUNT + + MOVE NEW-CHUNK-X TO LK-ENTITY-CHUNK-X + MOVE NEW-CHUNK-Z TO LK-ENTITY-CHUNK-Z + + GOBACK. + +END PROGRAM World-UpdateEntityChunk. + *> --- World-DropItem --- *> Utility program to drop an item entity at a given position. IDENTIFICATION DIVISION. diff --git a/src/world/world.cob b/src/world/world.cob index bfb8715..1313887 100644 --- a/src/world/world.cob +++ b/src/world/world.cob @@ -203,6 +203,9 @@ TickEntity. END-IF END-PERFORM END-IF + + *> Ensure the entity is in the correct chunk + CALL "World-UpdateEntityChunk" USING ENTITY-LIST-ENTITY ENTITY-CHUNK-X ENTITY-CHUNK-Z . SendPickupItem.