diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/src/main/java/de/welterde/em/Entity.java b/src/main/java/de/welterde/em/Entity.java new file mode 100644 index 0000000..062735c --- /dev/null +++ b/src/main/java/de/welterde/em/Entity.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em; + +/** + * + * @author welterde + */ +public abstract class Entity { + protected final EntityStorage ctx; + protected final int id; + + public Entity(EntityStorage ctx, int id) { + this.id = id; + this.ctx = ctx; + } + + public int getEntityId() { + return this.id; + } +} diff --git a/src/main/java/de/welterde/em/EntityRef.java b/src/main/java/de/welterde/em/EntityRef.java new file mode 100644 index 0000000..cda120c --- /dev/null +++ b/src/main/java/de/welterde/em/EntityRef.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em; + +import java.lang.ref.WeakReference; + +/** + * + * @author welterde + * @param + */ +public class EntityRef { + protected final EntityStorage ctx; + + protected WeakReference ref; + protected final int entityId; + protected boolean invalid; + + public EntityRef(EntityStorage ctx, X entity) { + this.ctx = ctx; + this.entityId = entity.getEntityId(); + this.invalid = false; + } + + public X get() { + if(this.invalid) + throw new InvalidEntityReference(this.entityId); + + var e = this.ref.get(); + if(e != null) + return e; + + synchronized(this) { + var ee = this.ctx.getEntity(this.entityId); + // check if entity was already destroyed + if (ee == null) { + this.invalid = true; + throw new InvalidEntityReference(this.entityId); + } + + // try to cast it to the correct type and since we do not reuse + // entity ids this should not go wrong, but maybe it did.. + try { + X eee = (X) ee; + this.ref = new WeakReference(eee); + return eee; + } catch(ClassCastException exc) { + this.invalid = true; + throw new InvalidEntityReference(this.entityId); + } + } + } +} diff --git a/src/main/java/de/welterde/em/EntityStorage.java b/src/main/java/de/welterde/em/EntityStorage.java new file mode 100644 index 0000000..7aec1b4 --- /dev/null +++ b/src/main/java/de/welterde/em/EntityStorage.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em; + +/** + * + * @author welterde + */ +public interface EntityStorage { + public Entity getEntity(int entityId); +} diff --git a/src/main/java/de/welterde/em/InvalidEntityReference.java b/src/main/java/de/welterde/em/InvalidEntityReference.java new file mode 100644 index 0000000..86664e7 --- /dev/null +++ b/src/main/java/de/welterde/em/InvalidEntityReference.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em; + +/** + * + * @author welterde + */ +public class InvalidEntityReference extends RuntimeException { + + /** + * Creates a new instance of InvalidEntityReference without + * detail message. + */ + public InvalidEntityReference() { + } + + /** + * Constructs an instance of InvalidEntityReference with the + * specified detail message. + * + * @param msg the detail message. + */ + public InvalidEntityReference(int eid) { + super("Invalid entity reference to entity=" + eid); + } +} diff --git a/src/main/java/de/welterde/em/data/CounterName.java b/src/main/java/de/welterde/em/data/CounterName.java index f70c076..d2cc251 100644 --- a/src/main/java/de/welterde/em/data/CounterName.java +++ b/src/main/java/de/welterde/em/data/CounterName.java @@ -21,6 +21,9 @@ package de.welterde.em.data; * @author welterde */ public enum CounterName { + COUNTRY_IDX, + DIMENSION_IDX, + AREA_IDX, LOCATION_IDX, ENTITY_IDX, } diff --git a/src/main/java/de/welterde/em/data/Entity.java b/src/main/java/de/welterde/em/data/Entity.java index 2fec36a..b4db73d 100644 --- a/src/main/java/de/welterde/em/data/Entity.java +++ b/src/main/java/de/welterde/em/data/Entity.java @@ -37,6 +37,12 @@ public interface Entity { */ public Location getLocation(); + /** + * Relative position within location + * @return + */ + public LocationPos getLocationPos(); + public boolean isMovable(); public MovementStatus getMovementStatus(); diff --git a/src/main/java/de/welterde/em/data/LocationPos.java b/src/main/java/de/welterde/em/data/LocationPos.java new file mode 100644 index 0000000..d11b8da --- /dev/null +++ b/src/main/java/de/welterde/em/data/LocationPos.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em.data; + +/** + * + * @author welterde + */ +public interface LocationPos { + +} diff --git a/src/main/java/de/welterde/em/w/Area.java b/src/main/java/de/welterde/em/w/Area.java new file mode 100644 index 0000000..6d8b46e --- /dev/null +++ b/src/main/java/de/welterde/em/w/Area.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em.w; + +import de.welterde.em.data.Location; +import de.welterde.em.data.TerrainGen; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author welterde + */ +public class Area { + protected final int id; + protected final ReadWriteLock structLock; + + protected final AreaMap map; + protected final Map locations; + + public Area(int id, TerrainGen gen) { + this.id = id; + this.structLock = new ReentrantReadWriteLock(); + + this.map = new AreaMap(gen); + this.locations = new HashMap<>(); + } +} diff --git a/src/main/java/de/welterde/em/w/AreaMap.java b/src/main/java/de/welterde/em/w/AreaMap.java new file mode 100644 index 0000000..5dad232 --- /dev/null +++ b/src/main/java/de/welterde/em/w/AreaMap.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em.w; + +import de.welterde.em.data.MapCoord; +import de.welterde.em.data.TerrainGen; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author welterde + */ +public class AreaMap { + protected final Map blockMap; + protected final TerrainGen gen; + protected final ReadWriteLock structLock; + + public AreaMap(TerrainGen gen) { + this.gen = gen; + this.blockMap = new HashMap<>(); + this.structLock = new ReentrantReadWriteLock(); + } + + public Block getBlock(MapCoord c) { + if(!this.blockMap.containsKey(c)) { + // default to the terrain generator + return this.gen.generateBlock(this, c); + } else { + return this.tiles.get(c); + } + } +} diff --git a/src/main/java/de/welterde/em/w/Block.java b/src/main/java/de/welterde/em/w/Block.java new file mode 100644 index 0000000..6bb3d9f --- /dev/null +++ b/src/main/java/de/welterde/em/w/Block.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em.w; + +/** + * 5m x 5m block of the world + * @author welterde + */ +public class Block { + +} diff --git a/src/main/java/de/welterde/em/w/BlockCoord.java b/src/main/java/de/welterde/em/w/BlockCoord.java new file mode 100644 index 0000000..e5db199 --- /dev/null +++ b/src/main/java/de/welterde/em/w/BlockCoord.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2026 welterde + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.welterde.em.w; + +/** + * + * @author welterde + */ +class BlockCoord { + +} diff --git a/src/main/java/de/welterde/em/w/Country.java b/src/main/java/de/welterde/em/w/Country.java index 8923416..991ed6d 100644 --- a/src/main/java/de/welterde/em/w/Country.java +++ b/src/main/java/de/welterde/em/w/Country.java @@ -16,10 +16,17 @@ */ package de.welterde.em.w; +import de.welterde.em.Entity; +import de.welterde.em.EntityStorage; + /** * * @author welterde */ -public class Country { +public class Country extends Entity { + + public Country(EntityStorage ctx, int id) { + super(ctx, id); + } } diff --git a/src/main/java/de/welterde/em/w/Dimension.java b/src/main/java/de/welterde/em/w/Dimension.java index 32f9815..44178b5 100644 --- a/src/main/java/de/welterde/em/w/Dimension.java +++ b/src/main/java/de/welterde/em/w/Dimension.java @@ -16,10 +16,39 @@ */ package de.welterde.em.w; +import de.welterde.em.Entity; +import de.welterde.em.data.CounterName; +import de.welterde.em.data.TerrainGen; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + /** * * @author welterde */ -public class Dimension { +public class Dimension extends Entity { + protected final ReadWriteLock structLock; + protected final Map areas; + + public Dimension(World ctx, int id) { + super(ctx, id); + this.structLock = new ReentrantReadWriteLock(); + + this.areas = new HashMap<>(); + } + + public Area addArea(TerrainGen gen) { + this.structLock.writeLock().lock(); + try { + var areaId = this.ctx.allocateId(CounterName.AREA_IDX); + var area = new Area(areaId, gen); + this.areas.put(areaId, area); + return area; + } finally { + this.structLock.writeLock().unlock(); + } + } } diff --git a/src/main/java/de/welterde/em/w/World.java b/src/main/java/de/welterde/em/w/World.java index 96bcab4..47b40ea 100644 --- a/src/main/java/de/welterde/em/w/World.java +++ b/src/main/java/de/welterde/em/w/World.java @@ -16,10 +16,72 @@ */ package de.welterde.em.w; +import de.welterde.em.Entity; +import de.welterde.em.EntityRef; +import de.welterde.em.EntityStorage; +import de.welterde.em.data.CounterName; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + /** * * @author welterde */ -public class World { +public class World implements EntityStorage { + protected final ArrayList entities; + protected final EnumMap counters; + protected final ArrayList> dimensions; + protected final Map> countries; + protected final ReadWriteLock structLock; + public World() { + this.counters = new EnumMap<>(CounterName.class); + this.dimensions = new ArrayList<>(); + this.countries = new HashMap<>(); + this.entities = new ArrayList<>(); + + this.structLock = new ReentrantReadWriteLock(); + } + + + public int allocateId(CounterName name) { + synchronized(this.counters) { + // start counter at zero if not yet a thing + if(!this.counters.containsKey(name)) + this.counters.put(name, 0); + + var nextVal = this.counters.get(name) + 1; + this.counters.put(name, nextVal); + return nextVal; + } + } + + public Dimension addDimension() { + this.structLock.writeLock().lock(); + try{ + var dim = new Dimension(this, this.dimensions.size()); + this.dimensions.add(dim); + return dim; + } finally { + this.structLock.writeLock().unlock(); + } + } + public Dimension getDimension(int id) { + this.structLock.readLock().lock(); + try { + return this.dimensions.get(id); + } finally { + this.structLock.readLock().unlock(); + } + } + + @Override + public Entity getEntity(int entityId) { + return this.entities.get(entityId); + } }