Start adding beacon beam repo handling

This commit is contained in:
James Seibel
2024-07-01 07:51:08 -05:00
parent 51de347bdd
commit 6a398e6514
12 changed files with 385 additions and 5 deletions
@@ -26,10 +26,12 @@ import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.util.TimerUtil;
import com.seibel.distanthorizons.core.util.objects.Pair;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
@@ -345,6 +347,12 @@ public class SharedApi
DhLightingEngine.INSTANCE.lightChunk(chunkWrapper, nearbyChunkList, dhLevel.hasSkyLight() ? 15 : 0);
}
// get this chunk's active beacons
List<BeaconBeamDTO> beaconBeamList = chunkWrapper.getAllActiveBeacons();
dhLevel.ensureBeaconBeamsAtPos(DhSectionPos.encode(chunkWrapper.getChunkPos()), beaconBeamList);
dhLevel.updateChunkAsync(chunkWrapper);
dhLevel.setChunkHash(chunkWrapper.getChunkPos(), newChunkHash);
}
@@ -19,14 +19,21 @@
package com.seibel.distanthorizons.core.level;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkModifiedEvent;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dataObjects.transformers.ChunkToLodBuilder;
import com.seibel.distanthorizons.core.file.fullDatafile.DelayedFullDataSourceSaveCache;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.render.renderer.GenericObjectRenderer;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.sql.dto.ChunkHashDTO;
import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo;
import com.seibel.distanthorizons.core.sql.repo.ChunkHashRepo;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
@@ -35,7 +42,10 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractDhLevel implements IDhLevel
@@ -47,6 +57,9 @@ public abstract class AbstractDhLevel implements IDhLevel
/** if this is null then the other handler is probably null too, but just in case */
@Nullable
public ChunkHashRepo chunkHashRepo;
/** if this is null then the other handler is probably null too, but just in case */
@Nullable
public BeaconBeamRepo beaconBeamRepo;
protected final DelayedFullDataSourceSaveCache delayedFullDataSourceSaveCache = new DelayedFullDataSourceSaveCache(this::onDataSourceSave, 2_000);
/** contains the {@link DhChunkPos} for each {@link DhSectionPos} that are queued to save via {@link AbstractDhLevel#delayedFullDataSourceSaveCache} */
@@ -60,8 +73,9 @@ public abstract class AbstractDhLevel implements IDhLevel
protected AbstractDhLevel() { this.chunkToLodBuilder = new ChunkToLodBuilder(); }
protected void createAndSetChunkHashRepo(File databaseFile)
protected void createAndSetSupportingRepos(File databaseFile)
{
// chunk hash
ChunkHashRepo newChunkHashRepo = null;
try
{
@@ -72,6 +86,19 @@ public abstract class AbstractDhLevel implements IDhLevel
LOGGER.error("Unable to create [ChunkHashRepo], error: ["+e.getMessage()+"].", e);
}
this.chunkHashRepo = newChunkHashRepo;
// beacon beam
BeaconBeamRepo newBeaconBeamRepo = null;
try
{
newBeaconBeamRepo = new BeaconBeamRepo("jdbc:sqlite", databaseFile);
}
catch (SQLException e)
{
LOGGER.error("Unable to create [BeaconBeamRepo], error: ["+e.getMessage()+"].", e);
}
this.beaconBeamRepo = newBeaconBeamRepo;
}
@@ -126,6 +153,13 @@ public abstract class AbstractDhLevel implements IDhLevel
}
//=======//
// repos //
//=======//
// chunk hash //
@Override
public int getChunkHash(DhChunkPos pos)
{
@@ -148,6 +182,92 @@ public abstract class AbstractDhLevel implements IDhLevel
// beacon beam //
@Override
public List<BeaconBeamDTO> getAllBeamsForSectionPos(long pos)
{
if (this.beaconBeamRepo != null)
{
return this.beaconBeamRepo.getAllBeamsForSectionPos(pos);
}
else
{
return new ArrayList<>(0);
}
}
HashMap<DhBlockPos, IDhApiRenderableBoxGroup> beamRenderGroupByPos = new HashMap<>();
@Override
public void ensureBeaconBeamsAtPos(long pos, List<BeaconBeamDTO> newBeamList)
{
if (this.beaconBeamRepo != null)
{
HashSet<DhBlockPos> allPosSet = new HashSet<>();
// sort new beams
HashMap<DhBlockPos, BeaconBeamDTO> newBeamByPos = new HashMap<>(newBeamList.size());
for (int i = 0; i < newBeamList.size(); i++)
{
BeaconBeamDTO beam = newBeamList.get(i);
newBeamByPos.put(beam.pos, beam);
allPosSet.add(beam.pos);
}
// get existing beams
List<BeaconBeamDTO> existingBeamList = this.beaconBeamRepo.getAllBeamsForSectionPos(pos);
HashMap<DhBlockPos, BeaconBeamDTO> existingBeamByPos = new HashMap<>(existingBeamList.size());
for (int i = 0; i < existingBeamList.size(); i++)
{
BeaconBeamDTO beam = existingBeamList.get(i);
existingBeamByPos.put(beam.pos, beam);
allPosSet.add(beam.pos);
}
for (DhBlockPos beaconPos : allPosSet)
{
BeaconBeamDTO existingBeam = existingBeamByPos.get(beaconPos);
BeaconBeamDTO newBeam = newBeamByPos.get(beaconPos);
if (existingBeam != null && newBeam != null)
{
// beam still exists in chunk, do nothing
}
else if (existingBeam == null && newBeam != null)
{
// new beam found, add to DB
this.beaconBeamRepo.save(newBeam);
IDhApiRenderableBoxGroup beaconBox = GenericObjectRenderer.INSTANCE.createForSingleBox(new DhApiRenderableBox(
new DhApiVec3f(newBeam.pos.x, newBeam.pos.y+1, newBeam.pos.z),
new DhApiVec3f(newBeam.pos.x+1, 2_000, newBeam.pos.z+1),
newBeam.color
));
beamRenderGroupByPos.put(newBeam.pos, beaconBox);
GenericObjectRenderer.INSTANCE.add(beaconBox);
}
else if (existingBeam != null && newBeam == null)
{
// beam no longer exists at position, remove
this.beaconBeamRepo.deleteWithKey(beaconPos);
IDhApiRenderableBoxGroup beaconBox = beamRenderGroupByPos.remove(newBeam.pos);
if (beaconBox != null)
{
GenericObjectRenderer.INSTANCE.remove(beaconBox.getId());
}
}
}
}
}
//================//
// base overrides //
//================//
@@ -62,7 +62,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
this.dataFileHandler = new RemoteFullDataSourceProvider(this, saveStructure, fullDataSaveDirOverride);
this.clientside = new ClientLevelModule(this);
this.createAndSetChunkHashRepo(this.dataFileHandler.repo.databaseFile);
this.createAndSetSupportingRepos(this.dataFileHandler.repo.databaseFile);
if (enableRendering)
{
@@ -68,7 +68,7 @@ public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLev
this.serverLevelWrapper = serverLevelWrapper;
this.serverside = new ServerLevelModule(this, saveStructure);
this.clientside = new ClientLevelModule(this);
this.createAndSetChunkHashRepo(this.serverside.fullDataFileHandler.repo.databaseFile);
this.createAndSetSupportingRepos(this.serverside.fullDataFileHandler.repo.databaseFile);
LOGGER.info("Started " + DhClientServerLevel.class.getSimpleName() + " for " + serverLevelWrapper + " with saves at " + saveStructure);
}
@@ -47,7 +47,7 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel
}
this.serverLevelWrapper = serverLevelWrapper;
this.serverside = new ServerLevelModule(this, saveStructure);
this.createAndSetChunkHashRepo(this.serverside.fullDataFileHandler.repo.databaseFile);
this.createAndSetSupportingRepos(this.serverside.fullDataFileHandler.repo.databaseFile);
LOGGER.info("Started DHLevel for {} with saves at {}", serverLevelWrapper, saveStructure);
}
@@ -22,7 +22,9 @@ package com.seibel.distanthorizons.core.level;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2;
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
@@ -44,6 +46,9 @@ public interface IDhLevel extends AutoCloseable
void setChunkHash(DhChunkPos pos, int chunkHash);
void updateChunkAsync(IChunkWrapper chunk);
List<BeaconBeamDTO> getAllBeamsForSectionPos(long pos);
void ensureBeaconBeamsAtPos(long pos, List<BeaconBeamDTO> beamList);
FullDataSourceProviderV2 getFullDataProvider();
AbstractSaveStructure getSaveStructure();
@@ -74,6 +74,7 @@ import java.util.stream.Stream;
*/
public class GenericObjectRenderer implements IDhApiCustomRenderRegister
{
@Deprecated
public static GenericObjectRenderer INSTANCE = new GenericObjectRenderer();
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
@@ -0,0 +1,55 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.sql.dto;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import java.awt.*;
/** handles storing {@link FullDataSourceV2}'s in the database. */
public class BeaconBeamDTO implements IBaseDTO<DhBlockPos>
{
public DhBlockPos pos;
public Color color;
//=============//
// constructor //
//=============//
public BeaconBeamDTO(DhBlockPos pos, Color color)
{
this.pos = pos;
this.color = color;
}
//===========//
// overrides //
//===========//
@Override
public DhBlockPos getKey() { return this.pos; }
}
@@ -0,0 +1,152 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.sql.repo;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.io.File;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class BeaconBeamRepo extends AbstractDhRepo<DhBlockPos, BeaconBeamDTO>
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
//=============//
// constructor //
//=============//
public BeaconBeamRepo(String databaseType, File databaseFile) throws SQLException
{
super(databaseType, databaseFile, BeaconBeamDTO.class);
}
//===========//
// overrides //
//===========//
@Override
public String getTableName() { return "BeaconBeam"; }
@Override
public String createWhereStatement(DhBlockPos pos) { return "BlockPosX = "+pos.x+" AND BlockPosY = "+pos.y+" AND BlockPosZ = "+pos.z; }
//=======================//
// repo required methods //
//=======================//
@Override
public BeaconBeamDTO convertDictionaryToDto(Map<String, Object> objectMap) throws ClassCastException
{
int posX = (Integer) objectMap.get("BlockPosX");
int posY = (Integer) objectMap.get("BlockPosY");
int posZ = (Integer) objectMap.get("BlockPosZ");
int red = (Integer) objectMap.get("ColorR");
int green = (Integer) objectMap.get("ColorG");
int blue = (Integer) objectMap.get("ColorB");
BeaconBeamDTO dto = new BeaconBeamDTO(new DhBlockPos(posX, posY, posZ), new Color(red, green, blue));
return dto;
}
@Override
public PreparedStatement createInsertStatement(BeaconBeamDTO dto) throws SQLException
{
String sql =
"INSERT INTO "+this.getTableName() + " (\n" +
" BlockPosX, BlockPosY, BlockPosZ, \n" +
" ColorR, ColorG, ColorB, \n" +
" LastModifiedUnixDateTime, CreatedUnixDateTime) \n" +
"VALUES( \n" +
" ?, ?, ?, \n" +
" ?, ?, ?, \n" +
" ?, ? \n" +
");";
PreparedStatement statement = this.createPreparedStatement(sql);
int i = 1;
statement.setObject(i++, dto.pos.x);
statement.setObject(i++, dto.pos.y);
statement.setObject(i++, dto.pos.z);
statement.setObject(i++, dto.color.getRed());
statement.setObject(i++, dto.color.getGreen());
statement.setObject(i++, dto.color.getBlue());
statement.setObject(i++, System.currentTimeMillis()); // last modified unix time
statement.setObject(i++, System.currentTimeMillis()); // created unix time
return statement;
}
@Override
public PreparedStatement createUpdateStatement(BeaconBeamDTO dto) throws SQLException
{
String sql =
"UPDATE "+this.getTableName()+" \n" +
"SET \n" +
" ColorR = ?, ColorG = ?, ColorB = ?, \n" +
" ,LastModifiedUnixDateTime = ? \n" +
"WHERE BlockPosX = ? AND BlockPosY = ? AND BlockPosZ = ?";
PreparedStatement statement = this.createPreparedStatement(sql);
int i = 1;
statement.setObject(i++, dto.color.getRed());
statement.setObject(i++, dto.color.getGreen());
statement.setObject(i++, dto.color.getBlue());
statement.setObject(i++, System.currentTimeMillis()); // last modified unix time
statement.setObject(i++, dto.pos.x);
statement.setObject(i++, dto.pos.y);
statement.setObject(i++, dto.pos.z);
return statement;
}
//====================//
// additional methods //
//====================//
public List<BeaconBeamDTO> getAllBeamsForSectionPos(long pos)
{
return null;
}
}
@@ -22,13 +22,16 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.chunk;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public interface IChunkWrapper extends IBindable
{
@@ -243,5 +246,24 @@ public interface IChunkWrapper extends IBindable
return hash;
}
default List<BeaconBeamDTO> getAllActiveBeacons()
{
ArrayList<BeaconBeamDTO> beaconPosList = new ArrayList<>();
// since beacons emit light we can check only the positions that are emitting light
ArrayList<DhBlockPos> blockPosList = this.getBlockLightPosList();
for (int i = 0; i < blockPosList.size(); i++)
{
DhBlockPos pos = blockPosList.get(i).convertToChunkRelativePos();
IBlockStateWrapper block = this.getBlockState(pos);
if (block.getSerialString().equalsIgnoreCase("minecraft:beacon"))
{
BeaconBeamDTO beam = new BeaconBeamDTO(pos, Color.WHITE); // TODO
beaconPosList.add(beam);
}
}
return beaconPosList;
}
}
@@ -0,0 +1,16 @@
CREATE TABLE BeaconBeam(
-- compound primary key
BlockPosX INT NOT NULL
,BlockPosY INT NOT NULL
,BlockPosZ INT NOT NULL
,ColorR INT NOT NULL
,ColorG INT NOT NULL
,ColorB INT NOT NULL
,LastModifiedUnixDateTime BIGINT NOT NULL -- in GMT 0
,CreatedUnixDateTime BIGINT NOT NULL -- in GMT 0
,PRIMARY KEY (BlockPosX, BlockPosY, BlockPosZ)
);
@@ -6,3 +6,4 @@
0040-sqlite-removeRenderCache.sql
0050-sqlite-addApplyToParentIndex.sql
0060-sqlite-createChunkHashTable.sql
0070-sqlite-createBeaconBeamTable.sql