Skip to content

Commit

Permalink
fix: Move entities between chunks (#349)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
meyfa authored Feb 22, 2025
1 parent 2f4d02e commit f117bb9
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 11 deletions.
10 changes: 10 additions & 0 deletions src/_copybooks/structs/DD-ENTITY.cpy
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
106 changes: 95 additions & 11 deletions src/world/entities.cob
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions src/world/world.cob
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit f117bb9

Please sign in to comment.